aboutsummaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-01-06 15:00:48 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-01-10 02:42:34 +0000
commit5bf4bafd13a4044b7c3d2e8246684a597c6f2134 (patch)
tree8836207ffd2814acb8bdb9ac6b9c6d69436c9952 /lib/libc
parentde898cb96042a026ef703d81aea6cdf1ffce8f32 (diff)
downloadsrc-5bf4bafd13a4044b7c3d2e8246684a597c6f2134.tar.gz
src-5bf4bafd13a4044b7c3d2e8246684a597c6f2134.zip
x86 vdso gettc: eliminate duplicated code in ifunc selectors.
Create array of rdtsc selectors and provide helper that calculate the index into the selectors array. Reviewed by: gallatin, markj MFC after: 1 week Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D27986
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/x86/sys/__vdso_gettc.c87
1 files changed, 65 insertions, 22 deletions
diff --git a/lib/libc/x86/sys/__vdso_gettc.c b/lib/libc/x86/sys/__vdso_gettc.c
index b08b11e9c714..4e0fc9f7e841 100644
--- a/lib/libc/x86/sys/__vdso_gettc.c
+++ b/lib/libc/x86/sys/__vdso_gettc.c
@@ -83,20 +83,6 @@ rdtsc_low_mb_none(const struct vdso_timehands *th)
return (rdtsc_low(th));
}
-DEFINE_UIFUNC(static, u_int, __vdso_gettc_rdtsc_low,
- (const struct vdso_timehands *th))
-{
- u_int p[4];
- /* Not a typo, string matches our do_cpuid() registers use. */
- static const char intel_id[] = "GenuntelineI";
-
- if ((cpu_feature & CPUID_SSE2) == 0)
- return (rdtsc_low_mb_none);
- do_cpuid(0, p);
- return (memcmp(p + 1, intel_id, sizeof(intel_id) - 1) == 0 ?
- rdtsc_low_mb_lfence : rdtsc_low_mb_mfence);
-}
-
static u_int
rdtsc32_mb_lfence(void)
{
@@ -117,17 +103,74 @@ rdtsc32_mb_none(void)
return (rdtsc32());
}
-DEFINE_UIFUNC(static, u_int, __vdso_gettc_rdtsc32, (void))
+struct tsc_selector_tag {
+ u_int (*ts_rdtsc32)(void);
+ u_int (*ts_rdtsc_low)(const struct vdso_timehands *);
+};
+
+static const struct tsc_selector_tag tsc_selector[] = {
+ [0] = { /* Intel or AMD Zen+, LFENCE */
+ .ts_rdtsc32 = rdtsc32_mb_lfence,
+ .ts_rdtsc_low = rdtsc_low_mb_lfence,
+ },
+ [1] = { /* AMD, MFENCE */
+ .ts_rdtsc32 = rdtsc32_mb_mfence,
+ .ts_rdtsc_low = rdtsc_low_mb_mfence,
+ },
+ [2] = { /* No SSE2 */
+ .ts_rdtsc32 = rdtsc32_mb_none,
+ .ts_rdtsc_low = rdtsc_low_mb_none,
+ },
+};
+
+static int
+tsc_selector_idx(u_int cpu_feature)
{
- u_int p[4];
- /* Not a typo, string matches our do_cpuid() registers use. */
- static const char intel_id[] = "GenuntelineI";
+ u_int amd_feature, cpu_exthigh, cpu_id, p[4], v[3];
+ static const char amd_id[] = "AuthenticAMD";
+ static const char hygon_id[] = "HygonGenuine";
+ bool amd_cpu;
+
+ if (cpu_feature == 0)
+ return (2); /* should not happen due to RDTSC */
- if ((cpu_feature & CPUID_SSE2) == 0)
- return (rdtsc32_mb_none);
do_cpuid(0, p);
- return (memcmp(p + 1, intel_id, sizeof(intel_id) - 1) == 0 ?
- rdtsc32_mb_lfence : rdtsc32_mb_mfence);
+ v[0] = p[1];
+ v[1] = p[3];
+ v[2] = p[2];
+ amd_cpu = memcmp(v, amd_id, sizeof(amd_id) - 1) == 0 ||
+ memcmp(v, hygon_id, sizeof(hygon_id) - 1) == 0;
+
+ do_cpuid(1, p);
+ cpu_id = p[0];
+
+ if (cpu_feature != 0) {
+ do_cpuid(0x80000000, p);
+ cpu_exthigh = p[0];
+ } else {
+ cpu_exthigh = 0;
+ }
+ if (cpu_exthigh >= 0x80000001) {
+ do_cpuid(0x80000001, p);
+ amd_feature = p[3];
+ } else {
+ amd_feature = 0;
+ }
+
+ if ((cpu_feature & CPUID_SSE2) == 0)
+ return (2);
+ return (amd_cpu ? 1 : 0);
+}
+
+DEFINE_UIFUNC(static, u_int, __vdso_gettc_rdtsc_low,
+ (const struct vdso_timehands *th))
+{
+ return (tsc_selector[tsc_selector_idx(cpu_feature)].ts_rdtsc_low);
+}
+
+DEFINE_UIFUNC(static, u_int, __vdso_gettc_rdtsc32, (void))
+{
+ return (tsc_selector[tsc_selector_idx(cpu_feature)].ts_rdtsc32);
}
#define HPET_DEV_MAP_MAX 10