[patch-2.3.36-p3] dd if=microcode of=/proc/driver/microcode bs=98304 count=1

From: Tigran Aivazian (tigran@aivazian.fsnet.co.uk)
Date: Wed Feb 16 2000 - 17:33:11 EST


Hi Linus,

This version implements a write-only file /proc/driver/microcode which
gets rid of the need of any specialized tools. No ioctls - just write
method. Why do we need ioctl here? We don't.

Regards,
Tigran.

diff -urN -X dontdiff linux/CREDITS linux-mc/CREDITS
--- linux/CREDITS Mon Feb 14 20:59:06 2000
+++ linux-mc/CREDITS Wed Feb 16 20:55:10 2000
@@ -41,6 +41,7 @@
 E: tigran@ocston.org
 W: http://www.ocston.org/~tigran
 D: BFS filesystem
+D: Intel P6 CPU microcode update support
 S: United Kingdom
 
 N: Werner Almesberger
diff -urN -X dontdiff linux/Documentation/Configure.help linux-mc/Documentation/Configure.help
--- linux/Documentation/Configure.help Wed Feb 16 20:50:47 2000
+++ linux-mc/Documentation/Configure.help Wed Feb 16 21:17:11 2000
@@ -10752,6 +10752,22 @@
   module, say M here and read Documentation/modules.txt. Most people
   will say N.
 
+Intel P6 CPU Microcode Update Support
+CONFIG_MICROCODE
+ If you say Y here you will be able to use mcode ("man microcode")
+ utility to update microcode on Intel processors in P6 family, e.g.
+ Pentium Pro, Pentium II, Pentium III, Xeon etc. The user-space tool
+ required for microcode update can be found at
+ http://www.ocston.org/~tigran/patches/microcode . You will also
+ need the actual microcode binary data itself which is not shipped with the
+ kernel or with the p6mcode tool. Contact Intel to obtain the latest revision of
+ microcode for your CPU(s).
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called microcode.o. If you want to compile it as a
+ module, say M here and read Documentation/modules.txt.
+
 Enhanced Real Time Clock Support
 CONFIG_RTC
   If you say Y here and create a character special file /dev/rtc with
diff -urN -X dontdiff linux/MAINTAINERS linux-mc/MAINTAINERS
--- linux/MAINTAINERS Sun Feb 13 15:32:49 2000
+++ linux-mc/MAINTAINERS Wed Feb 16 20:55:10 2000
@@ -496,6 +496,11 @@
 M: mingo@redhat.com
 S: Maintained
 
+INTEL P6 MICROCODE UPDATE SUPPORT
+P: Tigran Aivazian
+M: tigran@sco.com
+S: Maintained
+
 IP MASQUERADING:
 P: Juanjo Ciarlante
 M: jjciarla@raiz.uncu.edu.ar
diff -urN -X dontdiff linux/arch/i386/config.in linux-mc/arch/i386/config.in
--- linux/arch/i386/config.in Wed Feb 2 10:09:49 2000
+++ linux-mc/arch/i386/config.in Wed Feb 16 22:22:31 2000
@@ -49,6 +49,10 @@
    define_bool CONFIG_X86_USE_3DNOW y
 fi
 
+if [ "$CONFIG_M686" = "y" -a "$CONFIG_PROC_FS" = "y" ]; then
+ tristate '/proc/driver/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
+fi
+
 choice 'High Memory Support' \
         "off CONFIG_NOHIGHMEM \
         4GB CONFIG_HIGHMEM4G \
diff -urN -X dontdiff linux/arch/i386/defconfig linux-mc/arch/i386/defconfig
--- linux/arch/i386/defconfig Wed Feb 16 20:50:47 2000
+++ linux-mc/arch/i386/defconfig Wed Feb 16 20:55:10 2000
@@ -393,6 +393,7 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+# CONFIG_MICROCODE is not set
 
 #
 # Video For Linux
