Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[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 < DEFAULT_UCODE_TOTALSIZE) {
88                 printk(KERN_ERR "microcode: not enough data\n"); 
89                 return -EINVAL;
90         }
91
92         if ((len >> PAGE_SHIFT) > num_physpages) {
93                 printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
94                 return -EINVAL;
95         }
96
97         mutex_lock(&microcode_mutex);
98
99         user_buffer = (void __user *) buf;
100         user_buffer_size = (int) len;
101
102         ret = do_microcode_update();
103         if (!ret)
104                 ret = (ssize_t)len;
105
106         mutex_unlock(&microcode_mutex);
107
108         return ret;
109 }
110
111 static struct file_operations microcode_fops = {
112         .owner          = THIS_MODULE,
113         .write          = microcode_write,
114         .open           = microcode_open,
115 };
116
117 static struct miscdevice microcode_dev = {
118         .minor          = MICROCODE_MINOR,
119         .name           = "microcode",
120         .fops           = &microcode_fops,
121 };
122
123 static int __init microcode_init (void)
124 {
125         int error;
126
127         error = misc_register(&microcode_dev);
128         if (error) {
129                 printk(KERN_ERR
130                         "microcode: can't misc_register on minor=%d\n",
131                         MICROCODE_MINOR);
132                 return error;
133         }
134
135         printk(KERN_INFO 
136                 "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
137         return 0;
138 }
139
140 static void __exit microcode_exit (void)
141 {
142         misc_deregister(&microcode_dev);
143 }
144
145 module_init(microcode_init)
146 module_exit(microcode_exit)
147 MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);