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