-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcyclecounter.c
More file actions
348 lines (286 loc) · 9.39 KB
/
cyclecounter.c
File metadata and controls
348 lines (286 loc) · 9.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <asm/smp.h>
#include <asm/cacheflush.h>
#include <linux/proc_fs.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/slab.h> /* kmalloc() */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
#include "cyclecounter.h"
#include <linux/version.h>
#include <asm/outercache.h>
#define PERF_DEF_OPTS (1 | 16)
#define PERF_OPT_RESET_CYCLES (2 | 4)
#define procfs_name "cyclecounter"
#define FLUSHALL 3
#define ARMV7_CNT0 0 /* First event counter */
#define ARMV7_CCNT 31 /* Cycle counter */
#define ENABLE_CNTR (1 << ARMV7_CCNT)
#define ARMV7_PMNC_E (1 << 0) /* Enable all counters */
#define ARMV7_CNTENS_C (1 << ARMV7_CCNT)
#if !defined(__arm__)
#error Module can only be compiled on ARM machines.
#endif
enum armv7_counters {
ARMV7_CYCLE_COUNTER = 1, /* Cycle counter */
ARMV7_COUNTER0 = 2, /* First event counter */
};
/* Perf Event to low level counters mapping */
#define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0)
#define ARMV7_SELECT_MASK 0x1f /* Mask for writable bits */
#define ARMV7_CNTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
#define ARMV7_CNTENC_C (1 << ARMV7_CCNT)
#define ARMV7_CNTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
#define ARMV7_CNTENS_C (1 << ARMV7_CCNT)
/*
* * EVTSEL: Event selection reg
* */
#define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */
#define ARMV7_INTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
#define ARMV7_INTENS_C (1 << ARMV7_CCNT)
extern long simple_strtol(const char *,char **,unsigned int);
void memory_exit(void);
int memory_init(void);
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos);
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos);
/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
/* Global variables of the driver */
/* Major number */
int memory_major = 69;
/* Buffer to store data */
char *memory_buffer;
int memory_open(struct inode *inode, struct file *filp) {
/* Success */
printk(KERN_INFO "[" DRVR_NAME "] Opening device !\n");
return 0;
}
int memory_release(struct inode *inode, struct file *filp) {
/* Success */
return 0;
}
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,1);
/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
} else {
return 0;
}
}
ssize_t memory_write( struct file *filp, char *buf,
size_t count, loff_t *f_pos) {
char *tmp;
char *endptr;
char ret;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,1);
ret = simple_strtol(memory_buffer, &endptr, 10);
if(endptr == NULL)
{
printk(KERN_INFO "[" DRVR_NAME "] Failed to read an integer!\n");
}
else
{
//printk(KERN_INFO "[" DRVR_NAME "] Writing %d !\n", ret);
if(ret == FLUSHALL)
{
printk(KERN_INFO "[" DRVR_NAME "] FLUSH CACHE ALL");
flush_cache_all();
/*outer_flush_all();*/
/*flush_cache_louis();*/
}
}
return 1;
}
static inline void enable_intens(unsigned int idx)
{
u32 val;
if(idx == ARMV7_CYCLE_COUNTER)
{
val = ARMV7_INTENS_C;
}else
{
val = ARMV7_INTENS_P(idx);
}
asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
}
static inline void reset_pmn()
{
unsigned long value = 0;
asm volatile("mrc p15, 0, %0, c9, c12, 0 " : "=r" (value)); /* Read PMNC */
value |= 0x02;
asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r" (value));
}
static inline int select_counter(int idx)
{
u32 cnt = idx & 0x1F;
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (cnt));
return cnt;
}
static inline void write_evtsel(unsigned int idx, u32 evtCode)
{
select_counter(idx);
asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (evtCode));
}
static inline u32 read_counter(int idx)
{
unsigned long value = 0;
select_counter(idx);
asm volatile("mrc p15, 0, %0, c9, c13, 2": "=r" (value));
return value;
}
static inline void write_counter(int idx, u32 value)
{
select_counter(idx);
asm volatile("mcr p15, 0, %0, c9, c13, 2" :: "r" (value));
}
static inline void enable_counter(unsigned int idx)
{
u32 val;
if (idx == ARMV7_CYCLE_COUNTER)
val = ARMV7_CNTENS_C;
else
val = (1 << idx);
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
}
static inline void disable_counter(unsigned int idx)
{
u32 val;
if (idx == ARMV7_CYCLE_COUNTER)
val = ARMV7_CNTENC_C;
else
val = ARMV7_CNTENC_P(idx);
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
}
static inline void enable_event(int idx, int evt)
{
/*disable_counter(idx);*/
if (idx != ARMV7_CYCLE_COUNTER)
write_evtsel(idx, evt);
enable_intens(idx);
}
/* Called when a process tries to open the device file, like
* "cat /dev/mycharfile"
*/
static int cyclecounter_device_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "{" DRVR_NAME "] opening cyclecounter device.\n");
return 0;
}
static void enable_cpu_counters(void* data)
{
printk(KERN_INFO "[" DRVR_NAME "] enabling user-mode PMU access on CPU #%d", smp_processor_id());
/* Enable user-mode access to counters. */
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: "r"(1));
asm volatile("mcr p15, 0, %0, c9, c14, 2" :: "r"(0x80000000));
/* Enable all counters */
asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(ARMV7_PMNC_E));
//enable CCNT (write in CNTENS Register)
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (ARMV7_CNTENS_C));
//DISABLE L2
outer_disable();
}
static void disable_cpu_counters(void* data)
{
printk(KERN_INFO "[" DRVR_NAME "] disabling user-mode PMU access on CPU #%d",
smp_processor_id());
/* Program PMU and disable all counters */
/*asm volatile("mcr p15, 0, %0, c9, c12, 0" :: "r"(0));*/
/*asm volatile("mcr p15, 0, %0, c9, c12, 2" :: "r"(0x8000000f));*/
asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r" (0));
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (ARMV7_CNTENS_C));
/* Disable user-mode access to counters. */
asm volatile("mcr p15, 0, %0, c9, c14, 0" :: "r"(0));
}
int init_module(void)
{
printk(KERN_INFO "[" DRVR_NAME "] Module initialisation\n");
on_each_cpu(enable_cpu_counters, NULL, 1);
int result = register_chrdev(memory_major, "cyclecounter", &memory_fops);
if (result < 0) {
printk(
"[" DRVR_NAME "]: cannot obtain major number %d\n", memory_major);
return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);
printk("[" DRVR_NAME "] Inserting memory module\n");
/*unsigned int counter1= 0;*/
/*unsigned int event1 = 0x03;//cache_misses event*/
/*unsigned int counter2= 1;*/
/*unsigned int event2 = 0x04;*/
/*printk("[" DRVR_NAME "] Enabling counter %u for the event %u on CPU%d\n\n", counter1, event1, smp_processor_id());*/
/*reset_pmn();*/
/*enable_event(counter1, event1);*/
/*enable_event(counter2, event2);*/
/*enable_counter(counter1);*/
/*enable_counter(counter2);*/
/*write_counter(counter1, 0);*/
/*write_counter(counter2, 0);*/
/*u32 cm1, cm2, ch1, ch2;*/
/*cm1 = read_counter(counter1); */
/*ch1 = read_counter(counter2);*/
/*printk("[" DRVR_NAME "] ===============+> misses %u hits %u CPU%d\n\n", cm1, ch1, smp_processor_id());*/
/*ch2 = read_counter(counter2);*/
/*cm2 = read_counter(counter1);*/
/*printk("[" DRVR_NAME "] ===============+> misses %u hits %u CPU%d\n\n", (cm2 - cm1), (ch2 - ch1), smp_processor_id());*/
/*int i;*/
/*for(i = 0; i < 10; i++)*/
/*{*/
/*cm1 = read_counter(counter1); */
/*ch1 = read_counter(counter2);*/
/*msleep(2000);*/
/*cm2 = read_counter(counter1); */
/*ch2 = read_counter(counter2);*/
/*printk("[" DRVR_NAME "] ===============>+ misses %u hits: %u CPU%d\n\n", (cm2 - cm1), (ch2 - ch1), smp_processor_id());*/
/*}*/
return 0;
fail:
memory_exit();
return result;
return 0;
}
void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "cyclecounter");
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk("[" DRVR_NAME "] Removing module\n");
}
void cleanup_module(void)
{
printk(KERN_INFO "[" DRVR_NAME "] Module unloading\n");
on_each_cpu(disable_cpu_counters, NULL, 1);
memory_exit();
}
MODULE_AUTHOR("razaina.");
MODULE_LICENSE("GPL");
MODULE_VERSION("1");
MODULE_DESCRIPTION("Enables user-mode access to ARMv7 PMU counters + additional features");