2 /* ----------------------------------------------------------------------- * 4 * Copyright 2000 H. Peter Anvin - All Rights Reserved 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. 12 * ----------------------------------------------------------------------- */ 17 * x86 MSR access device 19 * This device is accessed by lseek() to the appropriate register number 20 * and then read/write in chunks of 8 bytes. A larger size means multiple 21 * reads or writes of the same register. 23 * This driver uses /dev/cpu/%d/msr where %d is the minor number, and on 24 * an SMP box will direct the access to CPU %d. 27 #include <linux/module.h> 28 #include <linux/config.h> 30 #include <linux/types.h> 31 #include <linux/errno.h> 32 #include <linux/fcntl.h> 33 #include <linux/init.h> 34 #include <linux/poll.h> 35 #include <linux/smp.h> 36 #include <linux/major.h> 38 #include <asm/processor.h> 40 #include <asm/uaccess.h> 41 #include <asm/system.h> 43 /* Note: "err" is handled in a funny way below. Otherwise one version 44 of gcc or another breaks. */ 46 extern inlineintwrmsr_eio(u32 reg
, u32 eax
, u32 edx
) 53 ".section .fixup,\"ax\"\n" 57 ".section __ex_table,\"a\"\n" 62 :"a"(eax
),"d"(edx
),"c"(reg
),"i"(-EIO
),"0"(0)); 67 extern inlineintrdmsr_eio(u32 reg
, u32
*eax
, u32
*edx
) 74 ".section .fixup,\"ax\"\n" 78 ".section __ex_table,\"a\"\n" 82 :"=&bDS"(err
),"=a"(*eax
),"=d"(*edx
) 83 :"c"(reg
),"i"(-EIO
),"0"(0)); 97 static voidmsr_smp_wrmsr(void*cmd_block
) 99 struct msr_command
*cmd
= (struct msr_command
*) cmd_block
; 101 if( cmd
->cpu
==smp_processor_id() ) 102 cmd
->err
=wrmsr_eio(cmd
->reg
, cmd
->data
[0], cmd
->data
[1]); 105 static voidmsr_smp_rdmsr(void*cmd_block
) 107 struct msr_command
*cmd
= (struct msr_command
*) cmd_block
; 109 if( cmd
->cpu
==smp_processor_id() ) 110 cmd
->err
=rdmsr_eio(cmd
->reg
, &cmd
->data
[0], &cmd
->data
[1]); 113 extern inlineintdo_wrmsr(int cpu
, u32 reg
, u32 eax
, u32 edx
) 115 struct msr_command cmd
; 117 if( cpu
==smp_processor_id() ) { 118 returnwrmsr_eio(reg
, eax
, edx
); 125 smp_call_function(msr_smp_wrmsr
, &cmd
,1,1); 130 extern inlineintdo_rdmsr(int cpu
, u32 reg
, u32
*eax
, u32
*edx
) 132 struct msr_command cmd
; 134 if( cpu
==smp_processor_id() ) { 135 returnrdmsr_eio(reg
, eax
, edx
); 140 smp_call_function(msr_smp_rdmsr
, &cmd
,1,1); 149 #else/* ! CONFIG_SMP */ 151 extern inlineintdo_wrmsr(int cpu
, u32 reg
, u32 eax
, u32 edx
) 153 returnwrmsr_eio(reg
, eax
, edx
); 156 extern inlineintdo_rdmsr(int cpu
, u32 reg
, u32
*eax
, u32
*edx
) 158 returnrdmsr_eio(reg
, eax
, edx
); 161 #endif/* ! CONFIG_SMP */ 163 static loff_t
msr_seek(struct file
*file
, loff_t offset
,int orig
) 167 file
->f_pos
= offset
; 170 file
->f_pos
+= offset
; 173 return-EINVAL
;/* SEEK_END not supported */ 177 static ssize_t
msr_read(struct file
* file
,char* buf
, 178 size_t count
, loff_t
*ppos
) 180 u32
*tmp
= (u32
*)buf
; 184 int cpu
=MINOR(file
->f_dentry
->d_inode
->i_rdev
); 188 return-EINVAL
;/* Invalid chunk size */ 190 for( rv
=0; count
; count
-=8) { 191 err
=do_rdmsr(cpu
, reg
, &data
[0], &data
[1]); 194 if(copy_to_user(tmp
,&data
,8) ) 199 return((char*)tmp
) - buf
; 202 static ssize_t
msr_write(struct file
* file
,const char* buf
, 203 size_t count
, loff_t
*ppos
) 205 const u32
*tmp
= (const u32
*)buf
; 209 int cpu
=MINOR(file
->f_dentry
->d_inode
->i_rdev
); 213 return-EINVAL
;/* Invalid chunk size */ 215 for( rv
=0; count
; count
-=8) { 216 if(copy_from_user(&data
,tmp
,8) ) 218 err
=do_wrmsr(cpu
, reg
, data
[0], data
[1]); 224 return((char*)tmp
) - buf
; 227 static intmsr_open(struct inode
*inode
,struct file
*file
) 229 int cpu
=MINOR(file
->f_dentry
->d_inode
->i_rdev
); 230 struct cpuinfo_x86
*c
= &(cpu_data
)[cpu
]; 232 if( !(cpu_online_map
& (1UL<< cpu
)) ) 233 return-ENXIO
;/* No such CPU */ 234 if( !test_bit(X86_FEATURE_MSR
, &c
->x86_capability
) ) 235 return-EIO
;/* MSR not supported */ 241 * File operations we support 243 static struct file_operations msr_fops
= { 251 int __init
msr_init(void) 253 if(register_chrdev(MSR_MAJOR
,"cpu/msr", &msr_fops
)) { 254 printk(KERN_ERR
"msr: unable to get major %d for msr\n", 262 void __exit
msr_exit(void) 264 unregister_chrdev(MSR_MAJOR
,"cpu/msr"); 267 module_init(msr_init
); 268 module_exit(msr_exit
) 272 MODULE_AUTHOR("H. Peter Anvin <hpa@zytor.com>"); 273 MODULE_DESCRIPTION("x86 generic MSR driver");