Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/microcode_amd.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  AMD CPU Microcode Update Driver for Linux
3
 *  Copyright (C) 2008 Advanced Micro Devices Inc.
4
 *
5
 *  Author: Peter Oruba <peter.oruba@amd.com>
6
 *
7
 *  Based on work by:
8
 *  Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
9
 *
10
 *  This driver allows to upgrade microcode on AMD
11
 *  family 0x10 and later.
12
 *
13
 *  Licensed unter the terms of the GNU General Public
14
 *  License version 2. See file COPYING for details.
15
 */
16
17
#include <xen/lib.h>
18
#include <xen/kernel.h>
19
#include <xen/init.h>
20
#include <xen/sched.h>
21
#include <xen/smp.h>
22
#include <xen/spinlock.h>
23
24
#include <asm/msr.h>
25
#include <asm/processor.h>
26
#include <asm/microcode.h>
27
#include <asm/hvm/svm/svm.h>
28
29
0
#define pr_debug(x...) ((void)0)
30
31
0
#define CONT_HDR_SIZE           12
32
0
#define SECTION_HDR_SIZE        8
33
0
#define PATCH_HDR_SIZE          32
34
35
struct __packed equiv_cpu_entry {
36
    uint32_t installed_cpu;
37
    uint32_t fixed_errata_mask;
38
    uint32_t fixed_errata_compare;
39
    uint16_t equiv_cpu;
40
    uint16_t reserved;
41
};
42
43
struct __packed microcode_header_amd {
44
    uint32_t data_code;
45
    uint32_t patch_id;
46
    uint8_t  mc_patch_data_id[2];
47
    uint8_t  mc_patch_data_len;
48
    uint8_t  init_flag;
49
    uint32_t mc_patch_data_checksum;
50
    uint32_t nb_dev_id;
51
    uint32_t sb_dev_id;
52
    uint16_t processor_rev_id;
53
    uint8_t  nb_rev_id;
54
    uint8_t  sb_rev_id;
55
    uint8_t  bios_api_rev;
56
    uint8_t  reserved1[3];
57
    uint32_t match_reg[8];
58
};
59
60
0
#define UCODE_MAGIC                0x00414d44
61
0
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
62
0
#define UCODE_UCODE_TYPE           0x00000001
63
64
struct microcode_amd {
65
    void *mpb;
66
    size_t mpb_size;
67
    struct equiv_cpu_entry *equiv_cpu_table;
68
    size_t equiv_cpu_table_size;
69
};
70
71
struct mpbhdr {
72
    uint32_t type;
73
    uint32_t len;
74
    uint8_t data[];
75
};
76
77
/* serialize access to the physical write */
78
static DEFINE_SPINLOCK(microcode_update_lock);
79
80
/* See comment in start_update() for cases when this routine fails */
81
static int collect_cpu_info(unsigned int cpu, struct cpu_signature *csig)
82
0
{
83
0
    struct cpuinfo_x86 *c = &cpu_data[cpu];
84
0
85
0
    memset(csig, 0, sizeof(*csig));
86
0
87
0
    if ( (c->x86_vendor != X86_VENDOR_AMD) || (c->x86 < 0x10) )
88
0
    {
89
0
        printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
90
0
               cpu);
91
0
        return -EINVAL;
92
0
    }
93
0
94
0
    rdmsrl(MSR_AMD_PATCHLEVEL, csig->rev);
95
0
96
0
    pr_debug("microcode: CPU%d collect_cpu_info: patch_id=%#x\n",
97
0
             cpu, csig->rev);
98
0
99
0
    return 0;
