1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #pragma once
8 
9 #include <assert.h>
10 #include <zircon/compiler.h>
11 #include <stdint.h>
12 #include <arch/x86.h>
13 
14 __BEGIN_CDECLS
15 
16 #define MAX_SUPPORTED_CPUID     (0x17)
17 #define MAX_SUPPORTED_CPUID_HYP (0x40000001)
18 #define MAX_SUPPORTED_CPUID_EXT (0x8000001e)
19 
20 struct cpuid_leaf {
21     uint32_t a;
22     uint32_t b;
23     uint32_t c;
24     uint32_t d;
25 };
26 
27 enum x86_cpuid_leaf_num {
28     X86_CPUID_BASE = 0,
29     X86_CPUID_MODEL_FEATURES = 0x1,
30     X86_CPUID_CACHE_V1 = 0x2,
31     X86_CPUID_CACHE_V2 = 0x4,
32     X86_CPUID_MON = 0x5,
33     X86_CPUID_THERMAL_AND_POWER = 0x6,
34     X86_CPUID_EXTENDED_FEATURE_FLAGS = 0x7,
35     X86_CPUID_PERFORMANCE_MONITORING = 0xa,
36     X86_CPUID_TOPOLOGY = 0xb,
37     X86_CPUID_XSAVE = 0xd,
38     X86_CPUID_PT = 0x14,
39     X86_CPUID_TSC = 0x15,
40 
41     X86_CPUID_HYP_BASE = 0x40000000,
42     X86_CPUID_HYP_VENDOR = 0x40000000,
43     X86_CPUID_KVM_FEATURES = 0x40000001,
44 
45     X86_CPUID_EXT_BASE = 0x80000000,
46     X86_CPUID_BRAND = 0x80000002,
47     X86_CPUID_ADDR_WIDTH = 0x80000008,
48     X86_CPUID_AMD_TOPOLOGY = 0x8000001e,
49 };
50 
51 struct x86_cpuid_bit {
52     enum x86_cpuid_leaf_num leaf_num;
53     uint8_t word;
54     uint8_t bit;
55 };
56 
57 #define X86_CPUID_BIT(leaf, word, bit) \
58         (struct x86_cpuid_bit){(enum x86_cpuid_leaf_num)(leaf), (word), (bit)}
59 
60 void x86_feature_init(void);
61 
x86_get_cpuid_leaf(enum x86_cpuid_leaf_num leaf)62 static inline const struct cpuid_leaf *x86_get_cpuid_leaf(enum x86_cpuid_leaf_num leaf)
63 {
64     extern struct cpuid_leaf _cpuid[MAX_SUPPORTED_CPUID + 1];
65     extern struct cpuid_leaf _cpuid_hyp[MAX_SUPPORTED_CPUID_HYP - X86_CPUID_HYP_BASE + 1];
66     extern struct cpuid_leaf _cpuid_ext[MAX_SUPPORTED_CPUID_EXT - X86_CPUID_EXT_BASE + 1];
67     extern uint32_t max_cpuid;
68     extern uint32_t max_ext_cpuid;
69     extern uint32_t max_hyp_cpuid;
70 
71     if (leaf < X86_CPUID_HYP_BASE) {
72         if (unlikely(leaf > max_cpuid))
73             return NULL;
74 
75         return &_cpuid[leaf];
76     } else if (leaf < X86_CPUID_EXT_BASE) {
77         if (unlikely(leaf > max_hyp_cpuid))
78             return NULL;
79 
80         return &_cpuid_hyp[(uint32_t)leaf - (uint32_t)X86_CPUID_HYP_BASE];
81     } else {
82         if (unlikely(leaf > max_ext_cpuid))
83             return NULL;
84 
85         return &_cpuid_ext[(uint32_t)leaf - (uint32_t)X86_CPUID_EXT_BASE];
86     }
87 }
88 /* Retrieve the specified subleaf.  This function is not cached.
89  * Returns false if leaf num is invalid */
90 bool x86_get_cpuid_subleaf(
91         enum x86_cpuid_leaf_num, uint32_t, struct cpuid_leaf *);
92 
x86_feature_test(struct x86_cpuid_bit bit)93 static inline bool x86_feature_test(struct x86_cpuid_bit bit)
94 {
95     DEBUG_ASSERT (bit.word <= 3 && bit.bit <= 31);
96 
97     if (bit.word > 3 || bit.bit > 31)
98         return false;
99 
100     const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(bit.leaf_num);
101     if (!leaf)
102         return false;
103 
104     switch (bit.word) {
105         case 0: return !!((1u << bit.bit) & leaf->a);
106         case 1: return !!((1u << bit.bit) & leaf->b);
107         case 2: return !!((1u << bit.bit) & leaf->c);
108         case 3: return !!((1u << bit.bit) & leaf->d);
109         default: return false;
110     }
111 }
112 
113 void x86_feature_debug(void);
114 
115 /* add feature bits to test here */
116 /* format: X86_CPUID_BIT(cpuid leaf, register (eax-edx:0-3), bit) */
117 #define X86_FEATURE_SSE3                X86_CPUID_BIT(0x1, 2, 0)
118 #define X86_FEATURE_MON                 X86_CPUID_BIT(0x1, 2, 3)
119 #define X86_FEATURE_VMX                 X86_CPUID_BIT(0x1, 2, 5)
120 #define X86_FEATURE_TM2                 X86_CPUID_BIT(0x1, 2, 8)
121 #define X86_FEATURE_SSSE3               X86_CPUID_BIT(0x1, 2, 9)
122 #define X86_FEATURE_PDCM                X86_CPUID_BIT(0x1, 2, 15)
123 #define X86_FEATURE_PCID                X86_CPUID_BIT(0x1, 2, 17)
124 #define X86_FEATURE_SSE4_1              X86_CPUID_BIT(0x1, 2, 19)
125 #define X86_FEATURE_SSE4_2              X86_CPUID_BIT(0x1, 2, 20)
126 #define X86_FEATURE_X2APIC              X86_CPUID_BIT(0x1, 2, 21)
127 #define X86_FEATURE_TSC_DEADLINE        X86_CPUID_BIT(0x1, 2, 24)
128 #define X86_FEATURE_AESNI               X86_CPUID_BIT(0x1, 2, 25)
129 #define X86_FEATURE_XSAVE               X86_CPUID_BIT(0x1, 2, 26)
130 #define X86_FEATURE_AVX                 X86_CPUID_BIT(0x1, 2, 28)
131 #define X86_FEATURE_RDRAND              X86_CPUID_BIT(0x1, 2, 30)
132 #define X86_FEATURE_HYPERVISOR          X86_CPUID_BIT(0x1, 2, 31)
133 #define X86_FEATURE_FPU                 X86_CPUID_BIT(0x1, 3, 0)
134 #define X86_FEATURE_SEP                 X86_CPUID_BIT(0x1, 3, 11)
135 #define X86_FEATURE_CLFLUSH             X86_CPUID_BIT(0x1, 3, 19)
136 #define X86_FEATURE_ACPI                X86_CPUID_BIT(0x1, 3, 22)
137 #define X86_FEATURE_MMX                 X86_CPUID_BIT(0x1, 3, 23)
138 #define X86_FEATURE_FXSR                X86_CPUID_BIT(0x1, 3, 24)
139 #define X86_FEATURE_SSE                 X86_CPUID_BIT(0x1, 3, 25)
140 #define X86_FEATURE_SSE2                X86_CPUID_BIT(0x1, 3, 26)
141 #define X86_FEATURE_TM                  X86_CPUID_BIT(0x1, 3, 29)
142 #define X86_FEATURE_DTS                 X86_CPUID_BIT(0x6, 0, 0)
143 #define X86_FEATURE_PLN                 X86_CPUID_BIT(0x6, 0, 4)
144 #define X86_FEATURE_PTM                 X86_CPUID_BIT(0x6, 0, 6)
145 #define X86_FEATURE_HWP                 X86_CPUID_BIT(0x6, 0, 7)
146 #define X86_FEATURE_HWP_NOT             X86_CPUID_BIT(0x6, 0, 8)
147 #define X86_FEATURE_HWP_ACT             X86_CPUID_BIT(0x6, 0, 9)
148 #define X86_FEATURE_HWP_PREF            X86_CPUID_BIT(0x6, 0, 10)
149 #define X86_FEATURE_HW_FEEDBACK         X86_CPUID_BIT(0x6, 2, 0)
150 #define X86_FEATURE_PERF_BIAS           X86_CPUID_BIT(0x6, 2, 3)
151 #define X86_FEATURE_FSGSBASE            X86_CPUID_BIT(0x7, 1, 0)
152 #define X86_FEATURE_TSC_ADJUST          X86_CPUID_BIT(0x7, 1, 1)
153 #define X86_FEATURE_AVX2                X86_CPUID_BIT(0x7, 1, 5)
154 #define X86_FEATURE_SMEP                X86_CPUID_BIT(0x7, 1, 7)
155 #define X86_FEATURE_ERMS                X86_CPUID_BIT(0x7, 1, 9)
156 #define X86_FEATURE_INVPCID             X86_CPUID_BIT(0x7, 1, 10)
157 #define X86_FEATURE_RDSEED              X86_CPUID_BIT(0x7, 1, 18)
158 #define X86_FEATURE_SMAP                X86_CPUID_BIT(0x7, 1, 20)
159 #define X86_FEATURE_CLFLUSHOPT          X86_CPUID_BIT(0x7, 1, 23)
160 #define X86_FEATURE_CLWB                X86_CPUID_BIT(0x7, 1, 24)
161 #define X86_FEATURE_PT                  X86_CPUID_BIT(0x7, 1, 25)
162 #define X86_FEATURE_UMIP                X86_CPUID_BIT(0x7, 2, 2)
163 #define X86_FEATURE_PKU                 X86_CPUID_BIT(0x7, 2, 3)
164 #define X86_FEATURE_IBRS_IBPB           X86_CPUID_BIT(0x7, 3, 26)
165 #define X86_FEATURE_STIBP               X86_CPUID_BIT(0x7, 3, 27)
166 #define X86_FEATURE_SSBD                X86_CPUID_BIT(0x7, 3, 31)
167 
168 #define X86_FEATURE_KVM_PVCLOCK_STABLE  X86_CPUID_BIT(0x40000001, 0, 24)
169 #define X86_FEATURE_AMD_TOPO            X86_CPUID_BIT(0x80000001, 2, 22)
170 #define X86_FEATURE_SYSCALL             X86_CPUID_BIT(0x80000001, 3, 11)
171 #define X86_FEATURE_NX                  X86_CPUID_BIT(0x80000001, 3, 20)
172 #define X86_FEATURE_HUGE_PAGE           X86_CPUID_BIT(0x80000001, 3, 26)
173 #define X86_FEATURE_RDTSCP              X86_CPUID_BIT(0x80000001, 3, 27)
174 #define X86_FEATURE_INVAR_TSC           X86_CPUID_BIT(0x80000007, 3, 8)
175 
176 /* legacy accessors */
x86_linear_address_width(void)177 static inline uint8_t x86_linear_address_width(void)
178 {
179     const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(X86_CPUID_ADDR_WIDTH);
180     if (!leaf)
181         return 0;
182 
183     /*
184      Extracting bit 15:8 from eax register
185      Bits 15-08: #Linear Address Bits
186     */
187     return (leaf->a >> 8) & 0xff;
188 }
189 
x86_physical_address_width(void)190 static inline uint8_t x86_physical_address_width(void)
191 {
192     const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(X86_CPUID_ADDR_WIDTH);
193     if (!leaf)
194         return 0;
195 
196     /*
197      Extracting bit 7:0 from eax register
198      Bits 07-00: #Physical Address Bits
199     */
200     return leaf->a & 0xff;
201 }
202 
x86_get_clflush_line_size(void)203 static inline uint32_t x86_get_clflush_line_size(void)
204 {
205     const struct cpuid_leaf *leaf = x86_get_cpuid_leaf(X86_CPUID_MODEL_FEATURES);
206     if (!leaf)
207         return 0;
208 
209     /*
210      Extracting bit 15:8 from ebx register
211      Bits 15-08: #CLFLUSH line size in quadwords
212     */
213     return ((leaf->b >> 8) & 0xff) * 8u;
214 }
215 
216 /* cpu vendors */
217 enum x86_vendor_list {
218     X86_VENDOR_UNKNOWN,
219     X86_VENDOR_INTEL,
220     X86_VENDOR_AMD
221 };
222 
223 extern enum x86_vendor_list x86_vendor;
224 
225 /* topology */
226 
227 #define X86_TOPOLOGY_INVALID 0
228 #define X86_TOPOLOGY_SMT 1
229 #define X86_TOPOLOGY_CORE 2
230 
231 struct x86_topology_level {
232     /* The number of bits to right shift to identify the next-higher topological
233      * level */
234     uint8_t right_shift;
235     /* The type of relationship this level describes (hyperthread/core/etc) */
236     uint8_t type;
237 };
238 
239 /**
240  * @brief Fetch the topology information for the given level.
241  *
242  * This interface is uncached.
243  *
244  * @param level The level to retrieve info for.  Should initially be 0 and
245  * incremented with each call.
246  * @param info The structure to populate with the discovered information
247  *
248  * @return true if the requested level existed (and there may be higher levels).
249  * @return false if the requested level does not exist (and no higher ones do).
250  */
251 bool x86_topology_enumerate(uint8_t level, struct x86_topology_level *info);
252 
253 struct x86_model_info {
254     uint8_t processor_type;
255     uint8_t family;
256     uint8_t model;
257     uint8_t stepping;
258 
259     uint32_t display_family;
260     uint32_t display_model;
261 };
262 
263 const struct x86_model_info * x86_get_model(void);
264 
265 enum x86_microarch_list {
266     X86_MICROARCH_UNKNOWN,
267     X86_MICROARCH_INTEL_NEHALEM,
268     X86_MICROARCH_INTEL_WESTMERE,
269     X86_MICROARCH_INTEL_SANDY_BRIDGE,
270     X86_MICROARCH_INTEL_IVY_BRIDGE,
271     X86_MICROARCH_INTEL_BROADWELL,
272     X86_MICROARCH_INTEL_HASWELL,
273     X86_MICROARCH_INTEL_SKYLAKE,
274     X86_MICROARCH_INTEL_KABYLAKE,
275     X86_MICROARCH_INTEL_SILVERMONT,
276     X86_MICROARCH_AMD_BULLDOZER,
277     X86_MICROARCH_AMD_JAGUAR,
278     X86_MICROARCH_AMD_ZEN,
279 };
280 extern enum x86_microarch_list x86_microarch;
281 
282 extern bool g_x86_feature_fsgsbase;
283 
284 enum x86_hypervisor_list {
285     X86_HYPERVISOR_UNKNOWN,
286     X86_HYPERVISOR_KVM,
287 };
288 
289 extern enum x86_hypervisor_list x86_hypervisor;
290 
291 /* returns 0 if unknown, otherwise value in Hz */
292 typedef uint64_t (*x86_get_timer_freq_func_t)(void);
293 
294 /* attempt to reboot the system; may fail and simply return */
295 typedef void (*x86_reboot_system_func_t)(void);
296 
297 /* Structure for supporting per-microarchitecture kernel configuration */
298 typedef struct {
299     x86_get_timer_freq_func_t get_apic_freq;
300     x86_get_timer_freq_func_t get_tsc_freq;
301     x86_reboot_system_func_t reboot_system;
302 
303     bool disable_c1e;
304 } x86_microarch_config_t;
305 
x86_get_microarch_config(void)306 static inline const x86_microarch_config_t* x86_get_microarch_config(void) {
307     extern const x86_microarch_config_t* x86_microarch_config;
308     return x86_microarch_config;
309 }
310 
311 __END_CDECLS
312