Coverage Report

Created: 2026-08-15 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xen/xen/arch/x86/lib/cpu-policy/cpuid.c
Line
Count
Source
1
#include "private.h"
2
3
#include <xen/lib/x86/cpu-policy.h>
4
5
static void zero_leaves(struct cpuid_leaf *l,
6
                        unsigned int first, unsigned int last)
7
0
{
8
0
    if ( first <= last )
9
0
        memset(&l[first], 0, sizeof(*l) * (last - first + 1));
10
0
}
11
12
unsigned int x86_cpuid_lookup_vendor(uint32_t ebx, uint32_t ecx, uint32_t edx)
13
2
{
14
2
    switch ( ebx )
15
2
    {
16
2
    case X86_VENDOR_INTEL_EBX:
17
2
        if ( ecx == X86_VENDOR_INTEL_ECX &&
18
2
             edx == X86_VENDOR_INTEL_EDX )
19
2
            return X86_VENDOR_INTEL;
20
0
        break;
21
22
0
    case X86_VENDOR_AMD_EBX:
23
0
        if ( ecx == X86_VENDOR_AMD_ECX &&
24
0
             edx == X86_VENDOR_AMD_EDX )
25
0
            return X86_VENDOR_AMD;
26
0
        break;
27
28
0
    case X86_VENDOR_CENTAUR_EBX:
29
0
        if ( ecx == X86_VENDOR_CENTAUR_ECX &&
30
0
             edx == X86_VENDOR_CENTAUR_EDX )
31
0
            return X86_VENDOR_CENTAUR;
32
0
        break;
33
34
0
    case X86_VENDOR_SHANGHAI_EBX:
35
0
        if ( ecx == X86_VENDOR_SHANGHAI_ECX &&
36
0
             edx == X86_VENDOR_SHANGHAI_EDX )
37
0
            return X86_VENDOR_SHANGHAI;
38
0
        break;
39
40
0
    case X86_VENDOR_HYGON_EBX:
41
0
        if ( ecx == X86_VENDOR_HYGON_ECX &&
42
0
             edx == X86_VENDOR_HYGON_EDX )
43
0
            return X86_VENDOR_HYGON;
44
0
        break;
45
2
    }
46
47
0
    return X86_VENDOR_UNKNOWN;
48
2
}
49
50
const char *x86_cpuid_vendor_to_str(unsigned int vendor)
51
0
{
52
0
    switch ( vendor )
53
0
    {
54
0
    case X86_VENDOR_INTEL:    return "Intel";
55
0
    case X86_VENDOR_AMD:      return "AMD";
56
0
    case X86_VENDOR_CENTAUR:  return "Centaur";
57
0
    case X86_VENDOR_SHANGHAI: return "Shanghai";
58
0
    case X86_VENDOR_HYGON:    return "Hygon";
59
0
    default:                  return "Unknown";
60
0
    }
61
0
}
62
63
void x86_cpu_policy_to_featureset(
64
    const struct cpu_policy *p, uint32_t fs[FEATURESET_NR_ENTRIES])
65
0
{
66
0
    fs[FEATURESET_1d]        = p->basic._1d;
67
0
    fs[FEATURESET_1c]        = p->basic._1c;
68
0
    fs[FEATURESET_e1d]       = p->extd.e1d;
69
0
    fs[FEATURESET_e1c]       = p->extd.e1c;
70
0
    fs[FEATURESET_Da1]       = p->xstate.Da1;
71
0
    fs[FEATURESET_7b0]       = p->feat._7b0;
72
0
    fs[FEATURESET_7c0]       = p->feat._7c0;
73
0
    fs[FEATURESET_e7d]       = p->extd.e7d;
74
0
    fs[FEATURESET_e8b]       = p->extd.e8b;
75
0
    fs[FEATURESET_7d0]       = p->feat._7d0;
76
0
    fs[FEATURESET_7a1]       = p->feat._7a1;
77
0
    fs[FEATURESET_e21a]      = p->extd.e21a;
78
0
    fs[FEATURESET_7b1]       = p->feat._7b1;
79
0
    fs[FEATURESET_7d2]       = p->feat._7d2;
80
0
    fs[FEATURESET_7c1]       = p->feat._7c1;
81
0
    fs[FEATURESET_7d1]       = p->feat._7d1;
82
0
    fs[FEATURESET_m10Al]     = p->arch_caps.lo;
83
0
    fs[FEATURESET_m10Ah]     = p->arch_caps.hi;
84
0
    fs[FEATURESET_e21c]      = p->extd.e21c;
85
0
}
86
87
void x86_cpu_featureset_to_policy(
88
    const uint32_t fs[FEATURESET_NR_ENTRIES], struct cpu_policy *p)