100
0
}
101
102
static bool_t verify_patch_size(uint32_t patch_size)
103
0
{
104
0
    uint32_t max_size;
105
0
106
0
#define F1XH_MPB_MAX_SIZE 2048
107
0
#define F14H_MPB_MAX_SIZE 1824
108
0
#define F15H_MPB_MAX_SIZE 4096
109
0
#define F16H_MPB_MAX_SIZE 3458
110
0
111
0
    switch (boot_cpu_data.x86)
112
0
    {
113
0
    case 0x14:
114
0
        max_size = F14H_MPB_MAX_SIZE;
115
0
        break;
116
0
    case 0x15:
117
0
        max_size = F15H_MPB_MAX_SIZE;
118
0
        break;
119
0
    case 0x16:
120
0
        max_size = F16H_MPB_MAX_SIZE;
121
0
        break;
122
0
    default:
123
0
        max_size = F1XH_MPB_MAX_SIZE;
124
0
        break;
125
0
    }
126
0
127
0
    return (patch_size <= max_size);
128
0
}
129
130
static bool_t find_equiv_cpu_id(const struct equiv_cpu_entry *equiv_cpu_table,
131
                                unsigned int current_cpu_id,
132
                                unsigned int *equiv_cpu_id)
133
0
{
134
0
    unsigned int i;
135
0
136
0
    if ( !equiv_cpu_table )
137
0
        return 0;
138
0
139
0
    for ( i = 0; equiv_cpu_table[i].installed_cpu != 0; i++ )
140
0
    {
141
0
        if ( current_cpu_id == equiv_cpu_table[i].installed_cpu )
142
0
        {
143
0
            *equiv_cpu_id = equiv_cpu_table[i].equiv_cpu & 0xffff;
144
0
            return 1;
145
0
        }
146
0
    }
147
0
148
0
    return 0;
149
0
}
150
151
static bool_t microcode_fits(const struct microcode_amd *mc_amd,
152
                             unsigned int cpu)
153
0
{
154
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
155
0
    const struct microcode_header_amd *mc_header = mc_amd->mpb;
156
0
    const struct equiv_cpu_entry *equiv_cpu_table = mc_amd->equiv_cpu_table;
157
0
    unsigned int current_cpu_id;
158
0
    unsigned int equiv_cpu_id;
159
0
160
0
    /* We should bind the task to the CPU */
161
0
    BUG_ON(cpu != raw_smp_processor_id());
162
0
163
0
    current_cpu_id = cpuid_eax(0x00000001);
164
0
165
0
    if ( !find_equiv_cpu_id(equiv_cpu_table, current_cpu_id, &equiv_cpu_id) )
166
0
        return 0;
167
0
168
0
    if ( (mc_header->processor_rev_id) != equiv_cpu_id )
169
0
        return 0;
170
0
171
0
    if ( !verify_patch_size(mc_amd->mpb_size) )
172
0
    {
173
0
        pr_debug("microcode: patch size mismatch\n");
174
0
        return 0;
175
0
    }
176
0
177
0
    if ( mc_header->patch_id <= uci->cpu_sig.rev )
178
0
    {
179
0
        pr_debug("microcode: patch is already at required level or greater.\n");
180
0
        return 0;
181
0
    }
182
0
183
0
    pr_debug("microcode: CPU%d found a matching microcode update with version %#x (current=%#x)\n",
184
0
             cpu, mc_header->patch_id, uci->cpu_sig.rev);
185
0
186
0
    return 1;
187
0
}
188
189
static int apply_microcode(unsigned int cpu)
190
0
{
191
0
    unsigned long flags;
192
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
193
0
    uint32_t rev;
194
0
    struct microcode_amd *mc_amd = uci->mc.mc_amd;
195
0
    struct microcode_header_amd *hdr;
196
0
    int hw_err;
197
0
198
0
    /* We should bind the task to the CPU */
199
0
    BUG_ON(raw_smp_processor_id() != cpu);
200
0
201
0
    if ( mc_amd == NULL )
202
0
        return -EINVAL;
203
0
204
0
    hdr = mc_amd->mpb;
205
0
    if ( hdr == NULL )
206
0
        return -EINVAL;
207
0
208
0
    spin_lock_irqsave(&microcode_update_lock, flags);
209
0
210
0
    hw_err = wrmsr_safe(MSR_AMD_PATCHLOADER, (unsigned long)hdr);
211
0
212
0
    /* get patch id after patching */
213
0
    rdmsrl(MSR_AMD_PATCHLEVEL, rev);
214
0
215
0
    spin_unlock_irqrestore(&microcode_update_lock, flags);
216
0
217
0
    /* check current patch id and patch's id for match */
218
0
    if ( hw_err || (rev != hdr->patch_id) )
219
0
    {
220
0
        printk(KERN_ERR "microcode: CPU%d update from revision "
221
0
               "%#x to %#x failed\n", cpu, rev, hdr->patch_id);
222
0
        return -EIO;
223
0
    }
224
0
225
0
    printk(KERN_WARNING "microcode: CPU%d updated from revision %#x to %#x\n",
226
0
           cpu, uci->cpu_sig.rev, hdr->patch_id);
227
0
228
0
    uci->cpu_sig.rev = rev;
229
0
230
0
    return 0;
231
0
}
232
233
static int get_ucode_from_buffer_amd(
234
    struct microcode_amd *mc_amd,
235
    const void *buf,
236
    size_t bufsize,
237
    size_t *offset)
