Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/microcode_intel.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Intel CPU Microcode Update Driver for Linux
3
 *
4
 * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
5
 *               2006 Shaohua Li <shaohua.li@intel.com> *
6
 * This driver allows to upgrade microcode on Intel processors
7
 * belonging to IA-32 family - PentiumPro, Pentium II,
8
 * Pentium III, Xeon, Pentium 4, etc.
9
 *
10
 * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
11
 * Software Developer's Manual
12
 * Order Number 253668 or free download from:
13
 *
14
 * http://developer.intel.com/design/pentium4/manuals/253668.htm
15
 *
16
 * For more information, go to http://www.urbanmyth.org/microcode
17
 *
18
 * This program is free software; you can redistribute it and/or
19
 * modify it under the terms of the GNU General Public License
20
 * as published by the Free Software Foundation; either version
21
 * 2 of the License, or (at your option) any later version.
22
 */
23
24
#include <xen/lib.h>
25
#include <xen/kernel.h>
26
#include <xen/init.h>
27
#include <xen/sched.h>
28
#include <xen/smp.h>
29
#include <xen/spinlock.h>
30
31
#include <asm/msr.h>
32
#include <asm/processor.h>
33
#include <asm/microcode.h>
34
35
0
#define pr_debug(x...) ((void)0)
36
37
struct microcode_header_intel {
38
    unsigned int hdrver;
39
    unsigned int rev;
40
    unsigned int date;
41
    unsigned int sig;
42
    unsigned int cksum;
43
    unsigned int ldrver;
44
    unsigned int pf;
45
    unsigned int datasize;
46
    unsigned int totalsize;
47
    unsigned int reserved[3];
48
};
49
50
struct microcode_intel {
51
    struct microcode_header_intel hdr;
52
    unsigned int bits[0];
53
};
54
55
/* microcode format is extended from prescott processors */
56
struct extended_signature {
57
    unsigned int sig;
58
    unsigned int pf;
59
    unsigned int cksum;
60
};
61
62
struct extended_sigtable {
63
    unsigned int count;
64
    unsigned int cksum;
65
    unsigned int reserved[3];
66
    struct extended_signature sigs[0];
67
};
68
69
0
#define DEFAULT_UCODE_DATASIZE  (2000)
70
0
#define MC_HEADER_SIZE          (sizeof(struct microcode_header_intel))
71
0
#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
72
0
#define EXT_HEADER_SIZE         (sizeof(struct extended_sigtable))
73
0
#define EXT_SIGNATURE_SIZE      (sizeof(struct extended_signature))
74
0
#define DWSIZE                  (sizeof(u32))
75
#define get_totalsize(mc) \
76
0
        (((struct microcode_intel *)mc)->hdr.totalsize ? \
77
0
         ((struct microcode_intel *)mc)->hdr.totalsize : \
78
0
         DEFAULT_UCODE_TOTALSIZE)
