x86, msr: Export the register-setting MSR functions via /dev/*/msr
H. Peter Anvin [Mon, 31 Aug 2009 21:16:57 +0000 (14:16 -0700)]
Make it possible to access the all-register-setting/getting MSR
functions via the MSR driver.  This is implemented as an ioctl() on
the standard MSR device node.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Cc: Borislav Petkov <petkovbb@gmail.com>

Documentation/ioctl/ioctl-number.txt
arch/x86/include/asm/msr.h
arch/x86/kernel/msr.c

index dbea4f9..1c058b5 100644 (file)
@@ -121,6 +121,7 @@ Code        Seq#    Include File            Comments
 'c'    00-7F   linux/comstats.h        conflict!
 'c'    00-7F   linux/coda.h            conflict!
 'c'    80-9F   arch/s390/include/asm/chsc.h
+'c'    A0-AF   arch/x86/include/asm/msr.h
 'd'    00-FF   linux/char/drm/drm/h    conflict!
 'd'    F0-FF   linux/digi1.h
 'e'    all     linux/digi1.h           conflict!
index 8e56712..7e2b6ba 100644 (file)
@@ -3,10 +3,16 @@
 
 #include <asm/msr-index.h>
 
-#ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define X86_IOC_RDMSR_REGS     _IOWR('c', 0xA0, __u32[8])
+#define X86_IOC_WRMSR_REGS     _IOWR('c', 0xA1, __u32[8])
+
+#ifdef __KERNEL__
+
 #include <asm/asm.h>
 #include <asm/errno.h>
 #include <asm/cpumask.h>
@@ -286,6 +292,6 @@ static inline int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8])
        return wrmsr_safe_regs(regs);
 }
 #endif  /* CONFIG_SMP */
-#endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
 #endif /* _ASM_X86_MSR_H */
index 2cfbb4b..7dd9500 100644 (file)
@@ -1,6 +1,7 @@
 /* ----------------------------------------------------------------------- *
  *
  *   Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
  *
  *   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
@@ -121,6 +122,54 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
        return bytes ? bytes : err;
 }
 
+static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg)
+{
+       u32 __user *uregs = (u32 __user *)arg;
+       u32 regs[8];
+       int cpu = iminor(file->f_path.dentry->d_inode);
+       int err;
+
+       switch (ioc) {
+       case X86_IOC_RDMSR_REGS:
+               if (!(file->f_mode & FMODE_READ)) {
+                       err = -EBADF;
+                       break;
+               }
+               if (copy_from_user(&regs, uregs, sizeof regs)) {
+                       err = -EFAULT;
+                       break;
+               }
+               err = rdmsr_safe_regs_on_cpu(cpu, regs);
+               if (err)
+                       break;
+               if (copy_to_user(uregs, &regs, sizeof regs))
+                       err = -EFAULT;
+               break;
+
+       case X86_IOC_WRMSR_REGS:
+               if (!(file->f_mode & FMODE_WRITE)) {
+                       err = -EBADF;
+                       break;
+               }
+               if (copy_from_user(&regs, uregs, sizeof regs)) {
+                       err = -EFAULT;
+                       break;
+               }
+               err = wrmsr_safe_regs_on_cpu(cpu, regs);
+               if (err)
+                       break;
+               if (copy_to_user(uregs, &regs, sizeof regs))
+                       err = -EFAULT;
+               break;
+
+       default:
+               err = -ENOTTY;
+               break;
+       }
+
+       return err;
+}
+
 static int msr_open(struct inode *inode, struct file *file)
 {
        unsigned int cpu = iminor(file->f_path.dentry->d_inode);
@@ -151,6 +200,8 @@ static const struct file_operations msr_fops = {
        .read = msr_read,
        .write = msr_write,
        .open = msr_open,
+       .unlocked_ioctl = msr_ioctl,
+       .compat_ioctl = msr_ioctl,
 };
 
 static int __cpuinit msr_device_create(int cpu)