238
0
{
239
0
    const struct mpbhdr *mpbuf = buf + *offset;
240
0
241
0
    /* No more data */
242
0
    if ( *offset >= bufsize )
243
0
    {
244
0
        printk(KERN_ERR "microcode: Microcode buffer overrun\n");
245
0
        return -EINVAL;
246
0
    }
247
0
248
0
    if ( mpbuf->type != UCODE_UCODE_TYPE )
249
0
    {
250
0
        printk(KERN_ERR "microcode: Wrong microcode payload type field\n");
251
0
        return -EINVAL;
252
0
    }
253
0
254
0
    if ( (*offset + mpbuf->len) > bufsize )
255
0
    {
256
0
        printk(KERN_ERR "microcode: Bad data in microcode data file\n");
257
0
        return -EINVAL;
258
0
    }
259
0
260
0
    if ( mc_amd->mpb_size < mpbuf->len )
261
0
    {
262
0
        if ( mc_amd->mpb )
263
0
        {
264
0
            xfree(mc_amd->mpb);
265
0
            mc_amd->mpb_size = 0;
266
0
        }
267
0
        mc_amd->mpb = xmalloc_bytes(mpbuf->len);
268
0
        if ( mc_amd->mpb == NULL )
269
0
            return -ENOMEM;
270
0
        mc_amd->mpb_size = mpbuf->len;
271
0
    }
272
0
    memcpy(mc_amd->mpb, mpbuf->data, mpbuf->len);
273
0
274
0
    pr_debug("microcode: CPU%d size %zu, block size %u offset %zu equivID %#x rev %#x\n",
275
0
             raw_smp_processor_id(), bufsize, mpbuf->len, *offset,
276
0
             ((struct microcode_header_amd *)mc_amd->mpb)->processor_rev_id,
277
0
             ((struct microcode_header_amd *)mc_amd->mpb)->patch_id);
278
0
279
0
    *offset += mpbuf->len + SECTION_HDR_SIZE;
280
0
281
0
    return 0;
282
0
}
283
284
static int install_equiv_cpu_table(
285
    struct microcode_amd *mc_amd,
286
    const void *data,
287
    size_t *offset)
