1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
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
103static DECLARE_RWSEM(microcode_rwsem);
104
105static struct microcode *microcode;
106static unsigned int microcode_num;
107static char *mc_applied;
108static unsigned int mc_fsize;
109
110
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: µcode_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(µcode_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 µcode_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(µcode_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
173
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, µcode[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;
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
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 = µcode[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
252 spin_lock_irqsave(µcode_update_lock, flags);
253
254
255 wrmsr(MSR_IA32_UCODE_REV, 0, 0);
256 __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
257
258
259 rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
260
261 if (microcode[i].rev < rev) {
262 spin_unlock_irqrestore(µcode_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
269 req->err = 0;
270 spin_unlock_irqrestore(µcode_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
278 while (--sump >= (unsigned int *)m)
279 sum += *sump;
280 if (sum != 0) {
281 req->err = 1;
282 spin_unlock_irqrestore(µcode_update_lock, flags);
283 printk(KERN_ERR "microcode: CPU%d aborting, "
284 "bad checksum\n", cpu_num);
285 return;
286 }
287
288
289 wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
290
291
292 __asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
293
294
295 rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
296
297
298 req->err = 0;
299 spin_unlock_irqrestore(µcode_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(µcode_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(µcode_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(µcode_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(µcode_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(µcode_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(µcode_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(µcode_rwsem);
397 return 0;
398 }
399 up_write(µcode_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