linux/arch/x86/kernel/msr.c
<<
>>
Prefs
   1/* ----------------------------------------------------------------------- *
   2 *
   3 *   Copyright 2000-2008 H. Peter Anvin - All Rights Reserved
   4 *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
   5 *
   6 *   This program is free software; you can redistribute it and/or modify
   7 *   it under the terms of the GNU General Public License as published by
   8 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
   9 *   USA; either version 2 of the License, or (at your option) any later
  10 *   version; incorporated herein by reference.
  11 *
  12 * ----------------------------------------------------------------------- */
  13
  14/*
  15 * x86 MSR access device
  16 *
  17 * This device is accessed by lseek() to the appropriate register number
  18 * and then read/write in chunks of 8 bytes.  A larger size means multiple
  19 * reads or writes of the same register.
  20 *
  21 * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
  22 * an SMP box will direct the access to CPU %d.
  23 */
  24
  25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  26
  27#include <linux/module.h>
  28
  29#include <linux/types.h>
  30#include <linux/errno.h>
  31#include <linux/fcntl.h>
  32#include <linux/init.h>
  33#include <linux/poll.h>
  34#include <linux/smp.h>
  35#include <linux/major.h>
  36#include <linux/fs.h>
  37#include <linux/device.h>
  38#include <linux/cpu.h>
  39#include <linux/notifier.h>
  40#include <linux/uaccess.h>
  41#include <linux/gfp.h>
  42
  43#include <asm/cpufeature.h>
  44#include <asm/msr.h>
  45
  46static struct class *msr_class;
  47static enum cpuhp_state cpuhp_msr_state;
  48
  49static ssize_t msr_read(struct file *file, char __user *buf,
  50                        size_t count, loff_t *ppos)
  51{
  52        u32 __user *tmp = (u32 __user *) buf;
  53        u32 data[2];
  54        u32 reg = *ppos;
  55        int cpu = iminor(file_inode(file));
  56        int err = 0;
  57        ssize_t bytes = 0;
  58
  59        if (count % 8)
  60                return -EINVAL; /* Invalid chunk size */
  61
  62        for (; count; count -= 8) {
  63                err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
  64                if (err)
  65                        break;
  66                if (copy_to_user(tmp, &data, 8)) {
  67                        err = -EFAULT;
  68                        break;
  69                }
  70                tmp += 2;
  71                bytes += 8;
  72        }
  73
  74        return bytes ? bytes : err;
  75}
  76
  77static ssize_t msr_write(struct file *file, const char __user *buf,
  78                         size_t count, loff_t *ppos)
  79{
  80        const u32 __user *tmp = (const u32 __user *)buf;
  81        u32 data[2];
  82        u32 reg = *ppos;
  83        int cpu = iminor(file_inode(file));
  84        int err = 0;
  85        ssize_t bytes = 0;
  86
  87        if (count % 8)
  88                return -EINVAL; /* Invalid chunk size */
  89
  90        for (; count; count -= 8) {
  91                if (copy_from_user(&data, tmp, 8)) {
  92                        err = -EFAULT;
  93                        break;
  94                }
  95                err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]);
  96                if (err)
  97                        break;
  98                tmp += 2;
  99                bytes += 8;
 100        }
 101
 102        return bytes ? bytes : err;
 103}
 104
 105static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg)
 106{
 107        u32 __user *uregs = (u32 __user *)arg;
 108        u32 regs[8];
 109        int cpu = iminor(file_inode(file));
 110        int err;
 111
 112        switch (ioc) {
 113        case X86_IOC_RDMSR_REGS:
 114                if (!(file->f_mode & FMODE_READ)) {
 115                        err = -EBADF;
 116                        break;
 117                }
 118                if (copy_from_user(&regs, uregs, sizeof regs)) {
 119                        err = -EFAULT;
 120                        break;
 121                }
 122                err = rdmsr_safe_regs_on_cpu(cpu, regs);
 123                if (err)
 124                        break;
 125                if (copy_to_user(uregs, &regs, sizeof regs))
 126                        err = -EFAULT;
 127                break;
 128
 129        case X86_IOC_WRMSR_REGS:
 130                if (!(file->f_mode & FMODE_WRITE)) {
 131                        err = -EBADF;
 132                        break;
 133                }
 134                if (copy_from_user(&regs, uregs, sizeof regs)) {
 135                        err = -EFAULT;
 136                        break;
 137                }
 138                err = wrmsr_safe_regs_on_cpu(cpu, regs);
 139                if (err)
 140                        break;
 141                if (copy_to_user(uregs, &regs, sizeof regs))
 142                        err = -EFAULT;
 143                break;
 144
 145        default:
 146                err = -ENOTTY;
 147                break;
 148        }
 149
 150        return err;
 151}
 152
 153static int msr_open(struct inode *inode, struct file *file)
 154{
 155        unsigned int cpu = iminor(file_inode(file));
 156        struct cpuinfo_x86 *c;
 157
 158        if (!capable(CAP_SYS_RAWIO))
 159                return -EPERM;
 160
 161        if (cpu >= nr_cpu_ids || !cpu_online(cpu))
 162                return -ENXIO;  /* No such CPU */
 163
 164        c = &cpu_data(cpu);
 165        if (!cpu_has(c, X86_FEATURE_MSR))
 166                return -EIO;    /* MSR not supported */
 167
 168        return 0;
 169}
 170
 171/*
 172 * File operations we support
 173 */
 174static const struct file_operations msr_fops = {
 175        .owner = THIS_MODULE,
 176        .llseek = no_seek_end_llseek,
 177        .read = msr_read,
 178        .write = msr_write,
 179        .open = msr_open,
 180        .unlocked_ioctl = msr_ioctl,
 181        .compat_ioctl = msr_ioctl,
 182};
 183
 184static int msr_device_create(unsigned int cpu)
 185{
 186        struct device *dev;
 187
 188        dev = device_create(msr_class, NULL, MKDEV(MSR_MAJOR, cpu), NULL,
 189                            "msr%d", cpu);
 190        return PTR_ERR_OR_ZERO(dev);
 191}
 192
 193static int msr_device_destroy(unsigned int cpu)
 194{
 195        device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
 196        return 0;
 197}
 198
 199static char *msr_devnode(struct device *dev, umode_t *mode)
 200{
 201        return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
 202}
 203
 204static int __init msr_init(void)
 205{
 206        int err;
 207
 208        if (__register_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr", &msr_fops)) {
 209                pr_err("unable to get major %d for msr\n", MSR_MAJOR);
 210                return -EBUSY;
 211        }
 212        msr_class = class_create(THIS_MODULE, "msr");
 213        if (IS_ERR(msr_class)) {
 214                err = PTR_ERR(msr_class);
 215                goto out_chrdev;
 216        }
 217        msr_class->devnode = msr_devnode;
 218
 219        err  = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/msr:online",
 220                                 msr_device_create, msr_device_destroy);
 221        if (err < 0)
 222                goto out_class;
 223        cpuhp_msr_state = err;
 224        return 0;
 225
 226out_class:
 227        class_destroy(msr_class);
 228out_chrdev:
 229        __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
 230        return err;
 231}
 232module_init(msr_init);
 233
 234static void __exit msr_exit(void)
 235{
 236        cpuhp_remove_state(cpuhp_msr_state);
 237        class_destroy(msr_class);
 238        __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
 239}
 240module_exit(msr_exit)
 241
 242MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
 243MODULE_DESCRIPTION("x86 generic MSR driver");
 244MODULE_LICENSE("GPL");
 245