diff -urN -X dontdiff linux/arch/i386/kernel/Makefile linux-mc/arch/i386/kernel/Makefile
--- linux/arch/i386/kernel/Makefile Fri Feb 11 20:07:52 2000
+++ linux-mc/arch/i386/kernel/Makefile Wed Feb 16 21:26:04 2000
@@ -40,6 +40,16 @@
   endif
 endif
 
+ifeq ($(CONFIG_PROC_FS),y)
+ifeq ($(CONFIG_MICROCODE),y)
+OX_OBJS += microcode.o
+else
+ ifeq ($(CONFIG_MICROCODE),m)
+ MX_OBJS += microcode.o
+ endif
+endif
+endif
+
 ifeq ($(CONFIG_ACPI),y)
 O_OBJS += acpi.o
 else
diff -urN -X dontdiff linux/arch/i386/kernel/microcode.c linux-mc/arch/i386/kernel/microcode.c
--- linux/arch/i386/kernel/microcode.c Thu Jan 1 01:00:00 1970
+++ linux-mc/arch/i386/kernel/microcode.c Wed Feb 16 22:25:03 2000
@@ -0,0 +1,216 @@
+/*
+ * CPU Microcode Update interface for Linux
+ *
+ * Copyright (C) 2000 Tigran Aivazian
+ *
+ * This driver allows to upgrade microcode on Intel processors
+ * belonging to P6 family - PentiumPro, Pentium II, Pentium III etc.
+ *
+ * Reference: Section 8.10 of Volume III, Intel Pentium III Manual,
+ * Order Number 243192 or download from:
+ *
+ * http://developer.intel.com/design/pentiumii/manuals/243192.htm
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 1.0 16 February 2000, Tigran Aivazian <tigran@sco.com>
+ * Initial release.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/proc_fs.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+
+#define MICROCODE_VERSION "1.0"
+
+MODULE_DESCRIPTION("CPU (P6) microcode update driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@ocston.org>");
+EXPORT_NO_SYMBOLS;
+
+/* VFS interface */
+static int microcode_open(struct inode *, struct file *);
+static int microcode_release(struct inode *, struct file *);
+static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *);
+
+
+/* internal helpers to do the work */
+static void do_microcode_update(void);
+static void do_update_one(void *);
+
+/*
+ * Bits in microcode_status. (7 bits of room for future expansion)
+ */
+#define MICROCODE_IS_OPEN 0x01 /* set if /dev/microcode is in use */
+
+static atomic_t microcode_status = ATOMIC_INIT(0); /* bitmapped status byte */
+
+/* the actual array of microcode blocks, each 2048 bytes */
+static struct microcode * microcode = NULL;
+static unsigned int microcode_num = 0;
+
+static struct file_operations microcode_fops = {
+ write: microcode_write,
+ open: microcode_open,
+ release: microcode_release,
+};
+
+static struct inode_operations microcode_inops = {
+ default_file_ops: &microcode_fops,
+};
+
+static struct proc_dir_entry *proc_microcode;
+
+static int __init microcode_init(void)
+{
+ /* write-only /proc/driver/microcode file, one day may become read-write.. */
+ proc_microcode = create_proc_entry("microcode", S_IWUSR, proc_root_driver);
+ if (!proc_microcode) {
+ printk(KERN_ERR "microcode: can't create /proc/driver/microcode entry\n");
+ return -ENOMEM;
+ }
+ proc_microcode->ops = &microcode_inops;
+ printk(KERN_ERR "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION);
+ return 0;
+}
+
+static void __exit microcode_exit(void)
+{
+ remove_proc_entry("microcode", proc_root_driver);
+ printk(KERN_ERR "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION);
+}
+
+module_init(microcode_init);
+module_exit(microcode_exit);
+
+/*
+ * We enforce only one user at a time here with open/close.
+ */
+static int microcode_open(struct inode *inode, struct file *file)
+{
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /* one at a time, please */
+ if (atomic_read(&microcode_status) & MICROCODE_IS_OPEN)
+ return -EBUSY;
+
+ MOD_INC_USE_COUNT;
+
+ atomic_set(&microcode_status,
+ atomic_read(&microcode_status) | MICROCODE_IS_OPEN);
+
+ return 0;
+}
+
+static int microcode_release(struct inode *inode, struct file *file)
+{
+ MOD_DEC_USE_COUNT;
+
+ atomic_set(&microcode_status,
+ atomic_read(&microcode_status) & ~MICROCODE_IS_OPEN);
+
+ return 0;
+}
+
+
+static void do_microcode_update(void)
+{
+ if (smp_call_function(do_update_one, NULL, 1, 0) != 0)
+ panic("do_microcode_update(): timed out waiting for other CPUs\n");
+ do_update_one(NULL);
+}
+
+static void do_update_one(void *unused)
+{
+ struct cpuinfo_x86 * c;
+ unsigned int pf = 0, val[2], rev, sig;
+ int i, id;
+
+ id = smp_processor_id();
+ c = cpu_data + id;
+
+
+ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6)
+ return;
+
+ sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
+
+ if (c->x86_model >= 5) {
+ /* get processor flags from BBL_CR_OVRD MSR (0x17) */
+ rdmsr(0x17, val[0], val[1]);
+ pf = 1 << ((val[1] >> 18) & 7);
+ }
+
+ for (i=0; i<microcode_num; i++)
+ if (microcode[i].sig == sig && microcode[i].pf == pf &&
+ microcode[i].ldrver == 1 && microcode[i].hdrver == 1) {
+
+ rdmsr(0x8B, val[0], rev);
+ if (microcode[i].rev <= rev) {
+ printk(KERN_ERR
+ "microcode: CPU%d not 'upgrading' to earlier revision"
+ " %d (current=%d)\n", id, microcode[i].rev, rev);
+ } else {
+ int sum = 0;
+ struct microcode *m = &microcode[i];
+ unsigned int *sump = (unsigned int *)(m+1);
+
+ while (--sump >= (unsigned int *)m)
+ sum += *sump;
+ if (sum != 0) {
+ printk(KERN_ERR "microcode: CPU%d aborting, "
+ "bad checksum\n", id);
+ break;
+ }
+ wrmsr(0x79, (unsigned int)(m->bits), 0);
+ __asm__ __volatile__ ("cpuid");
+ rdmsr(0x8B, val[0], val[1]);
+ printk(KERN_ERR "microcode: CPU%d microcode updated "
+ "from revision %d to %d\n", id, rev, val[1]);
+ }
+ break;
+ }
+}
+
+static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
+{
+
+ if (*ppos) {
+ printk(KERN_ERR "microcode: can only write at offset=0\n");
+ return -EINVAL;
+ }
+ if (len % sizeof(struct microcode) != 0) {
+ printk(KERN_ERR "microcode: can only write in N*%d bytes units\n",
+ sizeof(struct microcode));
+ return -EINVAL;
+ return -EINVAL;
+ }
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ lock_kernel();
+ microcode_num = len/sizeof(struct microcode);
+ microcode = vmalloc(len);
+ if (!microcode) {
+ unlock_kernel();
+ return -ENOMEM;
+ }
+ if (copy_from_user(microcode, buf, len)) {
+ vfree(microcode);
+ unlock_kernel();
+ return -EFAULT;
+ }
+ do_microcode_update();
+ vfree(microcode);
+ unlock_kernel();
+ return len;
+}
diff -urN -X dontdiff linux/include/asm-i386/processor.h linux-mc/include/asm-i386/processor.h
--- linux/include/asm-i386/processor.h Wed Jan 26 20:34:27 2000
+++ linux-mc/include/asm-i386/processor.h Wed Feb 16 22:24:42 2000
@@ -419,4 +419,16 @@
 #define init_task (init_task_union.task)
 #define init_stack (init_task_union.stack)
 
+struct microcode {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int reserved[5];
+ unsigned int bits[500];
+};
+
 #endif /* __ASM_I386_PROCESSOR_H */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Feb 23 2000 - 21:00:16 EST