1 /* Common data structures and functions consumed by hypervisor and toolstack */
2 #ifndef XEN_LIB_X86_CPUID_H
3 #define XEN_LIB_X86_CPUID_H
4
5 #include <xen/lib/x86/cpuid-autogen.h>
6
7 #define FEATURESET_1d 0 /* 0x00000001.edx */
8 #define FEATURESET_1c 1 /* 0x00000001.ecx */
9 #define FEATURESET_e1d 2 /* 0x80000001.edx */
10 #define FEATURESET_e1c 3 /* 0x80000001.ecx */
11 #define FEATURESET_Da1 4 /* 0x0000000d:1.eax */
12 #define FEATURESET_7b0 5 /* 0x00000007:0.ebx */
13 #define FEATURESET_7c0 6 /* 0x00000007:0.ecx */
14 #define FEATURESET_e7d 7 /* 0x80000007.edx */
15 #define FEATURESET_e8b 8 /* 0x80000008.ebx */
16 #define FEATURESET_7d0 9 /* 0x00000007:0.edx */
17 #define FEATURESET_7a1 10 /* 0x00000007:1.eax */
18
19 struct cpuid_leaf
20 {
21 uint32_t a, b, c, d;
22 };
23
24 /*
25 * Versions of GCC before 5 unconditionally reserve %rBX as the PIC hard
26 * register, and are unable to cope with spilling it. This results in a
27 * rather cryptic error:
28 * error: inconsistent operand constraints in an ‘asm’
29 *
30 * In affected situations, work around the issue by using a separate register
31 * to hold the the %rBX output, and xchg twice to leave %rBX preserved around
32 * the asm() statement.
33 */
34 #if defined(__PIC__) && __GNUC__ < 5 && !defined(__clang__) && defined(__i386__)
35 # define XCHG_BX "xchg %%ebx, %[bx];"
36 # define BX_CON [bx] "=&r"
37 #elif defined(__PIC__) && __GNUC__ < 5 && !defined(__clang__) && \
38 defined(__x86_64__) && (defined(__code_model_medium__) || \
39 defined(__code_model_large__))
40 # define XCHG_BX "xchg %%rbx, %q[bx];"
41 # define BX_CON [bx] "=&r"
42 #else
43 # define XCHG_BX ""
44 # define BX_CON "=&b"
45 #endif
46
cpuid_leaf(uint32_t leaf,struct cpuid_leaf * l)47 static inline void cpuid_leaf(uint32_t leaf, struct cpuid_leaf *l)
48 {
49 asm ( XCHG_BX
50 "cpuid;"
51 XCHG_BX
52 : "=a" (l->a), BX_CON (l->b), "=&c" (l->c), "=&d" (l->d)
53 : "a" (leaf) );
54 }
55
cpuid_count_leaf(uint32_t leaf,uint32_t subleaf,struct cpuid_leaf * l)56 static inline void cpuid_count_leaf(
57 uint32_t leaf, uint32_t subleaf, struct cpuid_leaf *l)
58 {
59 asm ( XCHG_BX
60 "cpuid;"
61 XCHG_BX
62 : "=a" (l->a), BX_CON (l->b), "=c" (l->c), "=&d" (l->d)
63 : "a" (leaf), "c" (subleaf) );
64 }
65
66 #undef BX_CON
67 #undef XCHG
68
69 /**
70 * Given the vendor id from CPUID leaf 0, look up Xen's internal integer
71 * vendor ID. Returns X86_VENDOR_UNKNOWN for any unknown vendor.
72 */
73 unsigned int x86_cpuid_lookup_vendor(uint32_t ebx, uint32_t ecx, uint32_t edx);
74
75 /**
76 * Given Xen's internal vendor ID, return a string suitable for printing.
77 * Returns "Unknown" for any unrecognised ID.
78 */
79 const char *x86_cpuid_vendor_to_str(unsigned int vendor);
80
81 #define CPUID_GUEST_NR_BASIC (0xdu + 1)
82 #define CPUID_GUEST_NR_CACHE (5u + 1)
83 #define CPUID_GUEST_NR_FEAT (1u + 1)
84 #define CPUID_GUEST_NR_TOPO (1u + 1)
85 #define CPUID_GUEST_NR_XSTATE (62u + 1)
86 #define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1)
87 #define CPUID_GUEST_NR_EXTD_AMD (0x1cu + 1)
88 #define CPUID_GUEST_NR_EXTD MAX(CPUID_GUEST_NR_EXTD_INTEL, \
89 CPUID_GUEST_NR_EXTD_AMD)
90
91 /*
92 * Maximum number of leaves a struct cpuid_policy turns into when serialised
93 * for interaction with the toolstack. (Sum of all leaves in each union, less
94 * the entries in basic which sub-unions hang off of.)
95 */
96 #define CPUID_MAX_SERIALISED_LEAVES \
97 (CPUID_GUEST_NR_BASIC + \
98 CPUID_GUEST_NR_FEAT - !!CPUID_GUEST_NR_FEAT + \
99 CPUID_GUEST_NR_CACHE - !!CPUID_GUEST_NR_CACHE + \
100 CPUID_GUEST_NR_TOPO - !!CPUID_GUEST_NR_TOPO + \
101 CPUID_GUEST_NR_XSTATE - !!CPUID_GUEST_NR_XSTATE + \
102 CPUID_GUEST_NR_EXTD + 2 /* hv_limit and hv2_limit */ )
103
104 struct cpuid_policy
105 {
106 #define DECL_BITFIELD(word) _DECL_BITFIELD(FEATURESET_ ## word)
107 #define _DECL_BITFIELD(x) __DECL_BITFIELD(x)
108 #define __DECL_BITFIELD(x) CPUID_BITFIELD_ ## x
109
110 /* Basic leaves: 0x000000xx */
111 union {
112 struct cpuid_leaf raw[CPUID_GUEST_NR_BASIC];
113 struct {
114 /* Leaf 0x0 - Max and vendor. */
115 uint32_t max_leaf, vendor_ebx, vendor_ecx, vendor_edx;
116
117 /* Leaf 0x1 - Family/model/stepping and features. */
118 uint32_t raw_fms;
119 uint8_t :8, /* Brand ID. */
120 clflush_size, /* Number of 8-byte blocks per cache line. */
121 lppp, /* Logical processors per package. */
122 apic_id; /* Initial APIC ID. */
123 union {
124 uint32_t _1c;
125 struct { DECL_BITFIELD(1c); };
126 };
127 union {
128 uint32_t _1d;
129 struct { DECL_BITFIELD(1d); };
130 };
131
132 /* Leaf 0x2 - TLB/Cache/Prefetch. */
133 uint8_t l2_nr_queries; /* Documented as fixed to 1. */
134 uint8_t l2_desc[15];
135
136 uint64_t :64, :64; /* Leaf 0x3 - PSN. */
137 uint64_t :64, :64; /* Leaf 0x4 - Structured Cache. */
138 uint64_t :64, :64; /* Leaf 0x5 - MONITOR. */
139 uint64_t :64, :64; /* Leaf 0x6 - Therm/Perf. */
140 uint64_t :64, :64; /* Leaf 0x7 - Structured Features. */
141 uint64_t :64, :64; /* Leaf 0x8 - rsvd */
142 uint64_t :64, :64; /* Leaf 0x9 - DCA */
143
144 /* Leaf 0xa - Intel PMU. */
145 uint8_t pmu_version, _pmu[15];
146
147 uint64_t :64, :64; /* Leaf 0xb - Topology. */
148 uint64_t :64, :64; /* Leaf 0xc - rsvd */
149 uint64_t :64, :64; /* Leaf 0xd - XSTATE. */
150 };
151 } basic;
152
153 /* Structured cache leaf: 0x00000004[xx] */
154 union {
155 struct cpuid_leaf raw[CPUID_GUEST_NR_CACHE];
156 struct cpuid_cache_leaf {
157 uint32_t /* a */ type:5, level:3;
158 bool self_init:1, fully_assoc:1;
159 uint32_t :4, threads_per_cache:12, cores_per_package:6;
160 uint32_t /* b */ line_size:12, partitions:10, ways:10;
161 uint32_t /* c */ sets;
162 bool /* d */ wbinvd:1, inclusive:1, complex:1;
163 } subleaf[CPUID_GUEST_NR_CACHE];
164 } cache;
165
166 /* Structured feature leaf: 0x00000007[xx] */
167 union {
168 struct cpuid_leaf raw[CPUID_GUEST_NR_FEAT];
169 struct {
170 /* Subleaf 0. */
171 uint32_t max_subleaf;
172 union {
173 uint32_t _7b0;
174 struct { DECL_BITFIELD(7b0); };
175 };
176 union {
177 uint32_t _7c0;
178 struct { DECL_BITFIELD(7c0); };
179 };
180 union {
181 uint32_t _7d0;
182 struct { DECL_BITFIELD(7d0); };
183 };
184
185 /* Subleaf 1. */
186 union {
187 uint32_t _7a1;
188 struct { DECL_BITFIELD(7a1); };
189 };
190 };
191 } feat;
192
193 /* Extended topology enumeration: 0x0000000B[xx] */
194 union {
195 struct cpuid_leaf raw[CPUID_GUEST_NR_TOPO];
196 struct cpuid_topo_leaf {
197 uint32_t id_shift:5, :27;
198 uint16_t nr_logical, :16;
199 uint8_t level, type, :8, :8;
200 uint32_t x2apic_id;
201 } subleaf[CPUID_GUEST_NR_TOPO];
202 } topo;
203
204 /* Xstate feature leaf: 0x0000000D[xx] */
205 union {
206 struct cpuid_leaf raw[CPUID_GUEST_NR_XSTATE];
207
208 struct {
209 /* Subleaf 0. */
210 uint32_t xcr0_low, /* b */:32, max_size, xcr0_high;
211
212 /* Subleaf 1. */
213 union {
214 uint32_t Da1;
215 struct { DECL_BITFIELD(Da1); };
216 };
217 uint32_t /* b */:32, xss_low, xss_high;
218 };
219
220 /* Per-component common state. Valid for i >= 2. */
221 struct {
222 uint32_t size, offset;
223 bool xss:1, align:1;
224 uint32_t _res_d;
225 } comp[CPUID_GUEST_NR_XSTATE];
226 } xstate;
227
228 /* Extended leaves: 0x800000xx */
229 union {
230 struct cpuid_leaf raw[CPUID_GUEST_NR_EXTD];
231 struct {
232 /* Leaf 0x80000000 - Max and vendor. */
233 uint32_t max_leaf, vendor_ebx, vendor_ecx, vendor_edx;
234
235 /* Leaf 0x80000001 - Family/model/stepping and features. */
236 uint32_t raw_fms, /* b */:32;
237 union {
238 uint32_t e1c;
239 struct { DECL_BITFIELD(e1c); };
240 };
241 union {
242 uint32_t e1d;
243 struct { DECL_BITFIELD(e1d); };
244 };
245
246 uint64_t :64, :64; /* Brand string. */
247 uint64_t :64, :64; /* Brand string. */
248 uint64_t :64, :64; /* Brand string. */
249 uint64_t :64, :64; /* L1 cache/TLB. */
250 uint64_t :64, :64; /* L2/3 cache/TLB. */
251
252 /* Leaf 0x80000007 - Advanced Power Management. */
253 uint32_t /* a */:32, /* b */:32, /* c */:32;
254 union {
255 uint32_t e7d;
256 struct { DECL_BITFIELD(e7d); };
257 };
258
259 /* Leaf 0x80000008 - Misc addr/feature info. */
260 uint8_t maxphysaddr, maxlinaddr, :8, :8;
261 union {
262 uint32_t e8b;
263 struct { DECL_BITFIELD(e8b); };
264 };
265 uint32_t nc:8, :4, apic_id_size:4, :16;
266 uint32_t /* d */:32;
267 };
268 } extd;
269
270 #undef __DECL_BITFIELD
271 #undef _DECL_BITFIELD
272 #undef DECL_BITFIELD
273
274 /* Toolstack selected Hypervisor max_leaf (if non-zero). */
275 uint8_t hv_limit, hv2_limit;
276
277 /* Value calculated from raw data above. */
278 uint8_t x86_vendor;
279 };
280
281 /* Fill in a featureset bitmap from a CPUID policy. */
cpuid_policy_to_featureset(const struct cpuid_policy * p,uint32_t fs[FEATURESET_NR_ENTRIES])282 static inline void cpuid_policy_to_featureset(
283 const struct cpuid_policy *p, uint32_t fs[FEATURESET_NR_ENTRIES])
284 {
285 fs[FEATURESET_1d] = p->basic._1d;
286 fs[FEATURESET_1c] = p->basic._1c;
287 fs[FEATURESET_e1d] = p->extd.e1d;
288 fs[FEATURESET_e1c] = p->extd.e1c;
289 fs[FEATURESET_Da1] = p->xstate.Da1;
290 fs[FEATURESET_7b0] = p->feat._7b0;
291 fs[FEATURESET_7c0] = p->feat._7c0;
292 fs[FEATURESET_e7d] = p->extd.e7d;
293 fs[FEATURESET_e8b] = p->extd.e8b;
294 fs[FEATURESET_7d0] = p->feat._7d0;
295 fs[FEATURESET_7a1] = p->feat._7a1;
296 }
297
298 /* Fill in a CPUID policy from a featureset bitmap. */
cpuid_featureset_to_policy(const uint32_t fs[FEATURESET_NR_ENTRIES],struct cpuid_policy * p)299 static inline void cpuid_featureset_to_policy(
300 const uint32_t fs[FEATURESET_NR_ENTRIES], struct cpuid_policy *p)
301 {
302 p->basic._1d = fs[FEATURESET_1d];
303 p->basic._1c = fs[FEATURESET_1c];
304 p->extd.e1d = fs[FEATURESET_e1d];
305 p->extd.e1c = fs[FEATURESET_e1c];
306 p->xstate.Da1 = fs[FEATURESET_Da1];
307 p->feat._7b0 = fs[FEATURESET_7b0];
308 p->feat._7c0 = fs[FEATURESET_7c0];
309 p->extd.e7d = fs[FEATURESET_e7d];
310 p->extd.e8b = fs[FEATURESET_e8b];
311 p->feat._7d0 = fs[FEATURESET_7d0];
312 p->feat._7a1 = fs[FEATURESET_7a1];
313 }
314
cpuid_policy_xcr0_max(const struct cpuid_policy * p)315 static inline uint64_t cpuid_policy_xcr0_max(const struct cpuid_policy *p)
316 {
317 return ((uint64_t)p->xstate.xcr0_high << 32) | p->xstate.xcr0_low;
318 }
319
cpuid_policy_xstates(const struct cpuid_policy * p)320 static inline uint64_t cpuid_policy_xstates(const struct cpuid_policy *p)
321 {
322 uint64_t val = p->xstate.xcr0_high | p->xstate.xss_high;
323
324 return (val << 32) | p->xstate.xcr0_low | p->xstate.xss_low;
325 }
326
327 const uint32_t *x86_cpuid_lookup_deep_deps(uint32_t feature);
328
329 /**
330 * Recalculate the content in a CPUID policy which is derived from raw data.
331 */
332 void x86_cpuid_policy_recalc_synth(struct cpuid_policy *p);
333
334 /**
335 * Fill a CPUID policy using the native CPUID instruction.
336 *
337 * No sanitisation is performed, but synthesised values are calculated.
338 * Values may be influenced by a hypervisor or from masking/faulting
339 * configuration.
340 */
341 void x86_cpuid_policy_fill_native(struct cpuid_policy *p);
342
343 /**
344 * Clear leaf data beyond the policies max leaf/subleaf settings.
345 *
346 * Policy serialisation purposefully omits out-of-range leaves, because there
347 * are a large number of them due to vendor differences. However, when
348 * constructing new policies (e.g. levelling down), it is possible to end up
349 * with out-of-range leaves with stale content in them. This helper clears
350 * them.
351 */
352 void x86_cpuid_policy_clear_out_of_range_leaves(struct cpuid_policy *p);
353
354 #ifdef __XEN__
355 #include <public/arch-x86/xen.h>
356 typedef XEN_GUEST_HANDLE_64(xen_cpuid_leaf_t) cpuid_leaf_buffer_t;
357 #else
358 #include <xen/arch-x86/xen.h>
359 typedef xen_cpuid_leaf_t cpuid_leaf_buffer_t[];
360 #endif
361
362 /**
363 * Serialise a cpuid_policy object into an array of cpuid leaves.
364 *
365 * @param policy The cpuid_policy to serialise.
366 * @param leaves The array of leaves to serialise into.
367 * @param nr_entries The number of entries in 'leaves'.
368 * @returns -errno
369 *
370 * Writes at most CPUID_MAX_SERIALISED_LEAVES. May fail with -ENOBUFS if the
371 * leaves array is too short. On success, nr_entries is updated with the
372 * actual number of leaves written.
373 */
374 int x86_cpuid_copy_to_buffer(const struct cpuid_policy *policy,
375 cpuid_leaf_buffer_t leaves, uint32_t *nr_entries);
376
377 /**
378 * Unserialise a cpuid_policy object from an array of cpuid leaves.
379 *
380 * @param policy The cpuid_policy to unserialise into.
381 * @param leaves The array of leaves to unserialise from.
382 * @param nr_entries The number of entries in 'leaves'.
383 * @param err_leaf Optional hint for error diagnostics.
384 * @param err_subleaf Optional hint for error diagnostics.
385 * @returns -errno
386 *
387 * Reads at most CPUID_MAX_SERIALISED_LEAVES. May return -ERANGE if an
388 * incoming leaf is out of range of cpuid_policy, in which case the optional
389 * err_* pointers will identify the out-of-range indicies.
390 *
391 * No content validation of in-range leaves is performed. Synthesised data is
392 * recalculated.
393 */
394 int x86_cpuid_copy_from_buffer(struct cpuid_policy *policy,
395 const cpuid_leaf_buffer_t leaves,
396 uint32_t nr_entries, uint32_t *err_leaf,
397 uint32_t *err_subleaf);
398
399 #endif /* !XEN_LIB_X86_CPUID_H */
400
401 /*
402 * Local variables:
403 * mode: C
404 * c-file-style: "BSD"
405 * c-basic-offset: 4
406 * tab-width: 4
407 * indent-tabs-mode: nil
408 * End:
409 */
410