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