linux-old/arch/i386/kernel/microcode.c
<<
>>
Prefs
   1/*
   2 *      Intel CPU Microcode Update driver for Linux
   3 *
   4 *      Copyright (C) 2000 Tigran Aivazian
   5 *
   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.10 of Volume III, Intel Pentium 4 Manual, 
  11 *      Order Number 245472 or free download from:
  12 *              
  13 *      http://developer.intel.com/design/pentium4/manuals/245472.htm
  14 *
  15 *      For more information, go to http://www.urbanmyth.org/microcode
  16 *
  17 *      This program is free software; you can redistribute it and/or
  18 *      modify it under the terms of the GNU General Public License
  19 *      as published by the Free Software Foundation; either version
  20 *      2 of the License, or (at your option) any later version.
  21 *
  22 *      1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
  23 *              Initial release.
  24 *      1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
  25 *              Added read() support + cleanups.
  26 *      1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
  27 *              Added 'device trimming' support. open(O_WRONLY) zeroes
  28 *              and frees the saved copy of applied microcode.
  29 *      1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
  30 *              Made to use devfs (/dev/cpu/microcode) + cleanups.
  31 *      1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
  32 *              Added misc device support (now uses both devfs and misc).
  33 *              Added MICROCODE_IOCFREE ioctl to clear memory.
  34 *      1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
  35 *              Messages for error cases (non intel & no suitable microcode).
  36 *      1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
  37 *              Removed ->release(). Removed exclusive open and status bitmap.
  38 *              Added microcode_rwsem to serialize read()/write()/ioctl().
  39 *              Removed global kernel lock usage.
  40 *      1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
  41 *              Write 0 to 0x8B msr and then cpuid before reading revision,
  42 *              so that it works even if there were no update done by the
  43 *              BIOS. Otherwise, reading from 0x8B gives junk (which happened
  44 *              to be 0 on my machine which is why it worked even when I
  45 *              disabled update by the BIOS)
  46 *              Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
  47 *      1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
  48 *                           Tigran Aivazian <tigran@veritas.com>
  49 *              Intel Pentium 4 processor support and bugfixes.
  50 *      1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
  51 *              Bugfix for HT (Hyper-Threading) enabled processors
  52 *              whereby processor resources are shared by all logical processors
  53 *              in a single CPU package.
  54 *      1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
  55 *              Tigran Aivazian <tigran@veritas.com>,
  56 *              Serialize updates as required on HT processors due to speculative
  57 *              nature of implementation.
  58 *      1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
  59 *              Fix the panic when writing zero-length microcode chunk.
  60 */
  61
  62#include <linux/init.h>
  63#include <linux/sched.h>
  64#include <linux/module.h>
  65#include <linux/slab.h>
  66#include <linux/vmalloc.h>
  67#include <linux/miscdevice.h>
  68#include <linux/devfs_fs_kernel.h>
  69#include <linux/spinlock.h>
  70
  71#include <asm/msr.h>
  72#include <asm/uaccess.h>
  73#include <asm/processor.h>
  74
  75
  76static spinlock_t microcode_update_lock = SPIN_LOCK_UNLOCKED;
  77
  78#define MICROCODE_VERSION       "1.11"
  79
  80MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
  81MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
  82MODULE_LICENSE("GPL");
  83EXPORT_NO_SYMBOLS;
  84
  85#define MICRO_DEBUG 0
  86
  87#if MICRO_DEBUG
  88#define printf(x...) printk(##x)
  89#else
  90#define printf(x...)
  91#endif
  92
  93/* VFS interface */
  94static int microcode_open(struct inode *, struct file *);
  95static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
  96static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *);
  97static int microcode_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
  98
  99static int do_microcode_update(void);
 100static void do_update_one(void *);
 101
 102/* read()/write()/ioctl() are serialized on this */
 103static DECLARE_RWSEM(microcode_rwsem);
 104
 105static struct microcode *microcode; /* array of 2048byte microcode blocks */
 106static unsigned int microcode_num;  /* number of chunks in microcode */
 107static char *mc_applied;            /* array of applied microcode blocks */
 108static unsigned int mc_fsize;       /* file size of /dev/cpu/microcode */
 109
 110/* we share file_operations between misc and devfs mechanisms */
 111static struct file_operations microcode_fops = {
 112        owner:          THIS_MODULE,
 113        read:           microcode_read,
 114        write:          microcode_write,
 115        ioctl:          microcode_ioctl,
 116        open:           microcode_open,
 117};
 118
 119static struct miscdevice microcode_dev = {
 120        minor: MICROCODE_MINOR,
 121        name:   "microcode",
 122        fops:   &microcode_fops,
 123};
 124
 125static devfs_handle_t devfs_handle;
 126
 127static int __init microcode_init(void)
 128{
 129        int error;
 130
 131        error = misc_register(&microcode_dev);
 132        if (error)
 133                printk(KERN_WARNING 
 134                        "microcode: can't misc_register on minor=%d\n",
 135                        MICROCODE_MINOR);
 136
 137        devfs_handle = devfs_register(NULL, "cpu/microcode",
 138                        DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR, 
 139                        &microcode_fops, NULL);
 140        if (devfs_handle == NULL && error) {
 141                printk(KERN_ERR "microcode: failed to devfs_register()\n");
 142                goto out;
 143        }
 144        error = 0;
 145        printk(KERN_INFO 
 146                "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n", 
 147                MICROCODE_VERSION);
 148
 149out:
 150        return error;
 151}
 152
 153static void __exit microcode_exit(void)
 154{
 155        misc_deregister(&microcode_dev);
 156        devfs_unregister(devfs_handle);
 157        if (mc_applied)
 158                kfree(mc_applied);
 159        printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n", 
 160                        MICROCODE_VERSION);
 161}
 162
 163module_init(microcode_init)
 164module_exit(microcode_exit)
 165
 166static int microcode_open(struct inode *unused1, struct file *unused2)
 167{
 168        return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 169}
 170
 171/*
 172 * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
 173 * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
 174 */
 175struct update_req {
 176        int err;
 177        int slot;
 178} update_req[NR_CPUS];
 179
 180static int do_microcode_update(void)
 181{
 182        int i, error = 0, err;
 183        struct microcode *m;
 184
 185        if (smp_call_function(do_update_one, NULL, 1, 1) != 0) {
 186                printk(KERN_ERR "microcode: IPI timeout, giving up\n");
 187                return -EIO;
 188        }
 189        do_update_one(NULL);
 190
 191        for (i=0; i<smp_num_cpus; i++) {
 192                err = update_req[i].err;
 193                error += err;
 194                if (!err) {
 195                        m = (struct microcode *)mc_applied + i;
 196                        memcpy(m, &microcode[update_req[i].slot], sizeof(struct microcode));
 197                }
 198        }
 199        return error;
 200}
 201
 202static void do_update_one(void *unused)
 203{
 204        int cpu_num = smp_processor_id();
 205        struct cpuinfo_x86 *c = cpu_data + cpu_num;
 206        struct update_req *req = update_req + cpu_num;
 207        unsigned int pf = 0, val[2], rev, sig;
 208        unsigned long flags;
 209        int i;
 210
 211        req->err = 1; /* assume update will fail on this cpu */
 212
 213        if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
 214                test_bit(X86_FEATURE_IA64, &c->x86_capability)){
 215                printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
 216                return;
 217        }
 218
 219        sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
 220
 221        if ((c->x86_model >= 5) || (c->x86 > 6)) {
 222                /* get processor flags from MSR 0x17 */
 223                rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
 224                pf = 1 << ((val[1] >> 18) & 7);
 225        }
 226
 227        for (i=0; i<microcode_num; i++)
 228                if (microcode[i].sig == sig && microcode[i].pf == pf &&
 229                    microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
 230                        int sum = 0;
 231                        struct microcode *m = &microcode[i];
 232                        unsigned int *sump = (unsigned int *)(m+1);
 233
 234                        printf("Microcode\n");
 235                        printf("   Header Revision %d\n",microcode[i].hdrver);
 236                        printf("   Date %x/%x/%x\n",
 237                                ((microcode[i].date >> 24 ) & 0xff),
 238                                ((microcode[i].date >> 16 ) & 0xff),
 239                                (microcode[i].date & 0xFFFF));
 240                        printf("   Type %x Family %x Model %x Stepping %x\n",
 241                                ((microcode[i].sig >> 12) & 0x3),
 242                                ((microcode[i].sig >> 8) & 0xf),
 243                                ((microcode[i].sig >> 4) & 0xf),
 244                                ((microcode[i].sig & 0xf)));
 245                        printf("   Checksum %x\n",microcode[i].cksum);
 246                        printf("   Loader Revision %x\n",microcode[i].ldrver);
 247                        printf("   Processor Flags %x\n\n",microcode[i].pf);
 248
 249                        req->slot = i;
 250
 251                        /* serialize access to update decision */
 252                        spin_lock_irqsave(&microcode_update_lock, flags);          
 253
 254                        /* trick, to work even if there was no prior update by the BIOS */
 255                        wrmsr(MSR_IA32_UCODE_REV, 0, 0);
 256                        __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
 257
 258                        /* get current (on-cpu) revision into rev (ignore val[0]) */
 259                        rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
 260                        
 261                        if (microcode[i].rev < rev) {
 262                                spin_unlock_irqrestore(&microcode_update_lock, flags);
 263                                printk(KERN_ERR 
 264                                       "microcode: CPU%d not 'upgrading' to earlier revision"
 265                                       " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
 266                                return;
 267                        } else if (microcode[i].rev == rev) {
 268                                /* notify the caller of success on this cpu */
 269                                req->err = 0;
 270                                spin_unlock_irqrestore(&microcode_update_lock, flags);
 271                                printk(KERN_ERR 
 272                                        "microcode: CPU%d already at revision"
 273                                        " %d (current=%d)\n", cpu_num, microcode[i].rev, rev);
 274                                return;
 275                        }
 276
 277                        /* Verify the checksum */
 278                        while (--sump >= (unsigned int *)m)
 279                                sum += *sump;
 280                        if (sum != 0) {
 281                                req->err = 1;
 282                                spin_unlock_irqrestore(&microcode_update_lock, flags);
 283                                printk(KERN_ERR "microcode: CPU%d aborting, "
 284                                       "bad checksum\n", cpu_num);
 285                                return;
 286                        }
 287                        
 288                        /* write microcode via MSR 0x79 */
 289                        wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
 290
 291                        /* serialize */
 292                        __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
 293
 294                        /* get the current revision from MSR 0x8B */
 295                        rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
 296
 297                        /* notify the caller of success on this cpu */
 298                        req->err = 0;
 299                        spin_unlock_irqrestore(&microcode_update_lock, flags);
 300                        printk(KERN_INFO "microcode: CPU%d updated from revision "
 301                               "%d to %d, date=%08x\n", 
 302                               cpu_num, rev, val[1], microcode[i].date);
 303                        return;
 304                }
 305        
 306        printk(KERN_ERR
 307               "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n", 
 308               cpu_num, sig, pf);
 309}
 310
 311
 312static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
 313{
 314        ssize_t ret = 0;
 315
 316        down_read(&microcode_rwsem);
 317        if (*ppos >= mc_fsize)
 318                goto out;
 319        if (*ppos + len > mc_fsize)
 320                len = mc_fsize - *ppos;
 321        ret = -EFAULT;
 322        if (copy_to_user(buf, mc_applied + *ppos, len))
 323                goto out;
 324        *ppos += len;
 325        ret = len;
 326out:
 327        up_read(&microcode_rwsem);
 328        return ret;
 329}
 330
 331static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
 332{
 333        ssize_t ret;
 334
 335        if (!len || len % sizeof(struct microcode) != 0) {
 336                printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", 
 337                        sizeof(struct microcode));
 338                return -EINVAL;
 339        }
 340        if ((len >> PAGE_SHIFT) > num_physpages) {
 341                printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
 342                return -EINVAL;
 343        }
 344        down_write(&microcode_rwsem);
 345        if (!mc_applied) {
 346                mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
 347                                GFP_KERNEL);
 348                if (!mc_applied) {
 349                        up_write(&microcode_rwsem);
 350                        printk(KERN_ERR "microcode: out of memory for saved microcode\n");
 351                        return -ENOMEM;
 352                }
 353        }
 354        
 355        microcode_num = len/sizeof(struct microcode);
 356        microcode = vmalloc(len);
 357        if (!microcode) {
 358                ret = -ENOMEM;
 359                goto out_unlock;
 360        }
 361
 362        if (copy_from_user(microcode, buf, len)) {
 363                ret = -EFAULT;
 364                goto out_fsize;
 365        }
 366
 367        if(do_microcode_update()) {
 368                ret = -EIO;
 369                goto out_fsize;
 370        } else {
 371                mc_fsize = smp_num_cpus * sizeof(struct microcode);
 372                ret = (ssize_t)len;
 373        }
 374out_fsize:
 375        devfs_set_file_size(devfs_handle, mc_fsize);
 376        vfree(microcode);
 377out_unlock:
 378        up_write(&microcode_rwsem);
 379        return ret;
 380}
 381
 382static int microcode_ioctl(struct inode *inode, struct file *file, 
 383                unsigned int cmd, unsigned long arg)
 384{
 385        switch(cmd) {
 386                case MICROCODE_IOCFREE:
 387                        down_write(&microcode_rwsem);
 388                        if (mc_applied) {
 389                                int bytes = smp_num_cpus * sizeof(struct microcode);
 390
 391                                devfs_set_file_size(devfs_handle, 0);
 392                                kfree(mc_applied);
 393                                mc_applied = NULL;
 394                                printk(KERN_INFO "microcode: freed %d bytes\n", bytes);
 395                                mc_fsize = 0;
 396                                up_write(&microcode_rwsem);
 397                                return 0;
 398                        }
 399                        up_write(&microcode_rwsem);
 400                        return -ENODATA;
 401
 402                default:
 403                        printk(KERN_ERR "microcode: unknown ioctl cmd=%d\n", cmd);
 404                        return -EINVAL;
 405        }
 406        return -EINVAL;
 407}
 408
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.