Merge to Fedora kernel-2.6.18-1.2255_FC5-vs2.0.2.2-rc9 patched with stable patch...
[linux-2.6.git] / arch / i386 / kernel / microcode-xen.c
1 /*
2  *      Intel CPU Microcode Update Driver for Linux
3  *
4  *      Copyright (C) 2000-2004 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
23 //#define DEBUG /* pr_debug */
24 #include <linux/capability.h>
25 #include <linux/kernel.h>
26 #include <linux/init.h>
27 #include <linux/sched.h>
28 #include <linux/cpumask.h>
29 #include <linux/module.h>
30 #include <linux/slab.h>
31 #include <linux/vmalloc.h>
32 #include <linux/miscdevice.h>
33 #include <linux/spinlock.h>
34 #include <linux/mm.h>
35 #include <linux/mutex.h>
36 #include <linux/syscalls.h>
37
38 #include <asm/msr.h>
39 #include <asm/uaccess.h>
40 #include <asm/processor.h>
41
42 MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
43 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
44 MODULE_LICENSE("GPL");
45
46 #define MICROCODE_VERSION       "1.14-xen"
47
48 #define DEFAULT_UCODE_DATASIZE  (2000)    /* 2000 bytes */
49 #define MC_HEADER_SIZE          (sizeof (microcode_header_t))     /* 48 bytes */
50 #define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
51
52 /* no concurrent ->write()s are allowed on /dev/cpu/microcode */
53 static DEFINE_MUTEX(microcode_mutex);
54
55 static void __user *user_buffer;        /* user area microcode data buffer */
56 static unsigned int user_buffer_size;   /* it's size */
57                                 
58 static int microcode_open (struct inode *unused1, struct file *unused2)
59 {
60         return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
61 }
62
63
64 static int do_microcode_update (void)
65 {
66         int err;
67         dom0_op_t op;
68
69         err = sys_mlock((unsigned long)user_buffer, user_buffer_size);
70         if (err != 0)
71                 return err;
72
73         op.cmd = DOM0_MICROCODE;
74         set_xen_guest_handle(op.u.microcode.data, user_buffer);
75         op.u.microcode.length = user_buffer_size;
76         err = HYPERVISOR_dom0_op(&op);
77
78         (void)sys_munlock((unsigned long)user_buffer, user_buffer_size);
79
80         return err;
81 }
82
83 static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
84 {
85         ssize_t ret;
86
87         if ((len >> PAGE_SHIFT) > num_physpages) {
88                 printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
89                 return -EINVAL;
90         }
91
92         mutex_lock(&microcode_mutex);
93
94         user_buffer = (void __user *) buf;
95         user_buffer_size = (int) len;
96
97         ret = do_microcode_update();
98         if (!ret)
99                 ret = (ssize_t)len;
100
101         mutex_unlock(&microcode_mutex);
102
103         return ret;
104 }
105
106 static struct file_operations microcode_fops = {
107         .owner          = THIS_MODULE,
108         .write          = microcode_write,
109         .open           = microcode_open,
110 };
111
112 static struct miscdevice microcode_dev = {
113         .minor          = MICROCODE_MINOR,
114         .name           = "microcode",
115         .fops           = &microcode_fops,
116 };
117
118 static int __init microcode_init (void)
119 {
120         int error;
121
122         error = misc_register(&microcode_dev);
123         if (error) {
124                 printk(KERN_ERR
125                         "microcode: can't misc_register on minor=%d\n",
126                         MICROCODE_MINOR);
127                 return error;
128         }
129
130         printk(KERN_INFO 
131                 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
132         return 0;
133 }
134
135 static void __exit microcode_exit (void)
136 {
137         misc_deregister(&microcode_dev);
138 }
139
140 module_init(microcode_init)
141 module_exit(microcode_exit)
142 MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);