msr.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. #ident "$Id$"
  2. /* ----------------------------------------------------------------------- *
  3.  *   
  4.  *   Copyright 2000 H. Peter Anvin - All Rights Reserved
  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.  * msr.c
  15.  *
  16.  * x86 MSR access device
  17.  *
  18.  * This device is accessed by lseek() to the appropriate register number
  19.  * and then read/write in chunks of 8 bytes.  A larger size means multiple
  20.  * reads or writes of the same register.
  21.  *
  22.  * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on
  23.  * an SMP box will direct the access to CPU %d.
  24.  */
  25. #include <linux/module.h>
  26. #include <linux/config.h>
  27. #include <linux/types.h>
  28. #include <linux/errno.h>
  29. #include <linux/fcntl.h>
  30. #include <linux/init.h>
  31. #include <linux/poll.h>
  32. #include <linux/smp.h>
  33. #include <linux/major.h>
  34. #include <asm/processor.h>
  35. #include <asm/msr.h>
  36. #include <asm/uaccess.h>
  37. #include <asm/system.h>
  38. /* Note: "err" is handled in a funny way below.  Otherwise one version
  39.    of gcc or another breaks. */
  40. static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
  41. {
  42.   int err;
  43.   asm volatile(
  44.        "1: wrmsrn"
  45.        "2:n"
  46.        ".section .fixup,"ax"n"
  47.        "3: movl %4,%0n"
  48.        " jmp 2bn"
  49.        ".previousn"
  50.        ".section __ex_table,"a"n"
  51.        " .align 4n"
  52.        " .long 1b,3bn"
  53.        ".previous"
  54.        : "=&bDS" (err)
  55.        : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0));
  56.   return err;
  57. }
  58. static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
  59. {
  60.   int err;
  61.   asm volatile(
  62.        "1: rdmsrn"
  63.        "2:n"
  64.        ".section .fixup,"ax"n"
  65.        "3: movl %4,%0n"
  66.        " jmp 2bn"
  67.        ".previousn"
  68.        ".section __ex_table,"a"n"
  69.        " .align 4n"
  70.        " .long 1b,3bn"
  71.        ".previous"
  72.        : "=&bDS" (err), "=a" (*eax), "=d" (*edx)
  73.        : "c" (reg), "i" (-EIO), "0" (0));
  74.   return err;
  75. }
  76. #ifdef CONFIG_SMP
  77. struct msr_command {
  78.   int cpu;
  79.   int err;
  80.   u32 reg;
  81.   u32 data[2];
  82. };
  83. static void msr_smp_wrmsr(void *cmd_block)
  84. {
  85.   struct msr_command *cmd = (struct msr_command *) cmd_block;
  86.   
  87.   if ( cmd->cpu == smp_processor_id() )
  88.     cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
  89. }
  90. static void msr_smp_rdmsr(void *cmd_block)
  91. {
  92.   struct msr_command *cmd = (struct msr_command *) cmd_block;
  93.   
  94.   if ( cmd->cpu == smp_processor_id() )
  95.     cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
  96. }
  97. static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
  98. {
  99.   struct msr_command cmd;
  100.   if ( cpu == smp_processor_id() ) {
  101.     return wrmsr_eio(reg, eax, edx);
  102.   } else {
  103.     cmd.cpu = cpu;
  104.     cmd.reg = reg;
  105.     cmd.data[0] = eax;
  106.     cmd.data[1] = edx;
  107.     
  108.     smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
  109.     return cmd.err;
  110.   }
  111. }
  112. static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
  113. {
  114.   struct msr_command cmd;
  115.   if ( cpu == smp_processor_id() ) {
  116.     return rdmsr_eio(reg, eax, edx);
  117.   } else {
  118.     cmd.cpu = cpu;
  119.     cmd.reg = reg;
  120.     smp_call_function(msr_smp_rdmsr, &cmd, 1, 1);
  121.     
  122.     *eax = cmd.data[0];
  123.     *edx = cmd.data[1];
  124.     return cmd.err;
  125.   }
  126. }
  127. #else /* ! CONFIG_SMP */
  128. static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
  129. {
  130.   return wrmsr_eio(reg, eax, edx);
  131. }
  132. static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
  133. {
  134.   return rdmsr_eio(reg, eax, edx);
  135. }
  136. #endif /* ! CONFIG_SMP */
  137. static loff_t msr_seek(struct file *file, loff_t offset, int orig)
  138. {
  139.   switch (orig) {
  140.   case 0:
  141.     file->f_pos = offset;
  142.     return file->f_pos;
  143.   case 1:
  144.     file->f_pos += offset;
  145.     return file->f_pos;
  146.   default:
  147.     return -EINVAL; /* SEEK_END not supported */
  148.   }
  149. }
  150. static ssize_t msr_read(struct file * file, char * buf,
  151. size_t count, loff_t *ppos)
  152. {
  153.   u32 *tmp = (u32 *)buf;
  154.   u32 data[2];
  155.   size_t rv;
  156.   u32 reg = *ppos;
  157.   int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
  158.   int err;
  159.   if ( count % 8 )
  160.     return -EINVAL; /* Invalid chunk size */
  161.   
  162.   for ( rv = 0 ; count ; count -= 8 ) {
  163.     err = do_rdmsr(cpu, reg, &data[0], &data[1]);
  164.     if ( err )
  165.       return err;
  166.     if ( copy_to_user(tmp,&data,8) )
  167.       return -EFAULT;
  168.     tmp += 2;
  169.   }
  170.   return ((char *)tmp) - buf;
  171. }
  172. static ssize_t msr_write(struct file * file, const char * buf,
  173.  size_t count, loff_t *ppos)
  174. {
  175.   const u32 *tmp = (const u32 *)buf;
  176.   u32 data[2];
  177.   size_t rv;
  178.   u32 reg = *ppos;
  179.   int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
  180.   int err;
  181.   if ( count % 8 )
  182.     return -EINVAL; /* Invalid chunk size */
  183.   
  184.   for ( rv = 0 ; count ; count -= 8 ) {
  185.     if ( copy_from_user(&data,tmp,8) )
  186.       return -EFAULT;
  187.     err = do_wrmsr(cpu, reg, data[0], data[1]);
  188.     if ( err )
  189.       return err;
  190.     tmp += 2;
  191.   }
  192.   return ((char *)tmp) - buf;
  193. }
  194. static int msr_open(struct inode *inode, struct file *file)
  195. {
  196.   int cpu = MINOR(file->f_dentry->d_inode->i_rdev);
  197.   struct cpuinfo_x86 *c = &(cpu_data)[cpu];
  198.   
  199.   if ( !(cpu_online_map & (1UL << cpu)) )
  200.     return -ENXIO; /* No such CPU */
  201.   if ( !test_bit(X86_FEATURE_MSR, &c->x86_capability) )
  202.     return -EIO; /* MSR not supported */
  203.   
  204.   return 0;
  205. }
  206. /*
  207.  * File operations we support
  208.  */
  209. static struct file_operations msr_fops = {
  210.   owner: THIS_MODULE,
  211.   llseek: msr_seek,
  212.   read: msr_read,
  213.   write: msr_write,
  214.   open: msr_open,
  215. };
  216. int __init msr_init(void)
  217. {
  218.   if (register_chrdev(MSR_MAJOR, "cpu/msr", &msr_fops)) {
  219.     printk(KERN_ERR "msr: unable to get major %d for msrn",
  220.    MSR_MAJOR);
  221.     return -EBUSY;
  222.   }
  223.   
  224.   return 0;
  225. }
  226. void __exit msr_exit(void)
  227. {
  228.   unregister_chrdev(MSR_MAJOR, "cpu/msr");
  229. }
  230. module_init(msr_init);
  231. module_exit(msr_exit)
  232. EXPORT_NO_SYMBOLS;
  233. MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>");
  234. MODULE_DESCRIPTION("x86 generic MSR driver");
  235. MODULE_LICENSE("GPL");