/ src / cpu_features.c
cpu_features.c
  1  /*
  2   * Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without modification,
  5   * are permitted provided that the following conditions are met:
  6   * 1. Redistributions of source code must retain the above copyright notice,
  7   *    this list of conditions and the following disclaimer.
  8   * 2. Redistributions in binary form must reproduce the above copyright notice,
  9   *    this list of conditions and the following disclaimer in the documentation
 10   *    and/or other materials provided with the distribution.
 11   * 3. Neither the name of the copyright holder nor the names of its contributors
 12   *    may be used to endorse or promote products derived from this software without
 13   *    specific prior written permission.
 14   *
 15   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 16   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 17   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 18   * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 19   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 20   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 21   * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 22   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 24   * POSSIBILITY OF SUCH DAMAGE.
 25   *
 26   */
 27  
 28  #include <assert.h>
 29  #include <stdio.h>
 30  #include <stdlib.h>
 31  #include <string.h>                     /* for memcpy */
 32  
 33  #include <libm/cpu_features.h>
 34  #include <libm/compiler.h>
 35  #include <libm/iface.h>
 36  
 37  struct cpu_features cpu_features HIDDEN;
 38  
 39  struct {
 40      uint32_t eax;
 41      uint32_t ecx;
 42  } __cpuid_values[CPUID_MAX] = {
 43      [CPUID_EAX_1] = {0x1, 0x0},                         /* eax = 0, ecx=0 */
 44      [CPUID_EAX_7] = {0x7, 0x0},                         /* eax = 7,  -"- */
 45      [CPUID_EAX_8_01] = {0x80000001, 0x0},               /* eax = 0x80000001 */
 46      [CPUID_EAX_8_07] = {0x80000007, 0x0},               /* eax = 0x80000007 */
 47      [CPUID_EAX_8_08] = {0x80000008, 0x0},               /* eax = 0x80000008 */
 48  };
 49  
 50  static void
 51  __get_mfg_info(struct cpuid_regs *regs, struct cpu_mfg_info *mfg_info)
 52  {
 53      uint32_t ext_model;
 54  
 55      if (mfg_info) {
 56          struct cpuid_regs regs;
 57          uint32_t eax;
 58  
 59          __cpuid_1(1, &regs);
 60          eax = regs.eax;
 61  
 62          mfg_info->family = (eax >> 8) & 0x0f;
 63          mfg_info->model = (eax >> 4) & 0x0f;
 64          ext_model = (eax >> 12) & 0xf0;
 65          if (mfg_info->family == 0x0f) {
 66              mfg_info->family += (eax >> 20) & 0xff;
 67              mfg_info->model += ext_model;
 68          }
 69  
 70          mfg_info->stepping = eax & 0x0f;
 71      }
 72  }
 73  
 74  #ifndef ARRAY_SIZE
 75  #define ARRAY_SIZE(x) (sizeof(x)/ sizeof(x[0]))
 76  #endif
 77  
 78  #define INITIALIZED_MAGIC 0xdeadbeaf
 79  
 80  static void
 81  __init_cpu_features(void)
 82  {
 83      static unsigned initialized = 0;
 84  
 85      struct cpu_mfg_info *mfg_info = &cpu_features.cpu_mfg_info;
 86      int arr_size = ARRAY_SIZE(__cpuid_values);
 87      //assert(arr_size <= CPUID_MAX);
 88  
 89      if (initialized == INITIALIZED_MAGIC)
 90          return;
 91  
 92      struct cpuid_regs regs;
 93      __cpuid_1(0, &regs);
 94  
 95      /* "AuthenticAMD" */
 96      if (regs.ebx == 0x68747541 && regs.ecx == 0x444d4163 &&
 97          regs.edx == 0x69746e65) {
 98          cpu_features.cpu_mfg_info.mfg_type = CPU_MFG_AMD;
 99      }
100  
101      for (int i = 0; i < arr_size; i++) {
102          struct cpuid_regs ft;
103  
104          __cpuid_2(__cpuid_values[i].eax, __cpuid_values[i].ecx, &ft);
105  
106          cpu_features.available[i].eax = ft.eax;
107          cpu_features.available[i].ebx = ft.ebx;
108          cpu_features.available[i].ecx = ft.ecx;
109          cpu_features.available[i].edx = ft.edx;
110      }
111  
112      __get_mfg_info(&cpu_features.available[CPUID_EAX_1], mfg_info);
113  
114      /*
115       * Globally disable some *_USEABLE flags, so that all ifunc's
116       * sees them
117       */
118      if (mfg_info->mfg_type == CPU_MFG_AMD) {
119          memcpy(&cpu_features.usable[0], &cpu_features.available[0],
120                 sizeof(cpu_features.usable));
121  
122          switch(mfg_info->family) {
123          case 0x15:                      /* Naples */
124              break;
125          case 0x17:                      /* Rome */
126              break;
127          case 0x19:                      /* Milan */
128              break;
129          }
130      }
131  
132      initialized = INITIALIZED_MAGIC;
133  }
134  
135  static void CONSTRUCTOR
136  libm_init_cpu(void)
137  {
138      __init_cpu_features();
139  }
140  
141  struct cpu_features *
142  libm_cpu_get_features(void)
143  {
144      __init_cpu_features();
145  
146      return &cpu_features;
147  }
148  
149  int
150  libm_cpu_feature_is_avx_usable(void)
151  {
152      __init_cpu_features();
153  
154      return CPU_FEATURE_AVX_USABLE(&cpu_features);
155  }
156  
157  int
158  libm_cpu_feature_is_avx2_usable(void)
159  {
160      __init_cpu_features();
161  
162      return CPU_FEATURE_AVX2_USABLE(&cpu_features);
163  }