79
80
#define get_datasize(mc) \
81
0
        (((struct microcode_intel *)mc)->hdr.datasize ? \
82
0
         ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
83
84
#define sigmatch(s1, s2, p1, p2) \
85
0
        (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
86
87
0
#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
88
89
/* serialize access to the physical write to MSR 0x79 */
90
static DEFINE_SPINLOCK(microcode_update_lock);
91
92
static int collect_cpu_info(unsigned int cpu_num, struct cpu_signature *csig)
93
0
{
94
0
    struct cpuinfo_x86 *c = &cpu_data[cpu_num];
95
0
    uint64_t msr_content;
96
0
97
0
    BUG_ON(cpu_num != smp_processor_id());
98
0
99
0
    memset(csig, 0, sizeof(*csig));
100
0
101
0
    if ( (c->x86_vendor != X86_VENDOR_INTEL) || (c->x86 < 6) )
102
0
    {
103
0
        printk(KERN_ERR "microcode: CPU%d not a capable Intel "
104
0
               "processor\n", cpu_num);
105
0
        return -1;
106
0
    }
107
0
108
0
    csig->sig = cpuid_eax(0x00000001);
109
0
110
0
    if ( (c->x86_model >= 5) || (c->x86 > 6) )
111
0
    {
112
0
        /* get processor flags from MSR 0x17 */
113
0
        rdmsrl(MSR_IA32_PLATFORM_ID, msr_content);
114
0
        csig->pf = 1 << ((msr_content >> 50) & 7);
115
0
    }
116
0
117
0
    wrmsrl(MSR_IA32_UCODE_REV, 0x0ULL);
118
0
    /* As documented in the SDM: Do a CPUID 1 here */
119
0
    cpuid_eax(1);
120
0
121
0
    /* get the current revision from MSR 0x8B */
122
0
    rdmsrl(MSR_IA32_UCODE_REV, msr_content);
123
0
    csig->rev = (uint32_t)(msr_content >> 32);
124
0
    pr_debug("microcode: collect_cpu_info : sig=%#x, pf=%#x, rev=%#x\n",
125
0
             csig->sig, csig->pf, csig->rev);
126
0
127
0
    return 0;
128
0
}
129
130
static inline int microcode_update_match(
131
    unsigned int cpu_num, const struct microcode_header_intel *mc_header,
132
    int sig, int pf)
133
0
{
134
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu_num);
135
0
136
0
    return (sigmatch(sig, uci->cpu_sig.sig, pf, uci->cpu_sig.pf) &&
137
0
            (mc_header->rev > uci->cpu_sig.rev));
138
0
}
139
140
static int microcode_sanity_check(void *mc)
141
0
{
142
0
    struct microcode_header_intel *mc_header = mc;
143
0
    struct extended_sigtable *ext_header = NULL;
144
0
    struct extended_signature *ext_sig;
145
0
    unsigned long total_size, data_size, ext_table_size;
146
0
    unsigned int ext_sigcount = 0, i;
147
0
    uint32_t sum, orig_sum;
148
0
149
0
    total_size = get_totalsize(mc_header);
150
0
    data_size = get_datasize(mc_header);
151
0
    if ( (data_size + MC_HEADER_SIZE) > total_size )
152
0
    {
153
0
        printk(KERN_ERR "microcode: error! "
154
0
               "Bad data size in microcode data file\n");
155
0
        return -EINVAL;
156
0
    }
157
0
158
0
    if ( (mc_header->ldrver != 1) || (mc_header->hdrver != 1) )
159
0
    {
160
0
        printk(KERN_ERR "microcode: error! "
161
0
               "Unknown microcode update format\n");
162
0
        return -EINVAL;
163
0
    }
164
0
    ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
165
0
    if ( ext_table_size )
166
0
    {
167
0
        if ( (ext_table_size < EXT_HEADER_SIZE) ||
168
0
             ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE) )
169
0
        {
170
0
            printk(KERN_ERR "microcode: error! "
171
0
                   "Small exttable size in microcode data file\n");
172
0
            return -EINVAL;
173
0
        }
174
0
        ext_header = mc + MC_HEADER_SIZE + data_size;
175
0
        if ( ext_table_size != exttable_size(ext_header) )
176
0
        {
177
0
            printk(KERN_ERR "microcode: error! "
178
0
                   "Bad exttable size in microcode data file\n");
179
0
            return -EFAULT;
180
0
        }
181
0
        ext_sigcount = ext_header->count;
182
0
    }
183
0
184
0
    /* check extended table checksum */
185
0
    if ( ext_table_size )
186
0
    {
187
0
        uint32_t ext_table_sum = 0;
188
0
        uint32_t *ext_tablep = (uint32_t *)ext_header;
189
0
190
0
        i = ext_table_size / DWSIZE;
191
0
        while ( i-- )
192
0
            ext_table_sum += ext_tablep[i];
193
0
        if ( ext_table_sum )
194
0
        {
195
0
            printk(KERN_WARNING "microcode: aborting, "
196
0
                   "bad extended signature table checksum\n");
197
0
            return -EINVAL;
198
0
        }
199
0
    }
200
0
201
0
    /* calculate the checksum */
202
0
    orig_sum = 0;
203
0
    i = (MC_HEADER_SIZE + data_size) / DWSIZE;
204
0
    while ( i-- )
205
0
        orig_sum += ((uint32_t *)mc)[i];
206
0
    if ( orig_sum )
207
0
    {
208
0
        printk(KERN_ERR "microcode: aborting, bad checksum\n");
209
0
        return -EINVAL;
210
0
    }
211
0
    if ( !ext_table_size )
212
0
        return 0;
213
0
    /* check extended signature checksum */
214
0
    for ( i = 0; i < ext_sigcount; i++ )
215
0
    {
216
0
        ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
217
0
            EXT_SIGNATURE_SIZE * i;
218
0
        sum = orig_sum
219
0
            - (mc_header->sig + mc_header->pf + mc_header->cksum)
220
0
            + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
221
0
        if ( sum )
222
0
        {
223
0
            printk(KERN_ERR "microcode: aborting, bad checksum\n");
224
0
            return -EINVAL;
225
0
        }
226
0
    }
227
0
    return 0;
228
0
}
229
230
/*
231
 * return 0 - no update found
232
 * return 1 - found update
233
 * return < 0 - error
234
 */
