Blame sysdeps/x86/cpu-features.c

Packit 6c4009
/* Initialize CPU feature data.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Copyright (C) 2008-2018 Free Software Foundation, Inc.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <cpuid.h>
Packit Service 3b0880
#include <cpu-features.h>
Packit 6c4009
#include <dl-hwcap.h>
Packit 6c4009
#include <libc-pointer-arith.h>
Packit 6c4009
Packit 6c4009
#if HAVE_TUNABLES
Packit Service 3b0880
# define TUNABLE_NAMESPACE tune
Packit 6c4009
# include <unistd.h>		/* Get STDOUT_FILENO for _dl_printf.  */
Packit 6c4009
# include <elf/dl-tunables.h>
Packit 6c4009
Packit 6c4009
extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
Packit 6c4009
# if CET_ENABLED
Packit 6c4009
extern void TUNABLE_CALLBACK (set_x86_ibt) (tunable_val_t *)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
extern void TUNABLE_CALLBACK (set_x86_shstk) (tunable_val_t *)
Packit 6c4009
  attribute_hidden;
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if CET_ENABLED
Packit 6c4009
# include <dl-cet.h>
Packit Service 3b0880
# include <cet-tunables.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
static void
Packit Service 3b0880
get_extended_indices (struct cpu_features *cpu_features)
Packit 6c4009
{
Packit Service 3b0880
  unsigned int eax, ebx, ecx, edx;
Packit Service 3b0880
  __cpuid (0x80000000, eax, ebx, ecx, edx);
Packit Service 3b0880
  if (eax >= 0x80000001)
Packit Service 3b0880
    __cpuid (0x80000001,
Packit Service 3b0880
	     cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].eax,
Packit Service 3b0880
	     cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ebx,
Packit Service 3b0880
	     cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].ecx,
Packit Service 3b0880
	     cpu_features->cpuid[COMMON_CPUID_INDEX_80000001].edx);
Packit Service 3b0880
Packit Service 3b0880
}
Packit Service 3b0880
Packit Service 3b0880
static void
Packit Service 3b0880
get_common_indeces (struct cpu_features *cpu_features,
Packit Service 3b0880
		    unsigned int *family, unsigned int *model,
Packit Service 3b0880
		    unsigned int *extended_model, unsigned int *stepping)
Packit Service 3b0880
{
Packit Service 3b0880
  if (family)
Packit Service 3b0880
    {
Packit Service 3b0880
      unsigned int eax;
Packit Service 3b0880
      __cpuid (1, eax, cpu_features->cpuid[COMMON_CPUID_INDEX_1].ebx,
Packit Service 3b0880
	       cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx,
Packit Service 3b0880
	       cpu_features->cpuid[COMMON_CPUID_INDEX_1].edx);
Packit Service 3b0880
      cpu_features->cpuid[COMMON_CPUID_INDEX_1].eax = eax;
Packit Service 3b0880
      *family = (eax >> 8) & 0x0f;
Packit Service 3b0880
      *model = (eax >> 4) & 0x0f;
Packit Service 3b0880
      *extended_model = (eax >> 12) & 0xf0;
Packit Service 3b0880
      *stepping = eax & 0x0f;
Packit Service 3b0880
      if (*family == 0x0f)
Packit Service 3b0880
	{
Packit Service 3b0880
	  *family += (eax >> 20) & 0xff;
Packit Service 3b0880
	  *model += *extended_model;
Packit Service 3b0880
	}
Packit Service 3b0880
    }
Packit Service 3b0880
Packit Service 3b0880
  if (cpu_features->max_cpuid >= 7)
Packit Service 3b0880
    __cpuid_count (7, 0,
Packit Service 3b0880
		   cpu_features->cpuid[COMMON_CPUID_INDEX_7].eax,
Packit Service 3b0880
		   cpu_features->cpuid[COMMON_CPUID_INDEX_7].ebx,
Packit Service 3b0880
		   cpu_features->cpuid[COMMON_CPUID_INDEX_7].ecx,
Packit Service 3b0880
		   cpu_features->cpuid[COMMON_CPUID_INDEX_7].edx);
Packit Service a6fc86
Packit 6c4009
  /* Can we call xgetbv?  */
Packit 6c4009
  if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE))
