public inbox for glibc-cvs@sourceware.org help / color / mirror / Atom feed
From: Florian Weimer <fw@sourceware.org> To: glibc-cvs@sourceware.org Subject: [glibc/fw/x86-diagnostics] WIP CPUID consistency checks Date: Fri, 7 Jun 2024 14:44:28 +0000 (GMT) [thread overview] Message-ID: <20240607144428.72D90393D2CD@sourceware.org> (raw) https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=11db7b454a9cb72ce14be5498cc3f137e9026291 commit 11db7b454a9cb72ce14be5498cc3f137e9026291 Author: Florian Weimer <fweimer@redhat.com> Date: Tue May 28 13:12:16 2024 +0200 WIP CPUID consistency checks Diff: --- sysdeps/unix/sysv/linux/x86_64/Makefile | 6 + .../linux/x86_64/dl-x86_cpu_feature_diagnostics.c | 227 +++++++++++++++++ sysdeps/unix/sysv/linux/x86_64/dl-x86_probes.S | 274 +++++++++++++++++++++ .../x86_64/manual-x86_cpu_feature-diagnostics.py | 34 +++ sysdeps/x86/Makefile | 7 +- sysdeps/x86/dl-diagnostics-cpu.c | 19 ++ sysdeps/x86/dl-get-cpu-features.c | 28 ++- sysdeps/x86/dl-x86_cpu_feature_diagnostics.c | 26 ++ sysdeps/x86/include/cpu-features.h | 23 ++ 9 files changed, 632 insertions(+), 12 deletions(-) diff --git a/sysdeps/unix/sysv/linux/x86_64/Makefile b/sysdeps/unix/sysv/linux/x86_64/Makefile index fcbffd81cb..4fb0dd4d1d 100644 --- a/sysdeps/unix/sysv/linux/x86_64/Makefile +++ b/sysdeps/unix/sysv/linux/x86_64/Makefile @@ -15,6 +15,12 @@ gen-as-const-headers += sigaltstack-offsets.sym endif ifeq ($(subdir),elf) +sysdep-dl-routines += dl-x86_probes +shared-only-routines += dl-x86_probes +# Used internally by dl-x86_cpu_feature_diagnostics.c. +CFLAGS-dl-catch.os += $(rtld-early-cflags) +CFLAGS-rtld-__longjmp.os += $(rtld-early-cflags) + ifeq (yes,$(enable-x86-isa-level)) tests += \ tst-glibc-hwcaps-2 \ diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-x86_cpu_feature_diagnostics.c b/sysdeps/unix/sysv/linux/x86_64/dl-x86_cpu_feature_diagnostics.c new file mode 100644 index 0000000000..6486ebba5d --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/dl-x86_cpu_feature_diagnostics.c @@ -0,0 +1,227 @@ +/* CPU diagnostics probing. Linux/x86-64 version. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <cpu-features.h> +#include <stdbool.h> +#include <stddef.h> +#include <sys/wait.h> +#include <sysdep.h> + +static void +_dl_x86_probe (struct x86_cpu_feature_diagnostics *diag, bool reported, + void (*probe) (void)) +{ + if (reported) + diag->reported |= 1ULL << diag->count; + + /* Use fork/waitid for crash handling. This is simpler than using + signal handling: it does not need global data to communicate with + the handler, nor building out-of-line helper functions to the + baseline ISA, and it avoids dealing differences in sigset_t size. */ + long int ret = INTERNAL_SYSCALL_CALL (fork); + if (ret == 0) + { + /* New process that runs the probe. This may trigger a crash. */ + probe (); + + INTERNAL_SYSCALL_CALL (exit_group, 0); + } + else if (ret > 0) + { + siginfo_t si; + ret = INTERNAL_SYSCALL_CALL (waitid, P_PID, ret, &si, WEXITED, NULL); + if (ret >=0 && si.si_status == 0) + /* Probe was successful. */ + diag->probed |= 1ULL << diag->count; + } + + ++diag->count; +} + +void +_dl_x86_cpu_feature_diagnostics_run (const struct cpu_features *cpu_features, + struct x86_cpu_feature_diagnostics *diag) +{ + /* x86-64-v2 features. */ + extern void _dl_x86_probe_cmpxchg16b (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, CMPXCHG16B), + _dl_x86_probe_cmpxchg16b); + + extern void _dl_x86_probe_sahf (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, LAHF64_SAHF64), + _dl_x86_probe_sahf); + + extern void _dl_x86_probe_popcnt (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, POPCNT), + _dl_x86_probe_popcnt); + + extern void _dl_x86_probe_sse3 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, SSE3), + _dl_x86_probe_sse3); + + extern void _dl_x86_probe_sse4_1 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, SSE4_1), + _dl_x86_probe_sse4_1); + + extern void _dl_x86_probe_sse4_2 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, SSE4_2), + _dl_x86_probe_sse4_2); + + extern void _dl_x86_probe_ssse3 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, SSSE3), + _dl_x86_probe_ssse3); + + /* x86-64-v3 features. */ + extern void _dl_x86_probe_avx (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX), + _dl_x86_probe_avx); + + /* AVX probe using xmm registers. */ + extern void _dl_x86_probe_avx_xmm (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX), + _dl_x86_probe_avx_xmm); + + extern void _dl_x86_probe_avx2 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX2), + _dl_x86_probe_avx2); + + extern void _dl_x86_probe_bmi1 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, BMI1), + _dl_x86_probe_bmi1); + + /* Alternative BMI1 probe. Perhaps harder to mask. */ + extern void _dl_x86_probe_bmi1_tzcnt (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, BMI1), + _dl_x86_probe_bmi1_tzcnt); + + extern void _dl_x86_probe_bmi2 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, BMI2), + _dl_x86_probe_bmi2); + + extern void _dl_x86_probe_f16c (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, F16C), + _dl_x86_probe_f16c); + + extern void _dl_x86_probe_fma (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, FMA), + _dl_x86_probe_fma); + + /* FMA4 is not part of x86-64-v3, but may produce a useful hint. */ + extern void _dl_x86_probe_fma4 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, FMA4), + _dl_x86_probe_fma4); + + extern void _dl_x86_probe_lzcnt (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, LZCNT), + _dl_x86_probe_lzcnt); + + extern void _dl_x86_probe_movbe (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, MOVBE), + _dl_x86_probe_movbe); + + extern void _dl_x86_probe_osxsave (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, OSXSAVE), + _dl_x86_probe_osxsave); + + /* x86-64-v4 features. */ + extern void _dl_x86_probe_avx512f (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512F), + _dl_x86_probe_avx512f); + + extern void _dl_x86_probe_avx512bw (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512BW), + _dl_x86_probe_avx512bw); + + extern void _dl_x86_probe_avx512bw_ymm (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512BW), + _dl_x86_probe_avx512bw_ymm); + + extern void _dl_x86_probe_avx512cd (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512CD), + _dl_x86_probe_avx512cd); + + extern void _dl_x86_probe_avx512cd_ymm0 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512CD), + _dl_x86_probe_avx512cd_ymm0); + + extern void _dl_x86_probe_avx512vl (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512VL), + _dl_x86_probe_avx512vl); + + /* Other CPU features, not part of microarchitecture levels. */ + extern void _dl_x86_probe_adx (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, ADX), + _dl_x86_probe_adx); + + extern void _dl_x86_probe_aes (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AES), + _dl_x86_probe_aes); + + extern void _dl_x86_probe_aes_avx (void) attribute_hidden; + _dl_x86_probe (diag, + CPU_FEATURE_USABLE_P (cpu_features, AES) + && CPU_FEATURE_USABLE_P (cpu_features, AVX), + _dl_x86_probe_aes_avx); + + extern void _dl_x86_probe_vaes (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, VAES), + _dl_x86_probe_vaes); + + extern void _dl_x86_probe_sha (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, SHA), + _dl_x86_probe_sha); + + extern void _dl_x86_probe_avx512_vbmi (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512_VBMI), + _dl_x86_probe_avx512_vbmi); + + extern void _dl_x86_probe_avx512_vbmi_xmm (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512_VBMI), + _dl_x86_probe_avx512_vbmi_xmm); + + extern void _dl_x86_probe_avx512_vbmi2 (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512_VBMI2), + _dl_x86_probe_avx512_vbmi2); + + extern void _dl_x86_probe_avx512_vbmi2_xmm (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512_VBMI2), + _dl_x86_probe_avx512_vbmi2_xmm); + + extern void _dl_x86_probe_avx_vnni (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX_VNNI), + _dl_x86_probe_avx_vnni); + + extern void _dl_x86_probe_avx512_vnni (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512_VNNI), + _dl_x86_probe_avx512_vnni); + + extern void _dl_x86_probe_avx512_ifma (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, AVX512_IFMA), + _dl_x86_probe_avx512_ifma); + + serialize + tpause + ptwrite + xsusldtrk + clmul + crc32 + + extern void _dl_x86_probe_apx_f (void) attribute_hidden; + _dl_x86_probe (diag, CPU_FEATURE_USABLE_P (cpu_features, APX_F), + _dl_x86_probe_apx_f); +} diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-x86_probes.S b/sysdeps/unix/sysv/linux/x86_64/dl-x86_probes.S new file mode 100644 index 0000000000..e1226763ac --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/dl-x86_probes.S @@ -0,0 +1,274 @@ +/* Diagnostics probes for the x86 CPU family. Generic version. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <sysdep.h> + +ENTRY (_dl_x86_probe_cmpxchg16b) + xorl %eax, %eax + movq %rax, -8(%rsp) + movq %rax, -16(%rsp) + xorl %edx, %edx + cmpxchg16b -8(%rsp) + ret +END (_dl_x86_probe_cmpxchg16b) + +ENTRY (_dl_x86_probe_sahf) + xorl %eax, %eax + sahf + ret +END (_dl_x86_probe_sahf) + +ENTRY (_dl_x86_probe_popcnt) + xorl %eax, %eax + popcnt %eax, %eax + ret +END (_dl_x86_probe_popcnt) + +ENTRY (_dl_x86_probe_sse3) + pxor %xmm0, %xmm0 + addsubpd %xmm0, %xmm0 + ret +END (_dl_x86_probe_sse3) + +ENTRY (_dl_x86_probe_sse4_1) + pxor %xmm0, %xmm0 + blendpd $1, %xmm0, %xmm0 + ret +END (_dl_x86_probe_sse4_1) + +ENTRY (_dl_x86_probe_sse4_2) + pxor %xmm0, %xmm0 + pcmpestri $0, %xmm0, %xmm0 + ret +END (_dl_x86_probe_sse4_2) + +ENTRY (_dl_x86_probe_ssse3) + pxor %xmm0, %xmm0 + phaddd %xmm0, %xmm0 + ret +END (_dl_x86_probe_ssse3) + +ENTRY (_dl_x86_probe_avx) + vzeroall + ret +END (_dl_x86_probe_avx) + +ENTRY (_dl_x86_probe_avx_xmm) + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + vpxor %xmm0, %xmm1, %xmm2 + ret +END (_dl_x86_probe_avx_xmm) + +ENTRY (_dl_x86_probe_avx2) + vpxor %ymm0, %ymm0, %ymm0 + vpermd %ymm0, %ymm0, %ymm0 + ret +END (_dl_x86_probe_avx2) + +ENTRY (_dl_x86_probe_bmi1) + xorl %eax, %eax + andnl %eax, %eax, %eax + ret +END (_dl_x86_probe_bmi1) + +ENTRY (_dl_x86_probe_bmi1_tzcnt) + xorl %eax, %eax + /* Executes as bsfl if unsupported. */ + tzcntl %eax, %eax + cmp $32, %eax + jne 1f + ret +1: + ud2 +END (_dl_x86_probe_bmi1_tzcnt) + +ENTRY (_dl_x86_probe_bmi2) + xorl %eax, %eax + bzhil %eax, %eax, %eax + ret +END (_dl_x86_probe_bmi2) + +ENTRY (_dl_x86_probe_f16c) + pxor %xmm0, %xmm0 + vcvtph2ps %xmm0, %xmm0 + ret +END (_dl_x86_probe_f16c) + +ENTRY (_dl_x86_probe_fma) + pxor %xmm0, %xmm0 + vfmadd132pd %xmm0, %xmm0, %xmm0 + ret +END (_dl_x86_probe_fma) + +ENTRY (_dl_x86_probe_fma4) + pxor %xmm0, %xmm0 + vfmaddpd %xmm0, %xmm0, %xmm0, %xmm0 + ret +END (_dl_x86_probe_fma4) + +ENTRY (_dl_x86_probe_lzcnt) + xorl %eax, %eax + /* Executes as bsrl if unsupported. */ + lzcntl %eax, %eax + cmp $32, %eax + jne 1f + ret +1: + ud2 +END (_dl_x86_probe_lzcnt) + +ENTRY (_dl_x86_probe_movbe) + movbeq (%rsp), %rax + ret +1: + ud2 +END (_dl_x86_probe_movbe) + +ENTRY (_dl_x86_probe_osxsave) + xorl %ecx, %ecx + xgetbv + ret +END (_dl_x86_probe_osxsave) + +ENTRY (_dl_x86_probe_avx512f) + xorl %eax, %eax + kmovw %eax, %k0 + ret +END (_dl_x86_probe_avx512f) + +ENTRY (_dl_x86_probe_avx512bw) + vpxorq %zmm0, %zmm0, %zmm0 + vdbpsadbw $0, %zmm0, %zmm0, %zmm0 + ret +END (_dl_x86_probe_avx512bw) + +ENTRY (_dl_x86_probe_avx512bw_ymm) + vpxorq %ymm0, %ymm0, %ymm0 + vdbpsadbw $0, %ymm0, %ymm0, %ymm0 + ret +END (_dl_x86_probe_avx512bw) + +ENTRY (_dl_x86_probe_avx512cd) + vpxorq %zmm0, %zmm0, %zmm0 + vplzcntd %zmm0, %zmm0 + ret +END (_dl_x86_probe_avx512cd) + +ENTRY (_dl_x86_probe_avx512cd_ymm0) + vpxorq %ymm0, %ymm0, %ymm0 + vplzcntd %ymm0, %ymm0 + ret +END (_dl_x86_probe_avx512cd_ymm0) + +ENTRY (_dl_x86_probe_avx512dq) + vpxorq %zmm0, %zmm0, %zmm0 + vpmullq %zmm0, %zmm0, %zmm0 + ret +END (_dl_x86_probe_avx512dq) + +ENTRY (_dl_x86_probe_avx512dq_ymm0) + vpxorq %ymm0, %ymm0, %ymm0 + vpmulld %ymm0, %ymm0, %ymm0 + ret +END (_dl_x86_probe_avx512dq_ymm0) + +ENTRY (_dl_x86_probe_avx512vl) + xorl %eax, %eax + vpbroadcastq %rax, %xmm1 + ret +END (_dl_x86_probe_avx512vl) + +ENTRY (_dl_x86_probe_adx) + xorl %eax, %eax + adcxl %eax, %eax + ret +END (_dl_x86_probe_adx) + +ENTRY (_dl_x86_probe_aes) + pxor %xmm0, %xmm0 + aesenc %xmm0, %xmm0 + ret +END (_dl_x86_probe_aes) + +ENTRY (_dl_x86_probe_aes_avx) + pxor %xmm0, %xmm0 + vaesenc %xmm0, %xmm0, %xmm0 + ret +END (_dl_x86_probe_aes_avx) + +ENTRY (_dl_x86_probe_vaes) + vpxor %ymm0, %ymm0, %ymm0 + vaesenc %ymm0, %ymm0, %ymm0 + ret +END (_dl_x86_probe_vaes) + +ENTRY (_dl_x86_probe_sha) + pxor %xmm0, %xmm0 + sha1rnds4 $0, %xmm0, %xmm0 + ret +END (_dl_x86_probe_sha) + +ENTRY (_dl_x86_probe_avx512_vbmi) + vpxorq %zmm0, %zmm0, %zmm0 + vpermb %zmm0, %zmm0, %zmm0 + ret +END (_dl_x86_probe_avx512_vbmi) + +ENTRY (_dl_x86_probe_avx512_vbmi_xmm) + pxor %xmm0, %xmm0 + vpermb %xmm0, %xmm0, %xmm0 + ret +END (_dl_x86_probe_avx512_vbmi_xmm) + +ENTRY (_dl_x86_probe_avx512_vbmi2) + vpxorq %zmm0, %zmm0, %zmm0 + vpshrdd $1, %zmm0, %zmm0, %zmm0 + ret +END (_dl_x86_probe_avx512_vbmi2) + +ENTRY (_dl_x86_probe_avx512_vbmi2_xmm) + pxor %xmm0, %xmm0 + vpshrdd $1, %xmm0, %xmm0, %xmm0 + ret +END (_dl_x86_probe_avx512_vbmi2_xmm) + +ENTRY (_dl_x86_probe_avx_vnni) + pxor %xmm0, %xmm0 + /* Default is to use EVEX encoding. */ + /* {vex} vpdpbusd %xmm0, %xmm0, %xmm0 */ + .byte 0xc4, 0xe2, 0x79, 0x50, 0xc0 + ret +END (_dl_x86_probe_avx_vnni) + +ENTRY (_dl_x86_probe_avx512_vnni) + vpxorq %zmm0, %zmm0, %zmm0 + vpdpbusd %zmm0, %zmm0, %zmm0 + ret +END (_dl_x86_probe_avx512_vnni) + +ENTRY (_dl_x86_probe_avx512_ifma) + vpxorq %zmm0, %zmm0, %zmm0 + vpmadd52luq %zmm0, %zmm0, %zmm0 + ret +END (_dl_x86_probe_avx512_ifma) + +ENTRY (_dl_x86_probe_apx_f) + .byte 0x62, 0xf4, 0x7c, 0x18, 0x01, 0xff /* add %edi, %edi, %eax */ + ret +END (_dl_x86_probe_apx_f) diff --git a/sysdeps/unix/sysv/linux/x86_64/manual-x86_cpu_feature-diagnostics.py b/sysdeps/unix/sysv/linux/x86_64/manual-x86_cpu_feature-diagnostics.py new file mode 100644 index 0000000000..a8730d3371 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/manual-x86_cpu_feature-diagnostics.py @@ -0,0 +1,34 @@ +# CPU diagnostics probing. Generating documentatable for t he manual +# Copyright (C) 2024 Free Software Foundation, Inc. +# This file is part of the GNU C Library. +# +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with the GNU C Library; if not, see +# <https://www.gnu.org/licenses/>. + +import re +import sys + +path, = sys.argv[1:] + +RE_PROBE = re.compile('^\s+_dl_x86_probe_([a-z0-9_]+)\);$') + +bit = 1 +with open(path) as inp: + for line in inp: + m = RE_PROBE.match(line) + if m: + name = m.group(1) + print('@item 0x{:08x}:{:08x}'.format(bit >> 32, bit & 0xffffffff)) + print('@code{' + name + '}') + bit *= 2 diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile index 5311b594af..010f15b122 100644 --- a/sysdeps/x86/Makefile +++ b/sysdeps/x86/Makefile @@ -4,7 +4,11 @@ endif ifeq ($(subdir),elf) sysdep_routines += get-cpuid-feature-leaf -sysdep-dl-routines += dl-get-cpu-features +sysdep-dl-routines += \ + dl-get-cpu-features \ + dl-x86_cpu_feature_diagnostics \ + # sysdep-dl-routines +shared-only-routines += dl-x86_cpu_feature_diagnostics sysdep_headers += \ bits/platform/features.h \ bits/platform/x86.h \ @@ -12,6 +16,7 @@ sysdep_headers += \ # sysdep_headers CFLAGS-dl-get-cpu-features.os += $(rtld-early-cflags) +CFLAGS-dl-x86_cpu_feature_diagnostics.os += $(rtld-early-cflags) CFLAGS-get-cpuid-feature-leaf.o += $(no-stack-protector) tests += \ diff --git a/sysdeps/x86/dl-diagnostics-cpu.c b/sysdeps/x86/dl-diagnostics-cpu.c index ceafde9481..5555c473c1 100644 --- a/sysdeps/x86/dl-diagnostics-cpu.c +++ b/sysdeps/x86/dl-diagnostics-cpu.c @@ -51,6 +51,14 @@ print_cpu_feature_preferred (const char *label, unsigned int flag) _dl_printf("x86.cpu_features.preferred.%s=0x%x\n", label, flag); } +static void +_dl_x86_cpu_feature_diagnostics_print (const char *label, + unsigned long long int value) +{ + _dl_printf("x86.diagnostics."); + _dl_diagnostics_print_labeled_value (label, value); +} + void _dl_diagnostics_cpu (void) { @@ -132,6 +140,17 @@ _dl_diagnostics_cpu (void) == sizeof (*cpu_features), "last cpu_features field has been printed"); + { + struct x86_cpu_feature_diagnostics diag; + _dl_x86_cpu_feature_diagnostics_init (&diag); + _dl_x86_cpu_feature_diagnostics_run (cpu_features, &diag); + _dl_x86_cpu_feature_diagnostics_print ("count", diag.count); + _dl_x86_cpu_feature_diagnostics_print ("reported", diag.reported); + _dl_x86_cpu_feature_diagnostics_print ("probed", diag.probed); + _dl_x86_cpu_feature_diagnostics_print ("filtered", + diag.probed & ~diag.reported); + } + _dl_diagnostics_cpuid (); } diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c index f36d42d6af..7961aa3b9d 100644 --- a/sysdeps/x86/dl-get-cpu-features.c +++ b/sysdeps/x86/dl-get-cpu-features.c @@ -33,14 +33,20 @@ void (*const __x86_cpu_features_p) (void) attribute_hidden = __x86_cpu_features; _Noreturn static void __attribute__ ((unused)) -_dl_x86_init_cpu_failure (const struct cpu_features *cpu_features, int level) +_dl_x86_init_cpu_failure (const struct cpu_features *cpu_features, + const char *label) { - if (level == 5) - _dl_fatal_printf ("\ -Fatal glibc error: CPU does not support APX\n"); - else - _dl_fatal_printf ("\ -Fatal glibc error: CPU does not support x86-64-v%d\n", level); + struct x86_cpu_feature_diagnostics diag; + _dl_x86_cpu_feature_diagnostics_init (&diag); + _dl_x86_cpu_feature_diagnostics_run (cpu_features, &diag); + + _dl_fatal_printf ("\ +Fatal glibc error: CPU does not support %s [%u 0x%x:%x 0x%x:%x]\n", + label, diag.count, + (unsigned int) (diag.reported >> 32), + (unsigned int) diag.reported, + (unsigned int) (diag.probed >> 32), + (unsigned int) diag.probed); } void @@ -58,23 +64,23 @@ _dl_x86_init_cpu_features (void) && defined GCCMACRO__SSE3__ && defined GCCMACRO__SSSE3__ \ && defined GCCMACRO__SSE4_1__ && defined GCCMACRO__SSE4_2__ if (!(cpu_features->isa_1 & GNU_PROPERTY_X86_ISA_1_V2)) - _dl_x86_init_cpu_failure (cpu_features, 2); + _dl_x86_init_cpu_failure (cpu_features, "x86-64-v2"); # if defined GCCMACRO__AVX__ && defined GCCMACRO__AVX2__ \ && defined GCCMACRO__F16C__ && defined GCCMACRO__FMA__ \ && defined GCCMACRO__LZCNT__ && defined HAVE_X86_MOVBE if (!(cpu_features->isa_1 & GNU_PROPERTY_X86_ISA_1_V3)) - _dl_x86_init_cpu_failure (cpu_features, 3); + _dl_x86_init_cpu_failure (cpu_features, "x86-64-v3"); # if defined GCCMACRO__AVX512F__ && defined GCCMACRO__AVX512BW__ \ && defined GCCMACRO__AVX512CD__ && defined GCCMACRO__AVX512DQ__ \ && defined GCCMACRO__AVX512VL__ if (!(cpu_features->isa_1 & GNU_PROPERTY_X86_ISA_1_V4)) - _dl_x86_init_cpu_failure (cpu_features, 4); + _dl_x86_init_cpu_failure (cpu_features, "x86-64-v4"); # endif /* ISA level 4 */ # endif /* ISA level 3 */ # endif /* ISA level 2 */ # ifdef GCCMACRO__APX_F__ if (!CPU_FEATURE_USABLE_P (cpu_features, APX_F)) - _dl_x86_init_cpu_failure (cpu_features, 5); + _dl_x86_init_cpu_failure (cpu_features, "APX"); # endif # endif /* IS_IN (rtld) */ } diff --git a/sysdeps/x86/dl-x86_cpu_feature_diagnostics.c b/sysdeps/x86/dl-x86_cpu_feature_diagnostics.c new file mode 100644 index 0000000000..bb7ff9c24d --- /dev/null +++ b/sysdeps/x86/dl-x86_cpu_feature_diagnostics.c @@ -0,0 +1,26 @@ +/* CPU diagnostics probing. Generic x86 version. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <https://www.gnu.org/licenses/>. */ + +#include <cpu-features + +/* The generic version does not have any probes. */ +void +_dl_x86_cpu_feature_diagnostics_run (const struct cpu_features *cpu_features, + struct x86_cpu_feature_diagnostics *diag) +{ +} diff --git a/sysdeps/x86/include/cpu-features.h b/sysdeps/x86/include/cpu-features.h index cd7bd27cf3..2eea95d56b 100644 --- a/sysdeps/x86/include/cpu-features.h +++ b/sysdeps/x86/include/cpu-features.h @@ -987,6 +987,29 @@ extern const struct cpu_features *_dl_x86_get_cpu_features (void) #define __get_cpu_features() _dl_x86_get_cpu_features() +/* Used to store diagnostic information for startup failure reporting. + See _dl_x86_init_cpu_failure in sysdeps/x86/dl-diagnostics-cpu.c. */ +struct x86_cpu_feature_diagnostics +{ + unsigned int count; /* Bits recorded. */ + unsigned long long int reported; /* From CPUID. */ + unsigned long long int probed; /* From execution probing. */ +}; + +/* Initialize *DIAG prior to the diagnostics run below. */ +static inline void +_dl_x86_cpu_feature_diagnostics_init (struct x86_cpu_feature_diagnostics *diag) +{ + diag->count = 0; + diag->reported = 0; + diag->probed = 0; +} + +/* Updated the diagnostics with CPUID and execution probing information. */ +void _dl_x86_cpu_feature_diagnostics_run (const struct cpu_features *, + struct x86_cpu_feature_diagnostics *) + attribute_hidden; + #if defined (_LIBC) && !IS_IN (nonlib) /* Unused for x86. */ # define INIT_ARCH()
reply other threads:[~2024-06-07 14:44 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20240607144428.72D90393D2CD@sourceware.org \ --to=fw@sourceware.org \ --cc=glibc-cvs@sourceware.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).