235
static int get_matching_microcode(const void *mc, unsigned int cpu)
236
0
{
237
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
238
0
    const struct microcode_header_intel *mc_header = mc;
239
0
    const struct extended_sigtable *ext_header;
240
0
    unsigned long total_size = get_totalsize(mc_header);
241
0
    int ext_sigcount, i;
242
0
    struct extended_signature *ext_sig;
243
0
    void *new_mc;
244
0
245
0
    if ( microcode_update_match(cpu, mc_header,
246
0
                                mc_header->sig, mc_header->pf) )
247
0
        goto find;
248
0
249
0
    if ( total_size <= (get_datasize(mc_header) + MC_HEADER_SIZE) )
250
0
        return 0;
251
0
252
0
    ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
253
0
    ext_sigcount = ext_header->count;
254
0
    ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
255
0
    for ( i = 0; i < ext_sigcount; i++ )
256
0
    {
257
0
        if ( microcode_update_match(cpu, mc_header,
258
0
                                    ext_sig->sig, ext_sig->pf) )
259
0
            goto find;
260
0
        ext_sig++;
261
0
    }
262
0
    return 0;
263
0
 find:
264
0
    pr_debug("microcode: CPU%d found a matching microcode update with"
265
0
             " version %#x (current=%#x)\n",
266
0
             cpu, mc_header->rev, uci->cpu_sig.rev);
267
0
    new_mc = xmalloc_bytes(total_size);
268
0
    if ( new_mc == NULL )
269
0
    {
270
0
        printk(KERN_ERR "microcode: error! Can not allocate memory\n");
271
0
        return -ENOMEM;
272
0
    }
273
0
274
0
    memcpy(new_mc, mc, total_size);
275
0
    xfree(uci->mc.mc_intel);
276
0
    uci->mc.mc_intel = new_mc;
277
0
    return 1;
278
0
}
279
280
static int apply_microcode(unsigned int cpu)
281
0
{
282
0
    unsigned long flags;
283
0
    uint64_t msr_content;
284
0
    unsigned int val[2];
285
0
    unsigned int cpu_num = raw_smp_processor_id();
286
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu_num);
287
0
288
0
    /* We should bind the task to the CPU */
289
0
    BUG_ON(cpu_num != cpu);
290
0
291
0
    if ( uci->mc.mc_intel == NULL )
292
0
        return -EINVAL;
293
0
294
0
    /* serialize access to the physical write to MSR 0x79 */
295
0
    spin_lock_irqsave(&microcode_update_lock, flags);
296
0
297
0
    /* write microcode via MSR 0x79 */
298
0
    wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)uci->mc.mc_intel->bits);
299
0
    wrmsrl(MSR_IA32_UCODE_REV, 0x0ULL);
300
0
301
0
    /* As documented in the SDM: Do a CPUID 1 here */
302
0
    cpuid_eax(1);
303
0
304
0
    /* get the current revision from MSR 0x8B */
305
0
    rdmsrl(MSR_IA32_UCODE_REV, msr_content);