89
0
{
90
0
    p->basic._1d             = fs[FEATURESET_1d];
91
0
    p->basic._1c             = fs[FEATURESET_1c];
92
0
    p->extd.e1d              = fs[FEATURESET_e1d];
93
0
    p->extd.e1c              = fs[FEATURESET_e1c];
94
0
    p->xstate.Da1            = fs[FEATURESET_Da1];
95
0
    p->feat._7b0             = fs[FEATURESET_7b0];
96
0
    p->feat._7c0             = fs[FEATURESET_7c0];
97
0
    p->extd.e7d              = fs[FEATURESET_e7d];
98
0
    p->extd.e8b              = fs[FEATURESET_e8b];
99
0
    p->feat._7d0             = fs[FEATURESET_7d0];
100
0
    p->feat._7a1             = fs[FEATURESET_7a1];
101
0
    p->extd.e21a             = fs[FEATURESET_e21a];
102
0
    p->feat._7b1             = fs[FEATURESET_7b1];
103
0
    p->feat._7d2             = fs[FEATURESET_7d2];
104
0
    p->feat._7c1             = fs[FEATURESET_7c1];
105
0
    p->feat._7d1             = fs[FEATURESET_7d1];
106
0
    p->arch_caps.lo          = fs[FEATURESET_m10Al];
107
0
    p->arch_caps.hi          = fs[FEATURESET_m10Ah];
108
0
    p->extd.e21c             = fs[FEATURESET_e21c];
109
0
}
110
111
void x86_cpu_policy_recalc_synth(struct cpu_policy *p)
112
2
{
113
2
    p->x86_vendor = x86_cpuid_lookup_vendor(
114
2
        p->basic.vendor_ebx, p->basic.vendor_ecx, p->basic.vendor_edx);
115
2
}
116
117
void x86_cpu_policy_fill_native(struct cpu_policy *p)
118
2
{
119
2
    unsigned int i;
120
121
2
    cpuid_leaf(0, &p->basic.raw[0]);
122
28
    for ( i = 1; i <= MIN(p->basic.max_leaf,
123
26
                          ARRAY_SIZE(p->basic.raw) - 1); ++i )
124
26
    {
125
26
        switch ( i )
126
26
        {
127
8
        case 0x4: case 0x7: case 0xb: case 0xd:
128
            /* Multi-invocation leaves.  Deferred. */
129
8
            continue;
130
26
        }
131
132
18
        cpuid_leaf(i, &p->basic.raw[i]);
133
18
    }
134
135
2
    if ( p->basic.max_leaf >= 4 )
136
2
    {
137
10
        for ( i = 0; i < ARRAY_SIZE(p->cache.raw); ++i )
138
10
        {
139
10
            union {
140
10
                struct cpuid_leaf l;
141
10
                struct cpuid_cache_leaf c;
142
10
            } u;
143
144
10
            cpuid_count_leaf(4, i, &u.l);
145
146
10
            if ( u.c.type == 0 )
147
2
                break;
148
149
8
            p->cache.subleaf[i] = u.c;
150
8
        }
151
152
        /*
153
         * The choice of CPUID_GUEST_NR_CACHE is arbitrary.  It is expected
154
         * that it will eventually need increasing for future hardware.
155
         */
156
#ifdef __XEN__
157
        if ( i == ARRAY_SIZE(p->cache.raw) )
158
            printk(XENLOG_WARNING
159
                   "CPUID: Insufficient Leaf 4 space for this hardware\n");
160
#endif
161
2
    }
162
163
2
    if ( p->basic.max_leaf >= 7 )
164
2
    {
165
2
        cpuid_count_leaf(7, 0, &p->feat.raw[0]);
166
167
2
        for ( i = 1; i <= MIN(p->feat.max_subleaf,
168
2
                              ARRAY_SIZE(p->feat.raw) - 1); ++i )
169
0
            cpuid_count_leaf(7, i, &p->feat.raw[i]);
170
2
    }
171
172
2
    if ( p->basic.max_leaf >= 0xb )
173
2
    {
174
2
        union {
175
2
            struct cpuid_leaf l;
176
2
            struct cpuid_topo_leaf t;
177
2
        } u;
178
179
6
        for ( i = 0; i < ARRAY_SIZE(p->topo.raw); ++i )
180
4
        {
181
4
            cpuid_count_leaf(0xb, i, &u.l);
182
183
4
            if ( u.t.type == 0 )
184
0
                break;
185
186
4
            p->topo.subleaf[i] = u.t;
187
4
        }
188
189
        /*
190
         * The choice of CPUID_GUEST_NR_TOPO is per the manual.  It may need
191
         * to grow for future hardware.
192
         */
193
#ifdef __XEN__
194
        if ( i == ARRAY_SIZE(p->topo.raw) &&
195
             (cpuid_count_leaf(0xb, i, &u.l), u.t.type != 0) )
196
            printk(XENLOG_WARNING
197
                   "CPUID: Insufficient Leaf 0xb space for this hardware\n");
198
#endif
199
2
    }
200
201
2
    if ( p->basic.max_leaf >= 0xd )
202
2
    {
203
2
        uint64_t xstates;
204
205
2
        cpuid_count_leaf(0xd, 0, &p->xstate.raw[0]);
206
2
        cpuid_count_leaf(0xd, 1, &p->xstate.raw[1]);
207
208
2
        xstates = cpu_policy_xstates(p);
209
210
        /* This logic will probably need adjusting when XCR0[63] gets used. */
211
2
        BUILD_BUG_ON(ARRAY_SIZE(p->xstate.raw) > 63);
212
213
124
        for ( i = 2; i < min_t(unsigned int, 63,
214
122
                               ARRAY_SIZE(p->xstate.raw)); ++i )
215
122
        {
216
122
            if ( xstates & (1ULL << i) )
217
2
                cpuid_count_leaf(0xd, i, &p->xstate.raw[i]);
218
122
        }
219
2
    }
220
221
    /* Extended leaves. */
222
2
    cpuid_leaf(0x80000000U, &p->extd.raw[0]);
223
18
    for ( i = 1; i <= MIN(p->extd.max_leaf & 0xffffU,
224
16
                          ARRAY_SIZE(p->extd.raw) - 1); ++i )
225
16
        cpuid_leaf(0x80000000U + i, &p->extd.raw[i]);
226
227
    /* Don't report leaves from possible lower level hypervisor, for now. */
228
2
    p->hv_limit = 0;
229
2
    p->hv2_limit = 0;
230
231
#ifdef __XEN__
232
    /* TODO MSR_PLATFORM_INFO */
233
234
    if ( p->feat.arch_caps )
235
        rdmsrl(MSR_ARCH_CAPABILITIES, p->arch_caps.raw);
236
#endif
237
238
2
    x86_cpu_policy_recalc_synth(p);
239
2
}
240
241
void x86_cpu_policy_clear_out_of_range_leaves(struct cpu_policy *p)
242
0
{
243
0
    unsigned int i;
244
245
0
    zero_leaves(p->basic.raw, p->basic.max_leaf + 1,
246
0
                ARRAY_SIZE(p->basic.raw) - 1);
247
248
0
    if ( p->basic.max_leaf < 4 )
249
0
        memset(p->cache.raw, 0, sizeof(p->cache.raw));
250
0
    else
251
0
    {
252
0
        for ( i = 0; (i < ARRAY_SIZE(p->cache.raw) &&
253
0
                      p->cache.subleaf[i].type); ++i )
254
0
            ;
255
256
0
        zero_leaves(p->cache.raw, i, ARRAY_SIZE(p->cache.raw) - 1);
257
0
    }
258
259
0
    if ( p->basic.max_leaf < 7 )
260
0
        memset(p->feat.raw, 0, sizeof(p->feat.raw));
261
0
    else
262
0
        zero_leaves(p->feat.raw, p->feat.max_subleaf + 1,
263
0
                    ARRAY_SIZE(p->feat.raw) - 1);
264
265
0
    if ( p->basic.max_leaf < 0xb )
266
0
        memset(p->topo.raw, 0, sizeof(p->topo.raw));
267
0
    else
268
0
    {
269
0
        for ( i = 0; (i < ARRAY_SIZE(p->topo.raw) &&
270
0
                      p->topo.subleaf[i].type); ++i )
271
0
            ;
272
273
0
        zero_leaves(p->topo.raw, i, ARRAY_SIZE(p->topo.raw) - 1);
274
0
    }
275
276
0
    if ( p->basic.max_leaf < 0xd || !cpu_policy_xstates(p) )
277
0
        memset(p->xstate.raw, 0, sizeof(p->xstate.raw));
278
0
    else
279
0
    {
280
        /* This logic will probably need adjusting when XCR0[63] gets used. */
281
0
        BUILD_BUG_ON(ARRAY_SIZE(p->xstate.raw) > 63);
282
283
        /* First two leaves always valid.  Rest depend on xstates. */
284
0
        i = max(2, 64 - __builtin_clzll(cpu_policy_xstates(p)));
285
286
0
        zero_leaves(p->xstate.raw, i,
287
0
                    ARRAY_SIZE(p->xstate.raw) - 1);
288
0
    }
289
290
0
    zero_leaves(p->extd.raw, (p->extd.max_leaf & 0xffff) + 1,
291
0
                ARRAY_SIZE(p->extd.raw) - 1);
292
0
}
293
294
const uint32_t *x86_cpu_policy_lookup_deep_deps(uint32_t feature)
295
0
{
296
0
    static const uint32_t deep_features[] = INIT_DEEP_FEATURES;
297
0
    static const struct {
298
0
        uint32_t feature;
299
0
        uint32_t fs[FEATURESET_NR_ENTRIES];
300
0
    } deep_deps[] = INIT_DEEP_DEPS;
301
0
    unsigned int start = 0, end = ARRAY_SIZE(deep_deps);
302
303
0
    BUILD_BUG_ON(ARRAY_SIZE(deep_deps) != NR_DEEP_DEPS);
304
305
    /* Fast early exit. */
306
0
    if ( !test_bit(feature, deep_features) )
307
0
        return NULL;
308
309
    /* deep_deps[] is sorted.  Perform a binary search. */
310
0
    while ( start < end )
311
0
    {
312
0
        unsigned int mid = start + ((end - start) / 2);
313
314
0
        if ( deep_deps[mid].feature > feature )
315
0
            end = mid;
316
0
        else if ( deep_deps[mid].feature < feature )
317
0
            start = mid + 1;
318
0
        else
319
0
            return deep_deps[mid].fs;
320
0
    }
321
322
0
    return NULL;
323
0
}
324
325
/*
326
 * Local variables:
327
 * mode: C
328
 * c-file-style: "BSD"
329
 * c-basic-offset: 4
330
 * tab-width: 4
331
 * indent-tabs-mode: nil
332
 * End:
333
 */