This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RFC: Add <sys/platform/x86.h> to glibc 2.29


On 07/29/2018 12:16 PM, H.J. Lu wrote:
> I am proposing to add <sys/platform/x86.h> to glibc 2.29 to provide
> an API to access x86 specific platform features:
> 
> enum
>   {
>     /* The integer bit array index of architecture feature bits.  */
>     FEATURE_INDEX_1 = 0,
>     FEATURE_INDEX_2,
>     /* The current maximum size of the feature integer bit array.  */
>     FEATURE_INDEX_MAX
>   };
> 
> enum
>   {
>     COMMON_CPUID_INDEX_1 = 0,
>     COMMON_CPUID_INDEX_7,
>     COMMON_CPUID_INDEX_80000001,
>     COMMON_CPUID_INDEX_D_ECX_1,
>     COMMON_CPUID_INDEX_80000007,
>     COMMON_CPUID_INDEX_80000008,
>     /* Keep the following line at the end.  */
>     COMMON_CPUID_INDEX_MAX
>   };
> 
> enum cpu_features_kind
>   {
>     arch_kind_unknown = 0,
>     arch_kind_intel,
>     arch_kind_amd,
>     arch_kind_other
>   };
> 
> struct cpuid_registers
>   {
>     unsigned int eax;
>     unsigned int ebx;
>     unsigned int ecx;
>     unsigned int edx;
>   };
> 
> extern enum cpu_features_kind __x86_get_cpu_kind (void)
>      __attribute__ ((const));
> 
> extern const struct cpuid_registers *__x86_get_cpuid_registers
>      (unsigned int) __attribute__ ((const));
> 
> extern unsigned int __x86_get_arch_feature (unsigned int)
>      __attribute__ ((const));
> 
> extern unsigned long long __x86_tsc_to_ns (unsigned long long);
> extern unsigned long long __x86_ns_to_tsc (unsigned long long);
> 
> /* HAS_* evaluates to true if we may use the feature at runtime.  */
> #define HAS_CPU_FEATURE(name) \
>    ((__x86_get_cpuid_registers (index_cpu_##name)->reg_##name \
>      & (bit_cpu_##name)) != 0)

I don't like these as macros.

I would rather an inline function that does all the work within the function
and returns a result of the appropriate type e.g. boolean.

> #define HAS_ARCH_FEATURE(name) \
>    ((__x86_get_arch_feature (index_arch_##name) & (bit_arch_##name)) != 0)
> 

Likewise.

> Users can use <sys/platform/x86.h> to detect if a CPU feature is
> supported at run-time with
> 
> HAS_CPU_FEATURE (AVX)

Likewise.

> which returns true if glibc detects that AVX is available.  Before AVX
> can be used, he/she should check
> 
> HAS_ARCH_FEATURE (AVX_Usable)

Likewise.

These macros like this are harder to debug than static inline functions.

> which returns true if glibc detects that AVX is available and usable.
> 
> extern unsigned long long __x86_tsc_to_ns (unsigned long long);
> extern unsigned long long __x86_ns_to_tsc (unsigned long long);
> 
> can be used to convert between TSCs and nanoseconds if
> 
> HAS_ARCH_FEATURE (TSC_To_NS_Usable)
> 
> returns true.
> 
> Backward binary compatibility is provided by:
> 
> 1. __x86_get_cpu_kind will get a new version if a new CPU kind is added
> to cpu_features_kind.

This function takes void and returns the kind of CPU as an enum value. OK.

> 2. __x86_get_cpuid_registers returns a pointer to a cpuid_registers
> with all zeros if cpuid index >= COMMON_CPUID_INDEX_MAX.

Could you expand on this in more detail please.

> 3. __x86_get_arch_feature returns 0 if architecture index >=
> FEATURE_INDEX_MAX.

Likewise.

> This means:
> 
> 1. Applications linked against the new __x86_get_cpu_kind will only
> run with the newer libc.so.

How? Symbol versioning?

> 2. Applications linked against the new __x86_get_cpuid_registers and
> __x86_get_arch_feature will run with the older libc.so.  But new
> CPU and architecture features won't be detected by the older libc.so.

The caller must attempt to copy or inspect all the data, but it's structure
size may be larger, and the old glibc structure may be smaller, how do you
prevent the newer program from reading out of bounds when run in an older
glibc? This question is only relevant for __x86_get_cpuid_registers which
returns a pointer to a fixed size structure. The structure can grow, but
the caller needs to know exactly how big the returned structure is to avoid
reading outside of bounds.

> This program:
> 
> https://github.com/hjl-tools/glibc/blob/hjl/platform/master/sysdeps/x86/tst-x86-platform-1.c
> 
> may display:
> 
> [hjl@gnu-efi-2 build-x86_64-linux]$ ./elf/tst-x86-platform-1
> Vendor: Intel
> CPU features:
>   SSE3
>   PCLMULQDQ
>   DTES64
>   MONITOR
>   DS_CPL
>   VMX
>   EST
>   TM2
>   SSSE3
>   SDBG
>   FMA
>   CMPXCHG16B
>   XTPRUPDCTRL
>   PDCM
>   PCID
>   SSE4_1
>   SSE4_2
>   X2APIC
>   MOVBE
>   POPCOUNT
>   TSC_DEADLINE
>   AES
>   XSAVE
>   OSXSAVE
>   AVX
>   F16C
>   RDRAND
>   FPU
>   VME
>   DE
>   PSE
>   TSC
>   MSR
>   PAE
>   MCE
>   CX8
>   APIC
>   SEP
>   MTRR
>   PGE
>   MCA
>   CMOV
>   PAT
>   PSE_36
>   DS
>   ACPI
>   MMX
>   FXSR
>   SSE
>   SSE2
>   SS
>   HTT
>   TM
>   PBE
>   FSGSBASE
>   TSC_ADJUST
>   SGX
>   BMI1
>   AVX2
>   BMI2
>   ERMS
>   INVPCID
>   MPX
>   RDSEED
>   ADX
>   SMAP
>   TRACE
>   LAHF64_SAHF64
>   LZCNT
>   PREFETCHW
>   SYSCALL_SYSRET
>   NX
>   PAGE1GB
>   RDTSCP
>   LM
>   XSAVEOPT
>   XSAVEC
>   XGETBV_ECX_1
>   XSAVES
>   INVARIANT_TSC
> Architecture features:
>   AVX_Usable
>   AVX2_Usable
>   FMA_Usable
>   XSAVEC_Usable
>   TSC_To_NS_Usable
> [hjl@gnu-efi-2 build-x86_64-linux]$
> 
> Any comments?

The data you want to share seems reasonable, but I expect we'll need
some iteration on the interface design.
 
> H.J.
> 


-- 
Cheers,
Carlos.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]