diff -urN -X dontdiff linux/arch/i386/kernel/mtrr.c linux-p6uc/arch/i386/kernel/mtrr.c --- linux/arch/i386/kernel/mtrr.c Fri Feb 11 20:07:52 2000 +++ linux-p6uc/arch/i386/kernel/mtrr.c Tue Feb 15 23:57:18 2000 @@ -225,6 +225,10 @@ success. 19991008 Manfred Spraul replaced spin_lock_reschedule() with a normal semaphore. + 20000215 Tigran Aivazian + Added MTRIOC_P6UPDATE ioctl for P6 microcode update. + Reference: Section 8.10 of Volume III, Intel Pentium III + Manual, Order Number 243192. */ #include #include @@ -247,6 +251,7 @@ #include #include #include +#include #include #include @@ -321,6 +326,8 @@ static void compute_ascii (void); #endif +static struct p6ucode * p6ucode = NULL; +static int p6ucode_num = 0; struct set_mtrr_context { @@ -1393,6 +1400,59 @@ return -EINVAL; } /* End Function mtrr_write */ +static void p6update_one(void *arg) +{ + struct cpuinfo_x86 * c; + unsigned int pf = 0, val[2], rev, sig; + int i, id; + + id = smp_processor_id(); + c = cpu_data + id; + sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8); + + if (c->x86 >= 6 && 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= (unsigned int *)p) + sum += *sump; + if (sum != 0) { + printk(KERN_ERR "p6update_one(): aborting due to bad checksum\n"); + break; + } + wrmsr(0x79, (unsigned int)(p->bits), 0); + __asm__ __volatile__ ("cpuid"); + printk(KERN_ERR "p6update_one: CPU%d microcode updated\n", id); + } + break; + } +} + +static int do_p6update(void) +{ + if (smp_call_function (p6update_one, NULL, 1, 0) != 0) + panic("do_p6update(): timed out waiting for other CPUs\n"); + p6update_one(NULL); + return -EINVAL; +} + static int mtrr_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1400,34 +1460,65 @@ mtrr_type type; struct mtrr_sentry sentry; struct mtrr_gentry gentry; + struct mtrr_p6update p6up_ioc; + int p6up_len; switch (cmd) { default: return -ENOIOCTLCMD; + case MTRRIOC_P6UPDATE: + if ( !capable(CAP_SYS_RAWIO) ) return -EPERM; + + /* basic sanity checks for this CPU */ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || + boot_cpu_data.x86 != 6) + return -EINVAL; + + lock_kernel(); + if ( copy_from_user (&p6up_ioc, (void *) arg, sizeof p6up_ioc) ) + return -EFAULT; + p6ucode_num = p6up_ioc.num; + p6up_len = p6up_ioc.num * sizeof(struct p6ucode); + p6ucode = vmalloc(p6up_len); + if (!p6ucode) { + err = -ENOMEM; + unlock_kernel(); + break; + } + if ( copy_from_user (p6ucode, p6up_ioc.uaddr, p6up_len) ) { + err = -EFAULT; + vfree(p6ucode); + unlock_kernel(); + break; + } + err = do_p6update(); + vfree(p6ucode); + unlock_kernel(); + break; case MTRRIOC_ADD_ENTRY: - if ( !suser () ) return -EPERM; + if ( !capable (CAP_SYS_RAWIO) ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file); if (err < 0) return err; break; case MTRRIOC_SET_ENTRY: - if ( !suser () ) return -EPERM; + if ( !capable (CAP_SYS_RAWIO) ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; break; case MTRRIOC_DEL_ENTRY: - if ( !suser () ) return -EPERM; + if ( !capable (CAP_SYS_RAWIO) ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_del (sentry.base, sentry.size, file); if (err < 0) return err; break; case MTRRIOC_KILL_ENTRY: - if ( !suser () ) return -EPERM; + if ( !capable (CAP_SYS_RAWIO) ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_del (-1, sentry.base, sentry.size); diff -urN -X dontdiff linux/include/asm-i386/mtrr.h linux-p6uc/include/asm-i386/mtrr.h --- linux/include/asm-i386/mtrr.h Tue Dec 21 00:01:12 1999 +++ linux-p6uc/include/asm-i386/mtrr.h Wed Feb 16 00:00:28 2000 @@ -43,12 +43,31 @@ unsigned int type; /* Type of region */ }; +struct p6ucode { + 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]; +}; + +struct mtrr_p6update +{ + unsigned int num; /* number of 'struct p6ucode' elements, currently (15/02/2000) 48 */ + void * uaddr; /* pointer to the array of 'struct p6ucode' */ +}; + /* These are the various ioctls */ #define MTRRIOC_ADD_ENTRY _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry) #define MTRRIOC_SET_ENTRY _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry) #define MTRRIOC_DEL_ENTRY _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry) #define MTRRIOC_GET_ENTRY _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry) #define MTRRIOC_KILL_ENTRY _IOW(MTRR_IOCTL_BASE, 4, struct mtrr_sentry) +#define MTRRIOC_P6UPDATE _IOW(MTRR_IOCTL_BASE, 5, struct mtrr_p6update) /* These are the region types */ #define MTRR_TYPE_UNCACHABLE 0 .