306
0
    val[1] = (uint32_t)(msr_content >> 32);
307
0
308
0
    spin_unlock_irqrestore(&microcode_update_lock, flags);
309
0
    if ( val[1] != uci->mc.mc_intel->hdr.rev )
310
0
    {
311
0
        printk(KERN_ERR "microcode: CPU%d update from revision "
312
0
               "%#x to %#x failed\n", cpu_num, uci->cpu_sig.rev, val[1]);
313
0
        return -EIO;
314
0
    }
315
0
    printk(KERN_INFO "microcode: CPU%d updated from revision "
316
0
           "%#x to %#x, date = %04x-%02x-%02x \n",
317
0
           cpu_num, uci->cpu_sig.rev, val[1],
318
0
           uci->mc.mc_intel->hdr.date & 0xffff,
319
0
           uci->mc.mc_intel->hdr.date >> 24,
320
0
           (uci->mc.mc_intel->hdr.date >> 16) & 0xff);
321
0
    uci->cpu_sig.rev = val[1];
322
0
323
0
    return 0;
324
0
}
325
326
static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
327
                                       unsigned long size, long offset)
328
0
{
329
0
    struct microcode_header_intel *mc_header;
330
0
    unsigned long total_size;
331
0
332
0
    /* No more data */
333
0
    if ( offset >= size )
334
0
        return 0;
335
0
    mc_header = (struct microcode_header_intel *)(buf + offset);
336
0
    total_size = get_totalsize(mc_header);
337
0
338
0
    if ( (offset + total_size) > size )
339
0
    {
340
0
        printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
341
0
        return -EINVAL;
342
0
    }
343
0
344
0
    *mc = xmalloc_bytes(total_size);
345
0
    if ( *mc == NULL )
346
0
    {
347
0
        printk(KERN_ERR "microcode: error! Can not allocate memory\n");
348
0
        return -ENOMEM;
349
0
    }
350
0
    memcpy(*mc, (const void *)(buf + offset), total_size);
351
0
    return offset + total_size;
352
0
}
353
354
static int cpu_request_microcode(unsigned int cpu, const void *buf,
355
                                 size_t size)
356
0
{
357
0
    long offset = 0;
358
0
    int error = 0;
359
0
    void *mc;
360
0
    unsigned int matching_count = 0;
361
0
362
0
    /* We should bind the task to the CPU */
363
0
    BUG_ON(cpu != raw_smp_processor_id());
364
0
365
0
    while ( (offset = get_next_ucode_from_buffer(&mc, buf, size, offset)) > 0 )
366
0
    {
367
0
        error = microcode_sanity_check(mc);
368
0
        if ( error )
369
0
            break;
370
0
        error = get_matching_microcode(mc, cpu);
371
0
        if ( error < 0 )
372
0
            break;
373
0
        /*
374
0
         * It's possible the data file has multiple matching ucode,
375
0
         * lets keep searching till the latest version
376
0
         */
377
0
        if ( error == 1 )
378
0
        {
379
0
            matching_count++;
380
0
            error = 0;
381
0
        }
382
0
        xfree(mc);
383
0
    }
384
0
    if ( offset > 0 )
385
0
        xfree(mc);
386
0
    if ( offset < 0 )
387
0
        error = offset;
388
0
389
0
    if ( !error && matching_count )
390
0
        apply_microcode(cpu);
391
0
392
0
    return error;
393
0
}
394
395
static int microcode_resume_match(unsigned int cpu, const void *mc)
396
0
{
397
0
    return get_matching_microcode(mc, cpu);
398
0
}
399
400
static const struct microcode_ops microcode_intel_ops = {
401
    .microcode_resume_match           = microcode_resume_match,
402
    .cpu_request_microcode            = cpu_request_microcode,
403
    .collect_cpu_info                 = collect_cpu_info,
404
    .apply_microcode                  = apply_microcode,
405
};
406
407
int __init microcode_init_intel(void)
408
1
{
409
1
    if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
410
1
        microcode_ops = &microcode_intel_ops;
411
1
    return 0;
412
1
}