aboutsummaryrefslogtreecommitdiff
path: root/driver/gator_annotate.c
blob: 56656f0149902902c8c2297a4b463b76753b2ff9 (plain)
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
/**
 * Copyright (C) ARM Limited 2010-2011. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/current.h>
#include <linux/spinlock.h>

#define INSTSIZE	1024
static DEFINE_SPINLOCK(annotate_lock);
static char *annotateBuf;
static char *annotateBuf0;
static char *annotateBuf1;
static int annotatePos;
static int annotateSel;

static int gatorfs_copy_from_user(char* localbuf, char const __user *buf, size_t count)
{
	if (count == 0)
		return 0;

	if (copy_from_user(localbuf, buf, count))
		return -EFAULT;

	return 0;
}

static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
{
	char tempBuffer[32];
	unsigned long flags;
	int retval, remaining, size;

	if (*offset)
		return -EINVAL;

	// determine size to capture
	remaining = INSTSIZE - annotatePos - 24; // leave some extra space
	size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer);
	size = size < remaining ? size : remaining;
	if (size <= 0)
		return 0;

	// copy from user space
	retval = gatorfs_copy_from_user(tempBuffer, buf, size);
	if (retval == 0) {
		// synchronize shared variables annotateBuf and annotatePos
		spin_lock_irqsave(&annotate_lock, flags);
		if (!annotateBuf) {
			size = -EINVAL;
		} else  {
			*(int*)&annotateBuf[annotatePos + 0] = current->pid;		// thread id
			*(int*)&annotateBuf[annotatePos + 4] = size;				// length in bytes
			memcpy(&annotateBuf[annotatePos + 8], tempBuffer, size);	// data
			annotatePos = annotatePos + 8 + size;						// increment position
			annotatePos = (annotatePos + 3) & ~3;						// align to 4-byte boundary
		}
		spin_unlock_irqrestore(&annotate_lock, flags);

		// return the number of bytes written
		retval = size;
	}

	return retval;
}

static const struct file_operations annotate_fops = {
	.write		= annotate_write
};

int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
{
	annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
	return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
}

int gator_annotate_init(void)
{
	return 0;
}

int gator_annotate_start(void)
{
	annotatePos = annotateSel = 0;
	annotateBuf0 = kmalloc(INSTSIZE, GFP_KERNEL);
	annotateBuf1 = kmalloc(INSTSIZE, GFP_KERNEL);
	annotateBuf = annotateBuf0;
	if (!annotateBuf0 || !annotateBuf1)
		return -1;
	return 0;
}

void gator_annotate_stop(void)
{
	spin_lock(&annotate_lock);

	kfree(annotateBuf0);
	kfree(annotateBuf1);
	annotateBuf = annotateBuf0 = annotateBuf1 = NULL;

	spin_unlock(&annotate_lock);
}

int gator_annotate_read(int **buffer)
{
	int len;

	if (smp_processor_id() || !annotatePos || !annotateBuf)
		return 0;

	annotateSel = !annotateSel;

	if (buffer)
		*buffer = (int *)annotateBuf;

	spin_lock(&annotate_lock);

	len = annotatePos;
	annotatePos = 0;
	annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;

	spin_unlock(&annotate_lock);

	// Return number of 4-byte words
	return len / 4;
}