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, ®s); 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, ®s); 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 }