288
0
{
289
0
    const struct mpbhdr *mpbuf = data + *offset + 4;
290
0
291
0
    *offset += mpbuf->len + CONT_HDR_SIZE; /* add header length */
292
0
293
0
    if ( mpbuf->type != UCODE_EQUIV_CPU_TABLE_TYPE )
294
0
    {
295
0
        printk(KERN_ERR "microcode: Wrong microcode equivalent cpu table type field\n");
296
0
        return -EINVAL;
297
0
    }
298
0
299
0
    if ( mpbuf->len == 0 )
300
0
    {
301
0
        printk(KERN_ERR "microcode: Wrong microcode equivalent cpu table length\n");
302
0
        return -EINVAL;
303
0
    }
304
0
305
0
    mc_amd->equiv_cpu_table = xmalloc_bytes(mpbuf->len);
306
0
    if ( !mc_amd->equiv_cpu_table )
307
0
    {
308
0
        printk(KERN_ERR "microcode: Cannot allocate memory for equivalent cpu table\n");
309
0
        return -ENOMEM;
310
0
    }
311
0
312
0
    memcpy(mc_amd->equiv_cpu_table, mpbuf->data, mpbuf->len);
313
0
    mc_amd->equiv_cpu_table_size = mpbuf->len;
314
0
315
0
    return 0;
316
0
}
317
318
static int container_fast_forward(const void *data, size_t size_left, size_t *offset)
319
0
{
320
0
    for ( ; ; )
321
0
    {
322
0
        size_t size;
323
0
        const uint32_t *header;
324
0
325
0
        if ( size_left < SECTION_HDR_SIZE )
326
0
            return -EINVAL;
327
0
328
0
        header = data + *offset;
329
0
330
0
        if ( header[0] == UCODE_MAGIC &&
331
0
             header[1] == UCODE_EQUIV_CPU_TABLE_TYPE )
332
0
            break;
333
0
334
0
        if ( header[0] != UCODE_UCODE_TYPE )
335
0
            return -EINVAL;
336
0
        size = header[1] + SECTION_HDR_SIZE;
337
0
        if ( size < PATCH_HDR_SIZE || size_left < size )
338
0
            return -EINVAL;
339
0
340
0
        size_left -= size;
341
0
        *offset += size;
342
0
343
0
        if ( !size_left )
344
0
            return -ENODATA;
345
0
    }
346
0
347
0
    return 0;
348
0
}
349
350
/*
351
 * The 'final_levels' of patch ids have been obtained empirically.
352
 * Refer bug https://bugzilla.suse.com/show_bug.cgi?id=913996 
353
 * for details of the issue. The short version is that people
354
 * using certain Fam10h systems noticed system hang issues when
355
 * trying to update microcode levels beyond the patch IDs below.
356
 * From internal discussions, we gathered that OS/hypervisor
357
 * cannot reliably perform microcode updates beyond these levels
358
 * due to hardware issues. Therefore, we need to abort microcode
359
 * update process if we hit any of these levels.
360
 */
361
static const unsigned int final_levels[] = {
362
    0x01000098,
363
    0x0100009f,
364
    0x010000af
365
};
366
367
static bool_t check_final_patch_levels(unsigned int cpu)
368
0
{
369
0
    /*
370
0
     * Check the current patch levels on the cpu. If they are equal to
371
0
     * any of the 'final_levels', then we should not update the microcode
372
0
     * patch on the cpu as system will hang otherwise.
373
0
     */
374
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
375
0
    unsigned int i;
376
0
377
0
    if ( boot_cpu_data.x86 != 0x10 )
378
0
        return 0;
379
0
380
0
    for ( i = 0; i < ARRAY_SIZE(final_levels); i++ )
381
0
        if ( uci->cpu_sig.rev == final_levels[i] )
382
0
            return 1;
383
0
384
0
    return 0;
385
0
}
386
387
static int cpu_request_microcode(unsigned int cpu, const void *buf,
388
                                 size_t bufsize)
