linux/arch/i386/kernel/microcode.c
<<
>>
Prefs
   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 *
   7 *      This driver allows to upgrade microcode on Intel processors
   8 *      belonging to IA-32 family - PentiumPro, Pentium II, 
   9 *      Pentium III, Xeon, Pentium 4, etc.
  10 *
  11 *      Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual, 
  12 *      Order Number 245472 or free download from:
  13 *              
  14 *      http://developer.intel.com/design/pentium4/manuals/245472.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 *      1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
  24 *              Initial release.
  25 *      1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
  26 *              Added read() support + cleanups.
  27 *      1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
  28 *              Added 'device trimming' support. open(O_WRONLY) zeroes
  29 *              and frees the saved copy of applied microcode.
  30 *      1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
  31 *              Made to use devfs (/dev/cpu/microcode) + cleanups.
  32 *      1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
  33 *              Added misc device support (now uses both devfs and misc).
  34 *              Added MICROCODE_IOCFREE ioctl to clear memory.
  35 *      1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
  36 *              Messages for error cases (non Intel & no suitable microcode).
  37 *      1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
  38 *              Removed ->release(). Removed exclusive open and status bitmap.
  39 *              Added microcode_rwsem to serialize read()/write()/ioctl().
  40 *              Removed global kernel lock usage.
  41 *      1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
  42 *              Write 0 to 0x8B msr and then cpuid before reading revision,
  43 *              so that it works even if there were no update done by the
  44 *              BIOS. Otherwise, reading from 0x8B gives junk (which happened
  45 *              to be 0 on my machine which is why it worked even when I
  46 *              disabled update by the BIOS)
  47 *              Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
  48 *      1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
  49 *                           Tigran Aivazian <tigran@veritas.com>
  50 *              Intel Pentium 4 processor support and bugfixes.
  51 *      1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
  52 *              Bugfix for HT (Hyper-Threading) enabled processors
  53 *              whereby processor resources are shared by all logical processors
  54 *              in a single CPU package.
  55 *      1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
  56 *              Tigran Aivazian <tigran@veritas.com>,
  57 *              Serialize updates as required on HT processors due to speculative
  58 *              nature of implementation.
  59 *      1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
  60 *              Fix the panic when writing zero-length microcode chunk.
  61 *      1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>, 
  62 *              Jun Nakajima <jun.nakajima@intel.com>
  63 *              Support for the microcode updates in the new format.
  64 *      1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
  65 *              Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
  66 *              because we no longer hold a copy of applied microcode 
  67 *              in kernel memory.
  68 *      1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
  69 *              Fix sigmatch() macro to handle old CPUs with pf == 0.
  70 *              Thanks to Stuart Swales for pointing out this bug.
  71 */
  72
  73//#define DEBUG /* pr_debug */
  74#include <linux/capability.h>
  75#include <linux/kernel.h>
  76#include <linux/init.h>
  77#include <linux/sched.h>
  78#include <linux/cpumask.h>
  79#include <linux/module.h>
  80#include <linux/slab.h>
  81#include <linux/vmalloc.h>
  82#include <linux/miscdevice.h>
  83#include <linux/spinlock.h>
  84#include <linux/mm.h>
  85#include <linux/mutex.h>
  86#include <linux/cpu.h>
  87#include <linux/firmware.h>
  88#include <linux/platform_device.h>
  89
  90#include <asm/msr.h>
  91#include <asm/uaccess.h>
  92#include <asm/processor.h>
  93
  94MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
  95MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
  96MODULE_LICENSE("GPL");
  97
  98#define MICROCODE_VERSION       "1.14a"
  99
 100#define DEFAULT_UCODE_DATASIZE  (2000)    /* 2000 bytes */
 101#define MC_HEADER_SIZE          (sizeof (microcode_header_t))     /* 48 bytes */
 102#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
 103#define EXT_HEADER_SIZE         (sizeof (struct extended_sigtable)) /* 20 bytes */
 104#define EXT_SIGNATURE_SIZE      (sizeof (struct extended_signature)) /* 12 bytes */
 105#define DWSIZE                  (sizeof (u32))
 106#define get_totalsize(mc) \
 107        (((microcode_t *)mc)->hdr.totalsize ? \
 108         ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
 109#define get_datasize(mc) \
 110        (((microcode_t *)mc)->hdr.datasize ? \
 111         ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
 112
 113#define sigmatch(s1, s2, p1, p2) \
 114        (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
 115
 116#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
 117
 118/* serialize access to the physical write to MSR 0x79 */
 119static DEFINE_SPINLOCK(microcode_update_lock);
 120
 121/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
 122static DEFINE_MUTEX(microcode_mutex);
 123
 124static struct ucode_cpu_info {
 125        int valid;
 126        unsigned int sig;
 127        unsigned int pf;
 128        unsigned int rev;
 129        microcode_t *mc;
 130} ucode_cpu_info[NR_CPUS];
 131
 132static void collect_cpu_info(int cpu_num)
 133{
 134        struct cpuinfo_x86 *c = cpu_data + cpu_num;
 135        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
 136        unsigned int val[2];
 137
 138        /* We should bind the task to the CPU */
 139        BUG_ON(raw_smp_processor_id() != cpu_num);
 140        uci->pf = uci->rev = 0;
 141        uci->mc = NULL;
 142        uci->valid = 1;
 143
 144        if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
 145                cpu_has(c, X86_FEATURE_IA64)) {
 146                printk(KERN_ERR "microcode: CPU%d not a capable Intel "
 147                        "processor\n", cpu_num);
 148                uci->valid = 0;
 149                return;
 150        }
 151
 152        uci->sig = cpuid_eax(0x00000001);
 153
 154        if ((c->x86_model >= 5) || (c->x86 > 6)) {
 155                /* get processor flags from MSR 0x17 */
 156                rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
 157                uci->pf = 1 << ((val[1] >> 18) & 7);
 158        }
 159
 160        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 161        /* see notes above for revision 1.07.  Apparent chip bug */
 162        sync_core();
 163        /* get the current revision from MSR 0x8B */
 164        rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
 165        pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
 166                        uci->sig, uci->pf, uci->rev);
 167}
 168
 169static inline int microcode_update_match(int cpu_num,
 170        microcode_header_t *mc_header, int sig, int pf)
 171{
 172        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
 173
 174        if (!sigmatch(sig, uci->sig, pf, uci->pf)
 175                || mc_header->rev <= uci->rev)
 176                return 0;
 177        return 1;
 178}
 179
 180static int microcode_sanity_check(void *mc)
 181{
 182        microcode_header_t *mc_header = mc;
 183        struct extended_sigtable *ext_header = NULL;
 184        struct extended_signature *ext_sig;
 185        unsigned long total_size, data_size, ext_table_size;
 186        int sum, orig_sum, ext_sigcount = 0, i;
 187
 188        total_size = get_totalsize(mc_header);
 189        data_size = get_datasize(mc_header);
 190        if (data_size + MC_HEADER_SIZE > total_size) {
 191                printk(KERN_ERR "microcode: error! "
 192                        "Bad data size in microcode data file\n");
 193                return -EINVAL;
 194        }
 195
 196        if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
 197                printk(KERN_ERR "microcode: error! "
 198                        "Unknown microcode update format\n");
 199                return -EINVAL;
 200        }
 201        ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
 202        if (ext_table_size) {
 203                if ((ext_table_size < EXT_HEADER_SIZE)
 204                 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
 205                        printk(KERN_ERR "microcode: error! "
 206                                "Small exttable size in microcode data file\n");
 207                        return -EINVAL;
 208                }
 209                ext_header = mc + MC_HEADER_SIZE + data_size;
 210                if (ext_table_size != exttable_size(ext_header)) {
 211                        printk(KERN_ERR "microcode: error! "
 212                                "Bad exttable size in microcode data file\n");
 213                        return -EFAULT;
 214                }
 215                ext_sigcount = ext_header->count;
 216        }
 217
 218        /* check extended table checksum */
 219        if (ext_table_size) {
 220                int ext_table_sum = 0;
 221                int *ext_tablep = (int *)ext_header;
 222
 223                i = ext_table_size / DWSIZE;
 224                while (i--)
 225                        ext_table_sum += ext_tablep[i];
 226                if (ext_table_sum) {
 227                        printk(KERN_WARNING "microcode: aborting, "
 228                                "bad extended signature table checksum\n");
 229                        return -EINVAL;
 230                }
 231        }
 232
 233        /* calculate the checksum */
 234        orig_sum = 0;
 235        i = (MC_HEADER_SIZE + data_size) / DWSIZE;
 236        while (i--)
 237                orig_sum += ((int *)mc)[i];
 238        if (orig_sum) {
 239                printk(KERN_ERR "microcode: aborting, bad checksum\n");
 240                return -EINVAL;
 241        }
 242        if (!ext_table_size)
 243                return 0;
 244        /* check extended signature checksum */
 245        for (i = 0; i < ext_sigcount; i++) {
 246                ext_sig = (struct extended_signature *)((void *)ext_header
 247                        + EXT_HEADER_SIZE + EXT_SIGNATURE_SIZE * i);
 248                sum = orig_sum
 249                        - (mc_header->sig + mc_header->pf + mc_header->cksum)
 250                        + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
 251                if (sum) {
 252                        printk(KERN_ERR "microcode: aborting, bad checksum\n");
 253                        return -EINVAL;
 254                }
 255        }
 256        return 0;
 257}
 258
 259/*
 260 * return 0 - no update found
 261 * return 1 - found update
 262 * return < 0 - error
 263 */
 264static int get_maching_microcode(void *mc, int cpu)
 265{
 266        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 267        microcode_header_t *mc_header = mc;
 268        struct extended_sigtable *ext_header;
 269        unsigned long total_size = get_totalsize(mc_header);
 270        int ext_sigcount, i;
 271        struct extended_signature *ext_sig;
 272        void *new_mc;
 273
 274        if (microcode_update_match(cpu, mc_header,
 275                        mc_header->sig, mc_header->pf))
 276                goto find;
 277
 278        if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
 279                return 0;
 280
 281        ext_header = (struct extended_sigtable *)(mc +
 282                        get_datasize(mc_header) + MC_HEADER_SIZE);
 283        ext_sigcount = ext_header->count;
 284        ext_sig = (struct extended_signature *)((void *)ext_header
 285                        + EXT_HEADER_SIZE);
 286        for (i = 0; i < ext_sigcount; i++) {
 287                if (microcode_update_match(cpu, mc_header,
 288                                ext_sig->sig, ext_sig->pf))
 289                        goto find;
 290                ext_sig++;
 291        }
 292        return 0;
 293find:
 294        pr_debug("microcode: CPU %d found a matching microcode update with"
 295                " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
 296        new_mc = vmalloc(total_size);
 297        if (!new_mc) {
 298                printk(KERN_ERR "microcode: error! Can not allocate memory\n");
 299                return -ENOMEM;
 300        }
 301
 302        /* free previous update file */
 303        vfree(uci->mc);
 304
 305        memcpy(new_mc, mc, total_size);
 306        uci->mc = new_mc;
 307        return 1;
 308}
 309
 310static void apply_microcode(int cpu)
 311{
 312        unsigned long flags;
 313        unsigned int val[2];
 314        int cpu_num = raw_smp_processor_id();
 315        struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
 316
 317        /* We should bind the task to the CPU */
 318        BUG_ON(cpu_num != cpu);
 319
 320        if (uci->mc == NULL)
 321                return;
 322
 323        /* serialize access to the physical write to MSR 0x79 */
 324        spin_lock_irqsave(&microcode_update_lock, flags);          
 325
 326        /* write microcode via MSR 0x79 */
 327        wrmsr(MSR_IA32_UCODE_WRITE,
 328                (unsigned long) uci->mc->bits, 
 329                (unsigned long) uci->mc->bits >> 16 >> 16);
 330        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 331
 332        /* see notes above for revision 1.07.  Apparent chip bug */
 333        sync_core();
 334
 335        /* get the current revision from MSR 0x8B */
 336        rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
 337
 338        spin_unlock_irqrestore(&microcode_update_lock, flags);
 339        if (val[1] != uci->mc->hdr.rev) {
 340                printk(KERN_ERR "microcode: CPU%d updated from revision "
 341                        "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
 342                return;
 343        }
 344        pr_debug("microcode: CPU%d updated from revision "
 345               "0x%x to 0x%x, date = %08x \n", 
 346               cpu_num, uci->rev, val[1], uci->mc->hdr.date);
 347        uci->rev = val[1];
 348}
 349
 350#ifdef CONFIG_MICROCODE_OLD_INTERFACE
 351static void __user *user_buffer;        /* user area microcode data buffer */
 352static unsigned int user_buffer_size;   /* it's size */
 353
 354static long get_next_ucode(void **mc, long offset)
 355{
 356        microcode_header_t mc_header;
 357        unsigned long total_size;
 358
 359        /* No more data */
 360        if (offset >= user_buffer_size)
 361                return 0;
 362        if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
 363                printk(KERN_ERR "microcode: error! Can not read user data\n");
 364                return -EFAULT;
 365        }
 366        total_size = get_totalsize(&mc_header);
 367        if (offset + total_size > user_buffer_size) {
 368                printk(KERN_ERR "microcode: error! Bad total size in microcode "
 369                                "data file\n");
 370                return -EINVAL;
 371        }
 372        *mc = vmalloc(total_size);
 373        if (!*mc)
 374                return -ENOMEM;
 375        if (copy_from_user(*mc, user_buffer + offset, total_size)) {
 376                printk(KERN_ERR "microcode: error! Can not read user data\n");
 377                vfree(*mc);
 378                return -EFAULT;
 379        }
 380        return offset + total_size;
 381}
 382
 383static int do_microcode_update (void)
 384{
 385        long cursor = 0;
 386        int error = 0;
 387        void *new_mc = NULL;
 388        int cpu;
 389        cpumask_t old;
 390
 391        old = current->cpus_allowed;
 392
 393        while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
 394                error = microcode_sanity_check(new_mc);
 395                if (error)
 396                        goto out;
 397                /*
 398                 * It's possible the data file has multiple matching ucode,
 399                 * lets keep searching till the latest version
 400                 */
 401                for_each_online_cpu(cpu) {
 402                        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 403
 404                        if (!uci->valid)
 405                                continue;
 406                        set_cpus_allowed(current, cpumask_of_cpu(cpu));
 407                        error = get_maching_microcode(new_mc, cpu);
 408                        if (error < 0)
 409                                goto out;
 410                        if (error == 1)
 411                                apply_microcode(cpu);
 412                }
 413                vfree(new_mc);
 414        }
 415out:
 416        if (cursor > 0)
 417                vfree(new_mc);
 418        if (cursor < 0)
 419                error = cursor;
 420        set_cpus_allowed(current, old);
 421        return error;
 422}
 423
 424static int microcode_open (struct inode *unused1, struct file *unused2)
 425{
 426        return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 427}
 428
 429static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
 430{
 431        ssize_t ret;
 432
 433        if ((len >> PAGE_SHIFT) > num_physpages) {
 434                printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
 435                return -EINVAL;
 436        }
 437
 438        lock_cpu_hotplug();
 439        mutex_lock(&microcode_mutex);
 440
 441        user_buffer = (void __user *) buf;
 442        user_buffer_size = (int) len;
 443
 444        ret = do_microcode_update();
 445        if (!ret)
 446                ret = (ssize_t)len;
 447
 448        mutex_unlock(&microcode_mutex);
 449        unlock_cpu_hotplug();
 450
 451        return ret;
 452}
 453
 454static const struct file_operations microcode_fops = {
 455        .owner          = THIS_MODULE,
 456        .write          = microcode_write,
 457        .open           = microcode_open,
 458};
 459
 460static struct miscdevice microcode_dev = {
 461        .minor          = MICROCODE_MINOR,
 462        .name           = "microcode",
 463        .fops           = &microcode_fops,
 464};
 465
 466static int __init microcode_dev_init (void)
 467{
 468        int error;
 469
 470        error = misc_register(&microcode_dev);
 471        if (error) {
 472                printk(KERN_ERR
 473                        "microcode: can't misc_register on minor=%d\n",
 474                        MICROCODE_MINOR);
 475                return error;
 476        }
 477
 478        return 0;
 479}
 480
 481static void microcode_dev_exit (void)
 482{
 483        misc_deregister(&microcode_dev);
 484}
 485
 486MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
 487#else
 488#define microcode_dev_init() 0
 489#define microcode_dev_exit() do { } while(0)
 490#endif
 491
 492static long get_next_ucode_from_buffer(void **mc, void *buf,
 493        unsigned long size, long offset)
 494{
 495        microcode_header_t *mc_header;
 496        unsigned long total_size;
 497
 498        /* No more data */
 499        if (offset >= size)
 500                return 0;
 501        mc_header = (microcode_header_t *)(buf + offset);
 502        total_size = get_totalsize(mc_header);
 503
 504        if (offset + total_size > size) {
 505                printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
 506                return -EINVAL;
 507        }
 508
 509        *mc = vmalloc(total_size);
 510        if (!*mc) {
 511                printk(KERN_ERR "microcode: error! Can not allocate memory\n");
 512                return -ENOMEM;
 513        }
 514        memcpy(*mc, buf + offset, total_size);
 515        return offset + total_size;
 516}
 517
 518/* fake device for request_firmware */
 519static struct platform_device *microcode_pdev;
 520
 521static int cpu_request_microcode(int cpu)
 522{
 523        char name[30];
 524        struct cpuinfo_x86 *c = cpu_data + cpu;
 525        const struct firmware *firmware;
 526        void *buf;
 527        unsigned long size;
 528        long offset = 0;
 529        int error;
 530        void *mc;
 531
 532        /* We should bind the task to the CPU */
 533        BUG_ON(cpu != raw_smp_processor_id());
 534        sprintf(name,"intel-ucode/%02x-%02x-%02x",
 535                c->x86, c->x86_model, c->x86_mask);
 536        error = request_firmware(&firmware, name, &microcode_pdev->dev);
 537        if (error) {
 538                pr_debug("ucode data file %s load failed\n", name);
 539                return error;
 540        }
 541        buf = (void *)firmware->data;
 542        size = firmware->size;
 543        while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
 544                        > 0) {
 545                error = microcode_sanity_check(mc);
 546                if (error)
 547                        break;
 548                error = get_maching_microcode(mc, cpu);
 549                if (error < 0)
 550                        break;
 551                /*
 552                 * It's possible the data file has multiple matching ucode,
 553                 * lets keep searching till the latest version
 554                 */
 555                if (error == 1) {
 556                        apply_microcode(cpu);
 557                        error = 0;
 558                }
 559                vfree(mc);
 560        }
 561        if (offset > 0)
 562                vfree(mc);
 563        if (offset < 0)
 564                error = offset;
 565        release_firmware(firmware);
 566
 567        return error;
 568}
 569
 570static int apply_microcode_check_cpu(int cpu)
 571{
 572        struct cpuinfo_x86 *c = cpu_data + cpu;
 573        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 574        cpumask_t old;
 575        unsigned int val[2];
 576        int err = 0;
 577
 578        /* Check if the microcode is available */
 579        if (!uci->mc)
 580                return 0;
 581
 582        old = current->cpus_allowed;
 583        set_cpus_allowed(current, cpumask_of_cpu(cpu));
 584
 585        /* Check if the microcode we have in memory matches the CPU */
 586        if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
 587            cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
 588                err = -EINVAL;
 589
 590        if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
 591                /* get processor flags from MSR 0x17 */
 592                rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
 593                if (uci->pf != (1 << ((val[1] >> 18) & 7)))
 594                        err = -EINVAL;
 595        }
 596
 597        if (!err) {
 598                wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 599                /* see notes above for revision 1.07.  Apparent chip bug */
 600                sync_core();
 601                /* get the current revision from MSR 0x8B */
 602                rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
 603                if (uci->rev != val[1])
 604                        err = -EINVAL;
 605        }
 606
 607        if (!err)
 608                apply_microcode(cpu);
 609        else
 610                printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
 611                        " sig=0x%x, pf=0x%x, rev=0x%x\n",
 612                        cpu, uci->sig, uci->pf, uci->rev);
 613
 614        set_cpus_allowed(current, old);
 615        return err;
 616}
 617
 618static void microcode_init_cpu(int cpu, int resume)
 619{
 620        cpumask_t old;
 621        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 622
 623        old = current->cpus_allowed;
 624
 625        set_cpus_allowed(current, cpumask_of_cpu(cpu));
 626        mutex_lock(&microcode_mutex);
 627        collect_cpu_info(cpu);
 628        if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
 629                cpu_request_microcode(cpu);
 630        mutex_unlock(&microcode_mutex);
 631        set_cpus_allowed(current, old);
 632}
 633
 634static void microcode_fini_cpu(int cpu)
 635{
 636        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 637
 638        mutex_lock(&microcode_mutex);
 639        uci->valid = 0;
 640        vfree(uci->mc);
 641        uci->mc = NULL;
 642        mutex_unlock(&microcode_mutex);
 643}
 644
 645static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz)
 646{
 647        struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
 648        char *end;
 649        unsigned long val = simple_strtoul(buf, &end, 0);
 650        int err = 0;
 651        int cpu = dev->id;
 652
 653        if (end == buf)
 654                return -EINVAL;
 655        if (val == 1) {
 656                cpumask_t old;
 657
 658                old = current->cpus_allowed;
 659
 660                lock_cpu_hotplug();
 661                set_cpus_allowed(current, cpumask_of_cpu(cpu));
 662
 663                mutex_lock(&microcode_mutex);
 664                if (uci->valid)
 665                        err = cpu_request_microcode(cpu);
 666                mutex_unlock(&microcode_mutex);
 667                unlock_cpu_hotplug();
 668                set_cpus_allowed(current, old);
 669        }
 670        if (err)
 671                return err;
 672        return sz;
 673}
 674
 675static ssize_t version_show(struct sys_device *dev, char *buf)
 676{
 677        struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
 678
 679        return sprintf(buf, "0x%x\n", uci->rev);
 680}
 681
 682static ssize_t pf_show(struct sys_device *dev, char *buf)
 683{
 684        struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
 685
 686        return sprintf(buf, "0x%x\n", uci->pf);
 687}
 688
 689static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
 690static SYSDEV_ATTR(version, 0400, version_show, NULL);
 691static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
 692
 693static struct attribute *mc_default_attrs[] = {
 694        &attr_reload.attr,
 695        &attr_version.attr,
 696        &attr_processor_flags.attr,
 697        NULL
 698};
 699
 700static struct attribute_group mc_attr_group = {
 701        .attrs = mc_default_attrs,
 702        .name = "microcode",
 703};
 704
 705static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
 706{
 707        int err, cpu = sys_dev->id;
 708        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
 709
 710        if (!cpu_online(cpu))
 711                return 0;
 712
 713        pr_debug("Microcode:CPU %d added\n", cpu);
 714        memset(uci, 0, sizeof(*uci));
 715
 716        err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
 717        if (err)
 718                return err;
 719
 720        microcode_init_cpu(cpu, resume);
 721
 722        return 0;
 723}
 724
 725static int mc_sysdev_add(struct sys_device *sys_dev)
 726{
 727        return __mc_sysdev_add(sys_dev, 0);
 728}
 729
 730static int mc_sysdev_remove(struct sys_device *sys_dev)
 731{
 732        int cpu = sys_dev->id;
 733
 734        if (!cpu_online(cpu))
 735                return 0;
 736
 737        pr_debug("Microcode:CPU %d removed\n", cpu);
 738        microcode_fini_cpu(cpu);
 739        sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
 740        return 0;
 741}
 742
 743static int mc_sysdev_resume(struct sys_device *dev)
 744{
 745        int cpu = dev->id;
 746
 747        if (!cpu_online(cpu))
 748                return 0;
 749        pr_debug("Microcode:CPU %d resumed\n", cpu);
 750        /* only CPU 0 will apply ucode here */
 751        apply_microcode(0);
 752        return 0;
 753}
 754
 755static struct sysdev_driver mc_sysdev_driver = {
 756        .add = mc_sysdev_add,
 757        .remove = mc_sysdev_remove,
 758        .resume = mc_sysdev_resume,
 759};
 760
 761static __cpuinit int
 762mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
 763{
 764        unsigned int cpu = (unsigned long)hcpu;
 765        struct sys_device *sys_dev;
 766
 767        sys_dev = get_cpu_sysdev(cpu);
 768        switch (action) {
 769        case CPU_UP_CANCELED_FROZEN:
 770                /* The CPU refused to come up during a system resume */
 771                microcode_fini_cpu(cpu);
 772                break;
 773        case CPU_ONLINE:
 774        case CPU_DOWN_FAILED:
 775                mc_sysdev_add(sys_dev);
 776                break;
 777        case CPU_ONLINE_FROZEN:
 778                /* System-wide resume is in progress, try to apply microcode */
 779                if (apply_microcode_check_cpu(cpu)) {
 780                        /* The application of microcode failed */
 781                        microcode_fini_cpu(cpu);
 782                        __mc_sysdev_add(sys_dev, 1);
 783                        break;
 784                }
 785        case CPU_DOWN_FAILED_FROZEN:
 786                if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
 787                        printk(KERN_ERR "Microcode: Failed to create the sysfs "
 788                                "group for CPU%d\n", cpu);
 789                break;
 790        case CPU_DOWN_PREPARE:
 791                mc_sysdev_remove(sys_dev);
 792                break;
 793        case CPU_DOWN_PREPARE_FROZEN:
 794                /* Suspend is in progress, only remove the interface */
 795                sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
 796                break;
 797        }
 798        return NOTIFY_OK;
 799}
 800
 801static struct notifier_block __cpuinitdata mc_cpu_notifier = {
 802        .notifier_call = mc_cpu_callback,
 803};
 804
 805static int __init microcode_init (void)
 806{
 807        int error;
 808
 809        error = microcode_dev_init();
 810        if (error)
 811                return error;
 812        microcode_pdev = platform_device_register_simple("microcode", -1,
 813                                                         NULL, 0);
 814        if (IS_ERR(microcode_pdev)) {
 815                microcode_dev_exit();
 816                return PTR_ERR(microcode_pdev);
 817        }
 818
 819        lock_cpu_hotplug();
 820        error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
 821        unlock_cpu_hotplug();
 822        if (error) {
 823                microcode_dev_exit();
 824                platform_device_unregister(microcode_pdev);
 825                return error;
 826        }
 827
 828        register_hotcpu_notifier(&mc_cpu_notifier);
 829
 830        printk(KERN_INFO 
 831                "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
 832        return 0;
 833}
 834
 835static void __exit microcode_exit (void)
 836{
 837        microcode_dev_exit();
 838
 839        unregister_hotcpu_notifier(&mc_cpu_notifier);
 840
 841        lock_cpu_hotplug();
 842        sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
 843        unlock_cpu_hotplug();
 844
 845        platform_device_unregister(microcode_pdev);
 846}
 847
 848module_init(microcode_init)
 849module_exit(microcode_exit)
 850
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.