Packit 6c4009
    {
Packit 6c4009
      unsigned int xcrlow;
Packit 6c4009
      unsigned int xcrhigh;
Packit 6c4009
      asm ("xgetbv" : "=a" (xcrlow), "=d" (xcrhigh) : "c" (0));
Packit 6c4009
      /* Is YMM and XMM state usable?  */
Packit 6c4009
      if ((xcrlow & (bit_YMM_state | bit_XMM_state)) ==
Packit 6c4009
	  (bit_YMM_state | bit_XMM_state))
Packit 6c4009
	{
Packit 6c4009
	  /* Determine if AVX is usable.  */
Packit 6c4009
	  if (CPU_FEATURES_CPU_P (cpu_features, AVX))
Packit 6c4009
	    {
Packit Service 3b0880
	      cpu_features->feature[index_arch_AVX_Usable]
Packit Service 3b0880
		|= bit_arch_AVX_Usable;
Packit 6c4009
	      /* The following features depend on AVX being usable.  */
Packit 6c4009
	      /* Determine if AVX2 is usable.  */
Packit 6c4009
	      if (CPU_FEATURES_CPU_P (cpu_features, AVX2))
Packit Service 3b0880
	      {
Packit Service 3b0880
		cpu_features->feature[index_arch_AVX2_Usable]
Packit Service 3b0880
		  |= bit_arch_AVX2_Usable;
Packit Service 3b0880
Packit Service 3b0880
	        /* Unaligned load with 256-bit AVX registers are faster on
Packit Service 3b0880
	           Intel/AMD processors with AVX2.  */
Packit Service 3b0880
	        cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load]
Packit Service 3b0880
		  |= bit_arch_AVX_Fast_Unaligned_Load;
Packit Service 3b0880
	      }
Packit 6c4009
	      /* Determine if FMA is usable.  */
Packit Service 3b0880
	      if (CPU_FEATURES_CPU_P (cpu_features, FMA))
Packit Service 3b0880
		cpu_features->feature[index_arch_FMA_Usable]
Packit Service 3b0880
		  |= bit_arch_FMA_Usable;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Check if OPMASK state, upper 256-bit of ZMM0-ZMM15 and
Packit 6c4009
	     ZMM16-ZMM31 state are enabled.  */
Packit 6c4009
	  if ((xcrlow & (bit_Opmask_state | bit_ZMM0_15_state
Packit 6c4009
			 | bit_ZMM16_31_state)) ==
Packit 6c4009
	      (bit_Opmask_state | bit_ZMM0_15_state | bit_ZMM16_31_state))
Packit 6c4009
	    {
Packit 6c4009
	      /* Determine if AVX512F is usable.  */
Packit 6c4009
	      if (CPU_FEATURES_CPU_P (cpu_features, AVX512F))
Packit 6c4009
		{
Packit Service 3b0880
		  cpu_features->feature[index_arch_AVX512F_Usable]
Packit Service 3b0880
		    |= bit_arch_AVX512F_Usable;
Packit 6c4009
		  /* Determine if AVX512DQ is usable.  */
Packit Service 3b0880
		  if (CPU_FEATURES_CPU_P (cpu_features, AVX512DQ))
Packit Service 3b0880
		    cpu_features->feature[index_arch_AVX512DQ_Usable]
Packit Service 3b0880
		      |= bit_arch_AVX512DQ_Usable;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* For _dl_runtime_resolve, set xsave_state_size to xsave area
Packit 6c4009
	 size + integer register save size and align it to 64 bytes.  */
Packit Service 3b0880
      if (cpu_features->max_cpuid >= 0xd)
Packit 6c4009
	{
Packit 6c4009
	  unsigned int eax, ebx, ecx, edx;
Packit 6c4009
Packit 6c4009
	  __cpuid_count (0xd, 0, eax, ebx, ecx, edx);
Packit 6c4009
	  if (ebx != 0)
Packit 6c4009
	    {
Packit 6c4009
	      unsigned int xsave_state_full_size
Packit 6c4009
		= ALIGN_UP (ebx + STATE_SAVE_OFFSET, 64);
Packit 6c4009
Packit 6c4009
	      cpu_features->xsave_state_size
Packit 6c4009
		= xsave_state_full_size;
Packit 6c4009
	      cpu_features->xsave_state_full_size
Packit 6c4009
		= xsave_state_full_size;
Packit 6c4009
Packit Service 3b0880
	      __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
Packit Service 3b0880
Packit 6c4009
	      /* Check if XSAVEC is available.  */
Packit Service 3b0880
	      if ((eax & (1 << 1)) != 0)
Packit 6c4009
		{
Packit 6c4009
		  unsigned int xstate_comp_offsets[32];
Packit 6c4009
		  unsigned int xstate_comp_sizes[32];
Packit 6c4009
		  unsigned int i;
Packit 6c4009
Packit 6c4009
		  xstate_comp_offsets[0] = 0;
Packit 6c4009
		  xstate_comp_offsets[1] = 160;
Packit 6c4009
		  xstate_comp_offsets[2] = 576;
Packit 6c4009
		  xstate_comp_sizes[0] = 160;
Packit 6c4009
		  xstate_comp_sizes[1] = 256;
Packit 6c4009
Packit 6c4009
		  for (i = 2; i < 32; i++)
Packit 6c4009
		    {
Packit 6c4009
		      if ((STATE_SAVE_MASK & (1 << i)) != 0)
Packit 6c4009
			{
Packit 6c4009
			  __cpuid_count (0xd, i, eax, ebx, ecx, edx);
Packit 6c4009
			  xstate_comp_sizes[i] = eax;
Packit 6c4009
			}
Packit 6c4009
		      else
Packit 6c4009
			{
Packit 6c4009
			  ecx = 0;
Packit 6c4009
			  xstate_comp_sizes[i] = 0;
Packit 6c4009
			}
Packit 6c4009
Packit 6c4009
		      if (i > 2)
Packit 6c4009
			{
Packit 6c4009
			  xstate_comp_offsets[i]
Packit 6c4009
			    = (xstate_comp_offsets[i - 1]
Packit 6c4009
			       + xstate_comp_sizes[i -1]);
Packit 6c4009
			  if ((ecx & (1 << 1)) != 0)
Packit 6c4009
			    xstate_comp_offsets[i]
Packit 6c4009
			      = ALIGN_UP (xstate_comp_offsets[i], 64);
Packit 6c4009
			}
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  /* Use XSAVEC.  */
Packit 6c4009
		  unsigned int size
Packit 6c4009
		    = xstate_comp_offsets[31] + xstate_comp_sizes[31];
Packit 6c4009
		  if (size)
Packit 6c4009
		    {
Packit 6c4009
		      cpu_features->xsave_state_size
Packit 6c4009
			= ALIGN_UP (size + STATE_SAVE_OFFSET, 64);
Packit Service 3b0880
		      cpu_features->feature[index_arch_XSAVEC_Usable]
Packit Service 3b0880
			|= bit_arch_XSAVEC_Usable;
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit Service d34ac2
}
Packit Service d34ac2
Packit 6c4009
static inline void
Packit 6c4009
init_cpu_features (struct cpu_features *cpu_features)
Packit 6c4009
{
Packit 6c4009
  unsigned int ebx, ecx, edx;
Packit 6c4009
  unsigned int family = 0;
Packit 6c4009
  unsigned int model = 0;
Packit 6c4009
  enum cpu_features_kind kind;
Packit 6c4009
Packit 6c4009
#if !HAS_CPUID
Packit 6c4009
  if (__get_cpuid_max (0, 0) == 0)
Packit 6c4009
    {
Packit 6c4009
      kind = arch_kind_other;
Packit 6c4009
      goto no_cpuid;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit Service 3b0880
  __cpuid (0, cpu_features->max_cpuid, ebx, ecx, edx);
Packit 6c4009
Packit 6c4009
  /* This spells out "GenuineIntel".  */
Packit 6c4009
  if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69)
Packit 6c4009
    {
Packit Service 3b0880
      unsigned int extended_model, stepping;
Packit 6c4009
Packit 6c4009
      kind = arch_kind_intel;
Packit 6c4009
Packit Service 3b0880
      get_common_indeces (cpu_features, &family, &model, &extended_model,
Packit 6c4009
			  &stepping);
Packit 6c4009
Packit 6c4009
      get_extended_indices (cpu_features);
Packit 6c4009
Packit 6c4009
      if (family == 0x06)
Packit 6c4009
	{
Packit 6c4009
	  model += extended_model;
Packit 6c4009
	  switch (model)
Packit 6c4009
	    {
Packit 6c4009
	    case 0x1c:
Packit 6c4009
	    case 0x26:
Packit 6c4009
	      /* BSF is slow on Atom.  */
Packit Service 3b0880
	      cpu_features->feature[index_arch_Slow_BSF]
Packit 6c4009
		|= bit_arch_Slow_BSF;
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    case 0x57:
Packit 6c4009
	      /* Knights Landing.  Enable Silvermont optimizations.  */
Packit 6c4009
Packit 6c4009
	    case 0x5c:
Packit 6c4009
	    case 0x5f:
Packit 6c4009
	      /* Unaligned load versions are faster than SSSE3
Packit 6c4009
		 on Goldmont.  */
Packit 6c4009
Packit 6c4009
	    case 0x4c:
Packit 6c4009
	      /* Airmont is a die shrink of Silvermont.  */
Packit 6c4009
Packit 6c4009
	    case 0x37:
Packit 6c4009
	    case 0x4a:
Packit 6c4009
	    case 0x4d:
Packit Service 3b0880
	    case 0x5a:
Packit 6c4009
	    case 0x5d:
Packit 6c4009
	      /* Unaligned load versions are faster than SSSE3
Packit 6c4009
		 on Silvermont.  */
Packit Service 3b0880
#if index_arch_Fast_Unaligned_Load != index_arch_Prefer_PMINUB_for_stringop
Packit Service 3b0880
# error index_arch_Fast_Unaligned_Load != index_arch_Prefer_PMINUB_for_stringop
Packit Service 3b0880
#endif
Packit Service 3b0880
#if index_arch_Fast_Unaligned_Load != index_arch_Slow_SSE4_2
Packit Service 3b0880
# error index_arch_Fast_Unaligned_Load != index_arch_Slow_SSE4_2
Packit Service 3b0880
#endif
Packit Service 3b0880
#if index_arch_Fast_Unaligned_Load != index_arch_Fast_Unaligned_Copy
Packit Service 3b0880
# error index_arch_Fast_Unaligned_Load != index_arch_Fast_Unaligned_Copy
Packit Service 3b0880
#endif
Packit Service 3b0880
	      cpu_features->feature[index_arch_Fast_Unaligned_Load]
Packit 6c4009
		|= (bit_arch_Fast_Unaligned_Load
Packit 6c4009
		    | bit_arch_Fast_Unaligned_Copy
Packit 6c4009
		    | bit_arch_Prefer_PMINUB_for_stringop
Packit 6c4009
		    | bit_arch_Slow_SSE4_2);
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    default:
Packit 6c4009
	      /* Unknown family 0x06 processors.  Assuming this is one
Packit 6c4009
		 of Core i3/i5/i7 processors if AVX is available.  */
Packit 6c4009
	      if (!CPU_FEATURES_CPU_P (cpu_features, AVX))
Packit 6c4009
		break;
Packit 6c4009
Packit 6c4009
	    case 0x1a:
Packit 6c4009
	    case 0x1e:
Packit 6c4009
	    case 0x1f:
Packit 6c4009
	    case 0x25:
Packit 6c4009
	    case 0x2c:
Packit 6c4009
	    case 0x2e:
Packit 6c4009
	    case 0x2f:
Packit 6c4009
	      /* Rep string instructions, unaligned load, unaligned copy,
Packit 6c4009
		 and pminub are fast on Intel Core i3, i5 and i7.  */
Packit Service 3b0880
#if index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Load
Packit Service 3b0880
# error index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Load
Packit Service 3b0880
#endif
Packit Service 3b0880
#if index_arch_Fast_Rep_String != index_arch_Prefer_PMINUB_for_stringop
Packit Service 3b0880
# error index_arch_Fast_Rep_String != index_arch_Prefer_PMINUB_for_stringop
Packit Service 3b0880
#endif
Packit Service 3b0880
#if index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Copy
Packit Service 3b0880
# error index_arch_Fast_Rep_String != index_arch_Fast_Unaligned_Copy
Packit Service 3b0880
#endif
Packit Service 3b0880
	      cpu_features->feature[index_arch_Fast_Rep_String]
Packit 6c4009
		|= (bit_arch_Fast_Rep_String
Packit 6c4009
		    | bit_arch_Fast_Unaligned_Load
Packit 6c4009
		    | bit_arch_Fast_Unaligned_Copy
Packit 6c4009
		    | bit_arch_Prefer_PMINUB_for_stringop);
Packit 6c4009
	      break;
Packit Service c829fc
	    }
Packit 6c4009
Packit Service c829fc
	 /* Disable TSX on some Haswell processors to avoid TSX on kernels that
Packit Service c829fc
	    weren't updated with the latest microcode package (which disables
Packit Service c829fc
	    broken feature by default).  */
Packit Service c829fc
	 switch (model)
Packit Service c829fc
	    {
Packit 6c4009
	    case 0x3f:
Packit 6c4009
	      /* Xeon E7 v3 with stepping >= 4 has working TSX.  */
Packit 6c4009
	      if (stepping >= 4)
Packit 6c4009
		break;
Packit 6c4009
	    case 0x3c:
Packit 6c4009
	    case 0x45:
Packit 6c4009
	    case 0x46:
Packit 6c4009
	      /* Disable Intel TSX on Haswell processors (except Xeon E7 v3
Packit 6c4009
		 with stepping >= 4) to avoid TSX on kernels that weren't
Packit 6c4009
		 updated with the latest microcode package (which disables
Packit 6c4009
		 broken feature by default).  */
Packit Service 3b0880
	      cpu_features->cpuid[index_cpu_RTM].reg_RTM &= ~bit_cpu_RTM;
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
Packit 6c4009
      /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER
Packit 6c4009
         if AVX512ER is available.  Don't use AVX512 to avoid lower CPU
Packit 6c4009
	 frequency if AVX512ER isn't available.  */
Packit 6c4009
      if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER))
Packit Service 3b0880
	cpu_features->feature[index_arch_Prefer_No_VZEROUPPER]
Packit 6c4009
	  |= bit_arch_Prefer_No_VZEROUPPER;
Packit 6c4009
      else
Packit Service 3b0880
	cpu_features->feature[index_arch_Prefer_No_AVX512]
Packit 6c4009
	  |= bit_arch_Prefer_No_AVX512;
Packit 6c4009
    }
Packit 6c4009
  /* This spells out "AuthenticAMD".  */
Packit 6c4009
  else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
Packit 6c4009
    {
Packit Service 3b0880
      unsigned int extended_model, stepping;
Packit 6c4009
Packit 6c4009
      kind = arch_kind_amd;
Packit 6c4009
Packit Service 3b0880
      get_common_indeces (cpu_features, &family, &model, &extended_model,
Packit 6c4009
			  &stepping);
Packit 6c4009
Packit 6c4009
      get_extended_indices (cpu_features);
Packit 6c4009
Packit Service 3b0880
      ecx = cpu_features->cpuid[COMMON_CPUID_INDEX_1].ecx;
Packit 6c4009
Packit Service 3b0880
      if (HAS_ARCH_FEATURE (AVX_Usable))
Packit 6c4009
	{
Packit 6c4009
	  /* Since the FMA4 bit is in COMMON_CPUID_INDEX_80000001 and
Packit 6c4009
	     FMA4 requires AVX, determine if FMA4 is usable here.  */
Packit Service 3b0880
	  if (CPU_FEATURES_CPU_P (cpu_features, FMA4))
Packit Service 3b0880
	    cpu_features->feature[index_arch_FMA4_Usable]
Packit Service 3b0880
	      |= bit_arch_FMA4_Usable;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (family == 0x15)
Packit 6c4009
	{
Packit Service 3b0880
#if index_arch_Fast_Unaligned_Load != index_arch_Fast_Copy_Backward
Packit Service 3b0880
# error index_arch_Fast_Unaligned_Load != index_arch_Fast_Copy_Backward
Packit Service 3b0880
#endif
Packit 6c4009
	  /* "Excavator"   */
Packit 6c4009
	  if (model >= 0x60 && model <= 0x7f)
Packit 6c4009
	  {
Packit Service 3b0880
	    cpu_features->feature[index_arch_Fast_Unaligned_Load]
Packit 6c4009
	      |= (bit_arch_Fast_Unaligned_Load
Packit 6c4009
		  | bit_arch_Fast_Copy_Backward);
Packit 6c4009
Packit 6c4009
	    /* Unaligned AVX loads are slower.*/
Packit Service 3b0880
	    cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load]
Packit Service 3b0880
		  &= ~bit_arch_AVX_Fast_Unaligned_Load;
Packit 6c4009
	  }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      kind = arch_kind_other;
Packit Service 3b0880
      get_common_indeces (cpu_features, NULL, NULL, NULL, NULL);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Support i586 if CX8 is available.  */
Packit 6c4009
  if (CPU_FEATURES_CPU_P (cpu_features, CX8))
Packit Service 3b0880
    cpu_features->feature[index_arch_I586] |= bit_arch_I586;
Packit 6c4009
Packit 6c4009
  /* Support i686 if CMOV is available.  */
Packit 6c4009
  if (CPU_FEATURES_CPU_P (cpu_features, CMOV))
Packit Service 3b0880
    cpu_features->feature[index_arch_I686] |= bit_arch_I686;
Packit 6c4009
Packit 6c4009
#if !HAS_CPUID
Packit 6c4009
no_cpuid:
Packit 6c4009
#endif
Packit 6c4009
Packit Service 3b0880
  cpu_features->family = family;
Packit Service 3b0880
  cpu_features->model = model;
Packit Service 3b0880
  cpu_features->kind = kind;
Packit 6c4009
Packit 6c4009
#if HAVE_TUNABLES
Packit 6c4009
  TUNABLE_GET (hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps));
Packit 6c4009
  cpu_features->non_temporal_threshold
Packit 6c4009
    = TUNABLE_GET (x86_non_temporal_threshold, long int, NULL);
Packit 6c4009
  cpu_features->data_cache_size
Packit 6c4009
    = TUNABLE_GET (x86_data_cache_size, long int, NULL);
Packit 6c4009
  cpu_features->shared_cache_size
Packit 6c4009
    = TUNABLE_GET (x86_shared_cache_size, long int, NULL);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Reuse dl_platform, dl_hwcap and dl_hwcap_mask for x86.  */
Packit 6c4009
#if !HAVE_TUNABLES && defined SHARED
Packit Service 3b0880
  /* The glibc.tune.hwcap_mask tunable is initialized already, so no need to do
Packit 6c4009
     this.  */
Packit 6c4009
  GLRO(dl_hwcap_mask) = HWCAP_IMPORTANT;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef __x86_64__
Packit 6c4009
  GLRO(dl_hwcap) = HWCAP_X86_64;
Packit Service 3b0880
  if (cpu_features->kind == arch_kind_intel)
Packit 6c4009
    {
Packit 6c4009
      const char *platform = NULL;
Packit 6c4009
Packit Service 3b0880
      if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable)
Packit Service 3b0880
	  && CPU_FEATURES_CPU_P (cpu_features, AVX512CD))
Packit 6c4009
	{
Packit Service 3b0880
	  if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER))
Packit 6c4009
	    {
Packit Service 3b0880
	      if (CPU_FEATURES_CPU_P (cpu_features, AVX512PF))
Packit 6c4009
		platform = "xeon_phi";
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit Service 3b0880
	      if (CPU_FEATURES_CPU_P (cpu_features, AVX512BW)
Packit Service 3b0880
		  && CPU_FEATURES_CPU_P (cpu_features, AVX512DQ)
Packit Service 3b0880
		  && CPU_FEATURES_CPU_P (cpu_features, AVX512VL))
Packit 6c4009
		GLRO(dl_hwcap) |= HWCAP_X86_AVX512_1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (platform == NULL
Packit Service 3b0880
	  && CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)
Packit Service 3b0880
	  && CPU_FEATURES_ARCH_P (cpu_features, FMA_Usable)
Packit Service 3b0880
	  && CPU_FEATURES_CPU_P (cpu_features, BMI1)
Packit Service 3b0880
	  && CPU_FEATURES_CPU_P (cpu_features, BMI2)
Packit Service 3b0880
	  && CPU_FEATURES_CPU_P (cpu_features, LZCNT)
Packit Service 3b0880
	  && CPU_FEATURES_CPU_P (cpu_features, MOVBE)
Packit Service 3b0880
	  && CPU_FEATURES_CPU_P (cpu_features, POPCNT))
Packit 6c4009
	platform = "haswell";
Packit 6c4009
Packit 6c4009
      if (platform != NULL)
Packit 6c4009
	GLRO(dl_platform) = platform;
Packit 6c4009
    }
Packit 6c4009
#else
Packit 6c4009
  GLRO(dl_hwcap) = 0;
Packit Service 3b0880
  if (CPU_FEATURES_CPU_P (cpu_features, SSE2))
Packit 6c4009
    GLRO(dl_hwcap) |= HWCAP_X86_SSE2;
Packit 6c4009
Packit 6c4009
  if (CPU_FEATURES_ARCH_P (cpu_features, I686))
Packit 6c4009
    GLRO(dl_platform) = "i686";
Packit 6c4009
  else if (CPU_FEATURES_ARCH_P (cpu_features, I586))
Packit 6c4009
    GLRO(dl_platform) = "i586";
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#if CET_ENABLED
Packit 6c4009
# if HAVE_TUNABLES
Packit 6c4009
  TUNABLE_GET (x86_ibt, tunable_val_t *,
Packit 6c4009
	       TUNABLE_CALLBACK (set_x86_ibt));
Packit 6c4009
  TUNABLE_GET (x86_shstk, tunable_val_t *,
Packit 6c4009
	       TUNABLE_CALLBACK (set_x86_shstk));
Packit 6c4009
# endif
Packit 6c4009
Packit 6c4009
  /* Check CET status.  */
Packit 6c4009
  unsigned int cet_status = get_cet_status ();
Packit 6c4009
Packit 6c4009
  if (cet_status)
Packit 6c4009
    {
Packit Service 3b0880
      GL(dl_x86_feature_1)[0] = cet_status;
Packit 6c4009
Packit 6c4009
# ifndef SHARED
Packit 6c4009
      /* Check if IBT and SHSTK are enabled by kernel.  */
Packit 6c4009
      if ((cet_status & GNU_PROPERTY_X86_FEATURE_1_IBT)
Packit 6c4009
	  || (cet_status & GNU_PROPERTY_X86_FEATURE_1_SHSTK))
Packit 6c4009
	{
Packit 6c4009
	  /* Disable IBT and/or SHSTK if they are enabled by kernel, but
Packit 6c4009
	     disabled by environment variable:
Packit 6c4009
Packit Service 3b0880
	     GLIBC_TUNABLES=glibc.tune.hwcaps=-IBT,-SHSTK
Packit 6c4009
	   */
Packit 6c4009
	  unsigned int cet_feature = 0;
Packit Service 2049ea
	  if (!HAS_CPU_FEATURE (IBT))
Packit 6c4009
	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_IBT;
Packit Service 2049ea
	  if (!HAS_CPU_FEATURE (SHSTK))
Packit 6c4009
	    cet_feature |= GNU_PROPERTY_X86_FEATURE_1_SHSTK;
Packit 6c4009
Packit 6c4009
	  if (cet_feature)
Packit 6c4009
	    {
Packit 6c4009
	      int res = dl_cet_disable_cet (cet_feature);
Packit 6c4009
Packit 6c4009
	      /* Clear the disabled bits in dl_x86_feature_1.  */
Packit 6c4009
	      if (res == 0)
Packit Service 3b0880
		GL(dl_x86_feature_1)[0] &= ~cet_feature;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Lock CET if IBT or SHSTK is enabled in executable.  Don't
Packit Service 3b0880
	     lock CET if SHSTK is enabled permissively.  */
Packit Service 3b0880
	  if (((GL(dl_x86_feature_1)[1] >> CET_MAX)
Packit Service 3b0880
	       & ((1 << CET_MAX) - 1))
Packit Service 3b0880
	       != CET_PERMISSIVE)
Packit 6c4009
	    dl_cet_lock_cet ();
Packit 6c4009
	}
Packit 6c4009
# endif
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
}