WIP CPUID consistency checks

This commit is contained in:
Florian Weimer 2024-05-28 13:12:16 +02:00
parent 815c048269
commit 11db7b454a
9 changed files with 632 additions and 12 deletions

View File

@ -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 \

View File

@ -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);
}

View File

@ -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)

View File

@ -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

View File

@ -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 += \

View File

@ -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 ();
}

View File

@ -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) */
}

View File

@ -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)
{
}

View File

@ -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()