2 * Intel CPU Microcode Update driver for Linux
4 * Copyright (C) 2000 Tigran Aivazian
6 * This driver allows to upgrade microcode on Intel processors
7 * belonging to P6 family - PentiumPro, Pentium II,
8 * Pentium III, Xeon etc.
10 * Reference: Section 8.10 of Volume III, Intel Pentium III Manual,
11 * Order Number 243192 or free download from:
13 * http://developer.intel.com/design/pentiumii/manuals/243192.htm
15 * For more information, go to http://www.urbanmyth.org/microcode
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.
22 * 1.0 16 Feb 2000, Tigran Aivazian <tigran@sco.com>
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.
42 #include <linux/init.h>
43 #include <linux/sched.h>
44 #include <linux/module.h>
45 #include <linux/malloc.h>
46 #include <linux/vmalloc.h>
47 #include <linux/miscdevice.h>
48 #include <linux/devfs_fs_kernel.h>
51 #include <asm/uaccess.h>
52 #include <asm/processor.h>
54 #define MICROCODE_VERSION "1.06"
56 MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver");
57 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
61 static int microcode_open(struct inode
*, struct file
*);
62 static ssize_t
microcode_read(struct file
*, char *, size_t, loff_t
*);
63 static ssize_t
microcode_write(struct file
*, const char *, size_t, loff_t
*);
64 static int microcode_ioctl(struct inode
*, struct file
*, unsigned int, unsigned long);
66 static int do_microcode_update(void);
67 static void do_update_one(void *);
69 /* read()/write()/ioctl() are serialized on this */
70 DECLARE_RWSEM(microcode_rwsem
);
72 static struct microcode
*microcode
; /* array of 2048byte microcode blocks */
73 static unsigned int microcode_num
; /* number of chunks in microcode */
74 static char *mc_applied
; /* array of applied microcode blocks */
75 static unsigned int mc_fsize
; /* file size of /dev/cpu/microcode */
77 static struct file_operations microcode_fops
= {
80 write
: microcode_write
,
81 ioctl
: microcode_ioctl
,
85 static struct miscdevice microcode_dev
= {
86 minor
: MICROCODE_MINOR
,
88 fops
: µcode_fops
,
91 static devfs_handle_t devfs_handle
;
93 static int __init
microcode_init(void)
97 if (misc_register(µcode_dev
) < 0) {
99 "microcode: can't misc_register on minor=%d\n",
103 devfs_handle
= devfs_register(NULL
, "cpu/microcode",
104 DEVFS_FL_DEFAULT
, 0, 0, S_IFREG
| S_IRUSR
| S_IWUSR
,
105 µcode_fops
, NULL
);
106 if (devfs_handle
== NULL
&& error
) {
107 printk(KERN_ERR
"microcode: failed to devfs_register()\n");
110 printk(KERN_INFO
"P6 Microcode Update Driver v%s\n", MICROCODE_VERSION
);
114 static void __exit
microcode_exit(void)
116 misc_deregister(µcode_dev
);
117 devfs_unregister(devfs_handle
);
120 printk(KERN_INFO
"P6 Microcode Update Driver v%s unregistered\n",
124 module_init(microcode_init
);
125 module_exit(microcode_exit
);
127 static int microcode_open(struct inode
*unused1
, struct file
*unused2
)
129 return capable(CAP_SYS_RAWIO
) ? 0 : -EPERM
;
133 * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
134 * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
139 } update_req
[NR_CPUS
];
141 static int do_microcode_update(void)
143 int i
, error
= 0, err
;
146 if (smp_call_function(do_update_one
, NULL
, 1, 1) != 0) {
147 printk(KERN_ERR
"microcode: IPI timeout, giving up\n");
152 for (i
=0; i
<smp_num_cpus
; i
++) {
153 err
= update_req
[i
].err
;
156 m
= (struct microcode
*)mc_applied
+ i
;
157 memcpy(m
, µcode
[update_req
[i
].slot
], sizeof(struct microcode
));
163 static void do_update_one(void *unused
)
165 int cpu_num
= smp_processor_id();
166 struct cpuinfo_x86
*c
= cpu_data
+ cpu_num
;
167 struct update_req
*req
= update_req
+ cpu_num
;
168 unsigned int pf
= 0, val
[2], rev
, sig
;
171 req
->err
= 1; /* assume the worst */
173 if (c
->x86_vendor
!= X86_VENDOR_INTEL
|| c
->x86
< 6){
174 printk(KERN_ERR
"microcode: CPU%d not an Intel P6\n", cpu_num
);
178 sig
= c
->x86_mask
+ (c
->x86_model
<<4) + (c
->x86
<<8);
180 if (c
->x86_model
>= 5) {
181 /* get processor flags from BBL_CR_OVRD MSR (0x17) */
182 rdmsr(0x17, val
[0], val
[1]);
183 pf
= 1 << ((val
[1] >> 18) & 7);
186 for (i
=0; i
<microcode_num
; i
++)
187 if (microcode
[i
].sig
== sig
&& microcode
[i
].pf
== pf
&&
188 microcode
[i
].ldrver
== 1 && microcode
[i
].hdrver
== 1) {
192 rdmsr(0x8B, val
[0], rev
);
193 if (microcode
[i
].rev
<= rev
) {
195 "microcode: CPU%d not 'upgrading' to earlier revision"
196 " %d (current=%d)\n", cpu_num
, microcode
[i
].rev
, rev
);
199 struct microcode
*m
= µcode
[i
];
200 unsigned int *sump
= (unsigned int *)(m
+1);
202 while (--sump
>= (unsigned int *)m
)
205 printk(KERN_ERR
"microcode: CPU%d aborting, "
206 "bad checksum\n", cpu_num
);
210 wrmsr(0x79, (unsigned int)(m
->bits
), 0);
211 __asm__
__volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
212 rdmsr(0x8B, val
[0], val
[1]);
216 printk(KERN_ERR
"microcode: CPU%d updated from revision "
217 "%d to %d, date=%08x\n",
218 cpu_num
, rev
, val
[1], m
->date
);
224 printk(KERN_ERR
"microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n",
228 static ssize_t
microcode_read(struct file
*file
, char *buf
, size_t len
, loff_t
*ppos
)
230 if (*ppos
>= mc_fsize
)
232 down_read(µcode_rwsem
);
233 if (*ppos
+ len
> mc_fsize
)
234 len
= mc_fsize
- *ppos
;
235 if (copy_to_user(buf
, mc_applied
+ *ppos
, len
)) {
236 up_read(µcode_rwsem
);
240 up_read(µcode_rwsem
);
244 static ssize_t
microcode_write(struct file
*file
, const char *buf
, size_t len
, loff_t
*ppos
)
248 if (len
% sizeof(struct microcode
) != 0) {
249 printk(KERN_ERR
"microcode: can only write in N*%d bytes units\n",
250 sizeof(struct microcode
));
253 down_write(µcode_rwsem
);
255 mc_applied
= kmalloc(smp_num_cpus
*sizeof(struct microcode
),
258 printk(KERN_ERR
"microcode: out of memory for saved microcode\n");
259 up_write(µcode_rwsem
);
264 microcode_num
= len
/sizeof(struct microcode
);
265 microcode
= vmalloc(len
);
271 if (copy_from_user(microcode
, buf
, len
)) {
276 if(do_microcode_update()) {
280 mc_fsize
= smp_num_cpus
* sizeof(struct microcode
);
284 devfs_set_file_size(devfs_handle
, mc_fsize
);
287 up_write(µcode_rwsem
);
291 static int microcode_ioctl(struct inode
*inode
, struct file
*file
,
292 unsigned int cmd
, unsigned long arg
)
295 case MICROCODE_IOCFREE
:
296 down_write(µcode_rwsem
);
298 devfs_set_file_size(devfs_handle
, 0);
301 printk(KERN_INFO
"microcode: freed %d bytes\n", mc_fsize
);
303 up_write(µcode_rwsem
);
306 up_write(µcode_rwsem
);
310 printk(KERN_ERR
"microcode: unknown ioctl cmd=%d\n", cmd
);