1/*
2 * Copyright (c) 2015-2017, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "cpuid_flags.h"
30#include "cpuid_inline.h"
31#include "ue2common.h"
32#include "hs_compile.h" // for HS_MODE_ flags
33#include "hs_internal.h"
34#include "util/arch.h"
35
36#if !defined(_WIN32) && !defined(CPUID_H_)
37#include <cpuid.h>
38#endif
39
40u64a cpuid_flags(void) {
41 u64a cap = 0;
42
43 if (check_avx2()) {
44 DEBUG_PRINTF("AVX2 enabled\n");
45 cap |= HS_CPU_FEATURES_AVX2;
46 }
47
48 if (check_avx512()) {
49 DEBUG_PRINTF("AVX512 enabled\n");
50 cap |= HS_CPU_FEATURES_AVX512;
51 }
52
53#if !defined(FAT_RUNTIME) && !defined(HAVE_AVX2)
54 cap &= ~HS_CPU_FEATURES_AVX2;
55#endif
56
57#if (!defined(FAT_RUNTIME) && !defined(HAVE_AVX512)) || \
58 (defined(FAT_RUNTIME) && !defined(BUILD_AVX512))
59 cap &= ~HS_CPU_FEATURES_AVX512;
60#endif
61
62 return cap;
63}
64
65struct family_id {
66 u32 full_family;
67 u32 full_model;
68 u32 tune;
69};
70
71/* from table 35-1 of the Intel 64 and IA32 Arch. Software Developer's Manual
72 * and "Intel Architecture and Processor Identification With CPUID Model and
73 * Family Numbers" */
74static const struct family_id known_microarch[] = {
75 { 0x6, 0x37, HS_TUNE_FAMILY_SLM }, /* baytrail */
76 { 0x6, 0x4A, HS_TUNE_FAMILY_SLM }, /* silvermont */
77 { 0x6, 0x4C, HS_TUNE_FAMILY_SLM }, /* silvermont */
78 { 0x6, 0x4D, HS_TUNE_FAMILY_SLM }, /* avoton, rangley */
79 { 0x6, 0x5A, HS_TUNE_FAMILY_SLM }, /* silvermont */
80 { 0x6, 0x5D, HS_TUNE_FAMILY_SLM }, /* silvermont */
81
82 { 0x6, 0x5C, HS_TUNE_FAMILY_GLM }, /* goldmont */
83 { 0x6, 0x5F, HS_TUNE_FAMILY_GLM }, /* denverton */
84
85 { 0x6, 0x3C, HS_TUNE_FAMILY_HSW }, /* haswell */
86 { 0x6, 0x45, HS_TUNE_FAMILY_HSW }, /* haswell */
87 { 0x6, 0x46, HS_TUNE_FAMILY_HSW }, /* haswell */
88 { 0x6, 0x3F, HS_TUNE_FAMILY_HSW }, /* haswell Xeon */
89
90 { 0x6, 0x3E, HS_TUNE_FAMILY_IVB }, /* ivybridge Xeon */
91 { 0x6, 0x3A, HS_TUNE_FAMILY_IVB }, /* ivybridge */
92
93 { 0x6, 0x2A, HS_TUNE_FAMILY_SNB }, /* sandybridge */
94 { 0x6, 0x2D, HS_TUNE_FAMILY_SNB }, /* sandybridge Xeon */
95
96 { 0x6, 0x3D, HS_TUNE_FAMILY_BDW }, /* broadwell Core-M */
97 { 0x6, 0x47, HS_TUNE_FAMILY_BDW }, /* broadwell */
98 { 0x6, 0x4F, HS_TUNE_FAMILY_BDW }, /* broadwell xeon */
99 { 0x6, 0x56, HS_TUNE_FAMILY_BDW }, /* broadwell xeon-d */
100
101 { 0x6, 0x4E, HS_TUNE_FAMILY_SKL }, /* Skylake Mobile */
102 { 0x6, 0x5E, HS_TUNE_FAMILY_SKL }, /* Skylake Core/E3 Xeon */
103 { 0x6, 0x55, HS_TUNE_FAMILY_SKX }, /* Skylake Xeon */
104
105 { 0x6, 0x8E, HS_TUNE_FAMILY_SKL }, /* Kabylake Mobile */
106 { 0x6, 0x9E, HS_TUNE_FAMILY_SKL }, /* Kabylake desktop */
107
108};
109
110#ifdef DUMP_SUPPORT
111static UNUSED
112const char *dumpTune(u32 tune) {
113#define T_CASE(x) case x: return #x;
114 switch (tune) {
115 T_CASE(HS_TUNE_FAMILY_SLM);
116 T_CASE(HS_TUNE_FAMILY_GLM);
117 T_CASE(HS_TUNE_FAMILY_HSW);
118 T_CASE(HS_TUNE_FAMILY_SNB);
119 T_CASE(HS_TUNE_FAMILY_IVB);
120 T_CASE(HS_TUNE_FAMILY_BDW);
121 T_CASE(HS_TUNE_FAMILY_SKL);
122 T_CASE(HS_TUNE_FAMILY_SKX);
123 }
124#undef T_CASE
125 return "unknown";
126}
127#endif
128
129u32 cpuid_tune(void) {
130 unsigned int eax, ebx, ecx, edx;
131
132 cpuid(1, 0, &eax, &ebx, &ecx, &edx);
133
134 u32 family = (eax >> 8) & 0xf;
135 u32 model = 0;
136
137 if (family == 0x6 || family == 0xf) {
138 model = ((eax >> 4) & 0xf) | ((eax >> 12) & 0xf0);
139 } else {
140 model = (eax >> 4) & 0xf;
141 }
142
143 DEBUG_PRINTF("family = %xh model = %xh\n", family, model);
144 for (u32 i = 0; i < ARRAY_LENGTH(known_microarch); i++) {
145 if (family != known_microarch[i].full_family) {
146 continue;
147 }
148
149 if (model != known_microarch[i].full_model) {
150 continue;
151 }
152
153 u32 tune = known_microarch[i].tune;
154 DEBUG_PRINTF("found tune flag %s\n", dumpTune(tune) );
155 return tune;
156 }
157
158 return HS_TUNE_FAMILY_GENERIC;
159}
160