source: trunk/lib_ir/AgnerTestP/DriverSrcLinux/MSRdrv.c @ 4221

Last change on this file since 4221 was 4221, checked in by linmengl, 5 years ago

initial checkin of Agner Fog's performance script

File size: 6.3 KB
Line 
1//                       MSRdrv.c                     © 2012-03-02 Agner Fog
2
3// Device driver for access to Model-specific registers and control registers
4// in Linux (32 and 64 bit x86 platform)
5
6// Modified 2011-06-08 for changed IOCTL
7
8// © 2010-2012 GNU General Public License www.gnu.org/licences
9
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/fs.h>
13#include <linux/cdev.h>
14#include <linux/slab.h>
15#include <asm/uaccess.h>
16
17#include "MSRdrvL.h"
18
19MODULE_LICENSE("GPL");
20
21static int MSRdrv_open(struct inode *MSRdrv_inode, struct file *MSRdrv_file );
22static int MSRdrv_release(struct inode *MSRdrv_inode, struct file *MSRdrv_file );
23static ssize_t MSRdrv_read(struct file *p_file, char *u_buffer, size_t count, loff_t *ppos );
24static ssize_t MSRdrv_write(struct file *p_file, const char *u_buffer, size_t count, loff_t *ppos);
25//static int MSRdrv_ioctl(struct inode *inode, struct file *file, unsigned ioctl_num, unsigned long ioctl_param);
26static long MSRdrv_ioctl(struct file *file, unsigned ioctl_num, unsigned long ioctl_param);
27static long MSRdrv_ioctl32(struct file *file, unsigned ioctl_num, unsigned long ioctl_param);
28
29dev_t MSRdrv_dev;
30struct cdev *MSRdrv_cdev;
31struct file_operations MSRdrv_fops = {
32owner : THIS_MODULE,
33read : MSRdrv_read,
34       // ioctl : MSRdrv_ioctl,
35unlocked_ioctl : MSRdrv_ioctl,
36compat_ioctl : MSRdrv_ioctl32,
37               .write = MSRdrv_write,
38open : MSRdrv_open,
39release : MSRdrv_release,
40};
41
42static int MSRdrv_open(struct inode *p_inode, struct file *p_file ) {
43    return 0;
44}
45
46static int MSRdrv_release(struct inode *p_inode, struct file *p_file ) {
47    return 0;
48}
49
50static long MSRdrv_ioctl32(struct file *file, unsigned ioctl_num, unsigned long ioctl_param) {
51    unsigned long param = (unsigned long)((void*)(ioctl_param));
52
53    MSRdrv_ioctl( /*file->f_dentry->d_inode,*/ file, ioctl_num, param);
54    return 0;
55}
56
57static long int ReadCR(int num) {
58    // read control register
59    long int val = 0;
60    switch (num) {
61    case 0:
62        __asm__ __volatile__("mov %%cr0, %0" : "=r"(val));
63        break;
64    case 2:
65        __asm__ __volatile__("mov %%cr2, %0" : "=r"(val));
66        break;
67    case 3:
68        __asm__ __volatile__("mov %%cr3, %0" : "=r"(val));
69        break;
70    case 4:
71        __asm__ __volatile__("mov %%cr4, %0" : "=r"(val));
72        break;
73    }
74    return val;
75}
76
77static void WriteCR(int num, long int val) {
78    // write control register
79    switch (num) {
80    case 0:
81        __asm__ __volatile__("mov %0, %%cr0" : : "r"(val));
82        break;
83    case 2:
84        __asm__ __volatile__("mov %0, %%cr2" : : "r"(val));
85        break;
86    case 3:
87        __asm__ __volatile__("mov %0, %%cr3" : : "r"(val));
88        break;
89    case 4:
90        __asm__ __volatile__("mov %0, %%cr4" : : "r"(val));
91        break;
92    }
93}
94
95static long long ReadMSR(int num) {
96    // read model specific register
97    unsigned int hi = 0, lo = 0;
98    __asm__ __volatile__("rdmsr" : "=a"(lo), "=d"(hi) : "c"(num));
99    return lo | (long long)hi << 32;
100}
101
102static void WriteMSR(int num, int low, int high) {
103    // write model specific register
104    __asm__ __volatile__("wrmsr" : : "c"(num), "a"(low), "d"(high));
105}
106
107
108static /*int*/ long MSRdrv_ioctl( /*struct inode *inode,*/ struct file *file, unsigned ioctl_num, unsigned long ioctl_param) {
109    struct SMSRInOut *commandp = (struct SMSRInOut*)ioctl_param;
110    int i;
111    long int cr4val;
112
113    if (ioctl_num == IOCTL_PROCESS_LIST) {
114        for (i = 0; i <= MAX_QUE_ENTRIES; i++, commandp++) {
115            switch (commandp->msr_command) {
116            case MSR_IGNORE:
117                break;
118
119            case MSR_STOP: default:       // end of command list
120                i = MAX_QUE_ENTRIES + 1;
121                break;
122
123            case MSR_READ:                // read model specific register
124                commandp->value = ReadMSR(commandp->register_number);
125                break;
126
127            case MSR_WRITE:               // write model specific register
128                WriteMSR(commandp->register_number, commandp->val[0], commandp->val[1]);
129                break;
130
131            case CR_READ:                 // read control register
132                commandp->value = (long long)ReadCR(commandp->register_number);
133                break;
134
135            case CR_WRITE:                // write control register
136                WriteCR(commandp->register_number, (long int)commandp->value);
137                break;
138
139            case PMC_ENABLE:              // Enable RDPMC and RDTSC instructions
140                cr4val = ReadCR(4);        // Read CR4
141                cr4val |= 0x100;           // Enable RDPMC
142                cr4val &= ~4;              // Enable RDTSC
143                WriteCR(4, cr4val);        // Write CR4
144                break;
145
146            case PMC_DISABLE:             // Disable RDPMC instruction (RDTSC remains enabled)
147                cr4val = ReadCR(4);        // Read CR4
148                cr4val &= ~0x100;          // Disable RDPMC
149                //cr4val |= 4;             // Disable RDTSC
150                WriteCR(4, cr4val);        // Write CR4
151                break;
152
153            case PROC_GET:                // get processor number.
154                // not implemented in Linux version
155                break;
156
157            case PROC_SET:                // set processor number.
158                // not implemented in Linux version
159                break;
160            }
161        }
162        return 0;
163    }
164    else {  // unknown command
165        return 1;
166    }
167}
168
169static ssize_t MSRdrv_read( struct file *p_file, char *u_buffer, size_t count, loff_t *ppos ) {
170    return 0;
171}
172
173static ssize_t MSRdrv_write(struct file *p_file, const char *u_buffer, size_t count, loff_t *ppos) {
174    return 0;
175}
176
177static int MSRdrv_init(void) {
178    MSRdrv_dev = MKDEV( DEV_MAJOR, DEV_MINOR );
179    register_chrdev_region( MSRdrv_dev, 1, DEV_NAME );
180
181    MSRdrv_cdev = cdev_alloc();
182    MSRdrv_cdev->owner = THIS_MODULE;
183    MSRdrv_cdev->ops = &MSRdrv_fops;
184    cdev_init( MSRdrv_cdev, &MSRdrv_fops );
185    cdev_add( MSRdrv_cdev, MSRdrv_dev, 1 );
186
187    return 0;
188}
189
190static void MSRdrv_exit(void) {
191    cdev_del( MSRdrv_cdev );
192    unregister_chrdev_region( MSRdrv_dev, 1 );
193}
194
195module_init(MSRdrv_init);
196module_exit(MSRdrv_exit);
Note: See TracBrowser for help on using the repository browser.