389
0
{
390
0
    struct microcode_amd *mc_amd, *mc_old;
391
0
    size_t offset = 0;
392
0
    size_t last_offset, applied_offset = 0;
393
0
    int error = 0, save_error = 1;
394
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
395
0
    unsigned int current_cpu_id;
396
0
    unsigned int equiv_cpu_id;
397
0
398
0
    /* We should bind the task to the CPU */
399
0
    BUG_ON(cpu != raw_smp_processor_id());
400
0
401
0
    current_cpu_id = cpuid_eax(0x00000001);
402
0
403
0
    if ( *(const uint32_t *)buf != UCODE_MAGIC )
404
0
    {
405
0
        printk(KERN_ERR "microcode: Wrong microcode patch file magic\n");
406
0
        error = -EINVAL;
407
0
        goto out;
408
0
    }
409
0
410
0
    if ( check_final_patch_levels(cpu) )
411
0
    {
412
0
        printk(XENLOG_INFO
413
0
               "microcode: Cannot update microcode patch on the cpu as we hit a final level\n");
414
0
        error = -EPERM;
415
0
        goto out;
416
0
    }
417
0
418
0
    mc_amd = xmalloc(struct microcode_amd);
419
0
    if ( !mc_amd )
420
0
    {
421
0
        printk(KERN_ERR "microcode: Cannot allocate memory for microcode patch\n");
422
0
        error = -ENOMEM;
423
0
        goto out;
424
0
    }
425
0
426
0
    /*
427
0
     * Multiple container file support:
428
0
     * 1. check if this container file has equiv_cpu_id match
429
0
     * 2. If not, fast-fwd to next container file
430
0
     */
431
0
    while ( offset < bufsize )
432
0
    {
433
0
        error = install_equiv_cpu_table(mc_amd, buf, &offset);
434
0
        if ( error )
435
0
        {
436
0
            printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
437
0
            break;
438
0
        }
439
0
440
0
        /*
441
0
         * Could happen as we advance 'offset' early
442
0
         * in install_equiv_cpu_table
443
0
         */
444
0
        if ( offset > bufsize )
445
0
        {
446
0
            printk(KERN_ERR "microcode: Microcode buffer overrun\n");
447
0
            error = -EINVAL;
448
0
            break;
449
0
        }
450
0
451
0
        if ( find_equiv_cpu_id(mc_amd->equiv_cpu_table, current_cpu_id,
452
0
                               &equiv_cpu_id) )
453
0
            break;
454
0
455
0
        error = container_fast_forward(buf, bufsize - offset, &offset);
456
0
        if ( error == -ENODATA )
457
0
        {
458
0
            ASSERT(offset == bufsize);
459
0
            break;
460
0
        }
461
0
        if ( error )
462
0
        {
463
0
            printk(KERN_ERR "microcode: CPU%d incorrect or corrupt container file\n"
464
0
                   "microcode: Failed to update patch level. "
465
0
                   "Current lvl:%#x\n", cpu, uci->cpu_sig.rev);
466
0
            break;
467
0
        }
468
0
    }
469
0
470
0
    if ( error )
471
0
    {
472
0
        xfree(mc_amd);
473
0
        goto out;
474
0
    }
475
0
476
0
    mc_old = uci->mc.mc_amd;
477
0
    /* implicitely validates uci->mc.mc_valid */
478
0
    uci->mc.mc_amd = mc_amd;
479
0
480
0
    /*
481
0
     * It's possible the data file has multiple matching ucode,
482
0
     * lets keep searching till the latest version
483
0
     */
484
0
    mc_amd->mpb = NULL;
485
0
    mc_amd->mpb_size = 0;
486
0
    last_offset = offset;
487
0
    while ( (error = get_ucode_from_buffer_amd(mc_amd, buf, bufsize,
488
0
                                               &offset)) == 0 )
489
0
    {
490
0
        if ( microcode_fits(mc_amd, cpu) )
491
0
        {
492
0
            error = apply_microcode(cpu);
493
0
            if ( error )
494
0
                break;
495
0
            applied_offset = last_offset;
496
0
        }
497
0
498
0
        last_offset = offset;
499
0
500
0
        if ( offset >= bufsize )
501
0
            break;
502
0
503
0
        /*
504
0
         * 1. Given a situation where multiple containers exist and correct
505
0
         *    patch lives on a container that is not the last container.
506
0
         * 2. We match equivalent ids using find_equiv_cpu_id() from the
507
0
         *    earlier while() (On this case, matches on earlier container
508
0
         *    file and we break)
509
0
         * 3. Proceed to while ( (error = get_ucode_from_buffer_amd(mc_amd,
510
0
         *                                  buf, bufsize,&offset)) == 0 )
511
0
         * 4. Find correct patch using microcode_fits() and apply the patch
512
0
         *    (Assume: apply_microcode() is successful)
513
0
         * 5. The while() loop from (3) continues to parse the binary as
514
0
         *    there is a subsequent container file, but...
515
0
         * 6. ...a correct patch can only be on one container and not on any
516
0
         *    subsequent ones. (Refer docs for more info) Therefore, we
517
0
         *    don't have to parse a subsequent container. So, we can abort
518
0
         *    the process here.
519
0
         * 7. This ensures that we retain a success value (= 0) to 'error'
520
0
         *    before if ( mpbuf->type != UCODE_UCODE_TYPE ) evaluates to
521
0
         *    false and returns -EINVAL.
522
0
         */
523
0
        if ( offset + SECTION_HDR_SIZE <= bufsize &&
524
0
             *(const uint32_t *)(buf + offset) == UCODE_MAGIC )
525
0
            break;
526
0
    }
527
0
528
0
    /* On success keep the microcode patch for
529
0
     * re-apply on resume.
530
0
     */
531
0
    if ( applied_offset )
532
0
    {
533
0
        save_error = get_ucode_from_buffer_amd(
534
0
            mc_amd, buf, bufsize, &applied_offset);
535
0
536
0
        if ( save_error )
537
0
            error = save_error;
538
0
    }
539
0
540
0
    if ( save_error )
541
0
    {
542
0
        xfree(mc_amd);
543
0
        uci->mc.mc_amd = mc_old;
544
0
    }
545
0
    else
546
0
        xfree(mc_old);
547
0
548
0
  out:
549
0
    svm_host_osvw_init();
550
0
551
0
    /*
552
0
     * In some cases we may return an error even if processor's microcode has
553
0
     * been updated. For example, the first patch in a container file is loaded
554
0
     * successfully but subsequent container file processing encounters a
555
0
     * failure.
556
0
     */
557
0
    return error;
558
0
}
559
560
static int microcode_resume_match(unsigned int cpu, const void *mc)
561
0
{
562
0
    struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
563
0
    struct microcode_amd *mc_amd = uci->mc.mc_amd;
564
0
    const struct microcode_amd *src = mc;
565
0
566
0
    if ( !microcode_fits(src, cpu) )
567
0
        return 0;
568
0
569
0
    if ( src != mc_amd )
570
0
    {
571
0
        if ( mc_amd )
572
0
        {
573
0
            xfree(mc_amd->equiv_cpu_table);
574
0
            xfree(mc_amd->mpb);
575
0
            xfree(mc_amd);
576
0
        }
577
0
578
0
        mc_amd = xmalloc(struct microcode_amd);
579
0
        uci->mc.mc_amd = mc_amd;
580
0
        if ( !mc_amd )
581
0
            return -ENOMEM;
582
0
        mc_amd->equiv_cpu_table = xmalloc_bytes(src->equiv_cpu_table_size);
583
0
        if ( !mc_amd->equiv_cpu_table )
584
0
            goto err1;
585
0
        mc_amd->mpb = xmalloc_bytes(src->mpb_size);
586
0
        if ( !mc_amd->mpb )
587
0
            goto err2;
588
0
589
0
        mc_amd->equiv_cpu_table_size = src->equiv_cpu_table_size;
590
0
        mc_amd->mpb_size = src->mpb_size;
591
0
        memcpy(mc_amd->mpb, src->mpb, src->mpb_size);
592
0
        memcpy(mc_amd->equiv_cpu_table, src->equiv_cpu_table,
593
0
               src->equiv_cpu_table_size);
594
0
    }
595
0
596
0
    return 1;
597
0
598
0
err2:
599
0
    xfree(mc_amd->equiv_cpu_table);
600
0
err1:
601
0
    xfree(mc_amd);
602
0
    uci->mc.mc_amd = NULL;
603
0
    return -ENOMEM;
604
0
}
605
606
static int start_update(void)
607
0
{
608
0
    /*
609
0
     * We assume here that svm_host_osvw_init() will be called on each cpu (from
610
0
     * cpu_request_microcode()).
611
0
     *
612
0
     * Note that if collect_cpu_info() returns an error then
613
0
     * cpu_request_microcode() will not invoked thus leaving OSVW bits not
614
0
     * updated. Currently though collect_cpu_info() will not fail on processors
615
0
     * supporting OSVW so we will not deal with this possibility.
616
0
     */
617
0
    svm_host_osvw_reset();
618
0
619
0
    return 0;
620
0
}
621
622
static const struct microcode_ops microcode_amd_ops = {
623
    .microcode_resume_match           = microcode_resume_match,
624
    .cpu_request_microcode            = cpu_request_microcode,
625
    .collect_cpu_info                 = collect_cpu_info,
626
    .apply_microcode                  = apply_microcode,
627
    .start_update                     = start_update,
628
};
629
630
int __init microcode_init_amd(void)
631
1
{
632
1
    if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
633
0
        microcode_ops = &microcode_amd_ops;
634
1
    return 0;
635
1
}