1 /**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
10 #include <linux/slab.h>
11 #include <linux/fs.h>
12 #include <linux/mm.h>
13 #include <linux/sched.h>
14 #include <asm/uaccess.h>
15 #include <asm/current.h>
16 #include <linux/spinlock.h>
18 #define ANNOTATE_SIZE (16*1024)
19 static DEFINE_SPINLOCK(annotate_lock);
20 static char *annotateBuf;
21 static char *annotateBuf0;
22 static char *annotateBuf1;
23 static int annotatePos;
24 static int annotateSel;
25 static bool collect_annotations = false;
27 static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
28 {
29 char tempBuffer[512];
30 int remaining, size;
31 uint32_t tid;
33 if (*offset)
34 return -EINVAL;
36 // determine size to capture
37 size = count < sizeof(tempBuffer) ? count : sizeof(tempBuffer);
39 // note: copy may be for naught if remaining is zero, but better to do the copy outside of the spinlock
40 if (file == NULL) {
41 // copy from kernel
42 memcpy(tempBuffer, buf, size);
44 // set the thread id to the kernel thread, not the current thread
45 tid = -1;
46 } else {
47 // copy from user space
48 if (copy_from_user(tempBuffer, buf, size) != 0)
49 return -EINVAL;
50 tid = current->pid;
51 }
53 // synchronize shared variables annotateBuf and annotatePos
54 spin_lock(&annotate_lock);
55 if (collect_annotations && annotateBuf) {
56 remaining = ANNOTATE_SIZE - annotatePos - 256; // pad for headers and release
57 size = size < remaining ? size : remaining;
58 if (size > 0) {
59 uint64_t time = gator_get_time();
60 uint32_t cpuid = smp_processor_id();
61 int pos = annotatePos;
62 pos += gator_write_packed_int(&annotateBuf[pos], tid);
63 pos += gator_write_packed_int64(&annotateBuf[pos], time);
64 pos += gator_write_packed_int(&annotateBuf[pos], cpuid);
65 pos += gator_write_packed_int(&annotateBuf[pos], size);
66 memcpy(&annotateBuf[pos], tempBuffer, size);
67 annotatePos = pos + size;
68 }
69 }
70 spin_unlock(&annotate_lock);
72 if (size <= 0) {
73 wake_up(&gator_buffer_wait);
74 return 0;
75 }
77 // return the number of bytes written
78 return size;
79 }
81 #include "gator_annotate_kernel.c"
83 static int annotate_release(struct inode *inode, struct file *file)
84 {
85 int remaining = ANNOTATE_SIZE - annotatePos;
86 if (remaining < 16) {
87 return -EFAULT;
88 }
90 spin_lock(&annotate_lock);
91 if (annotateBuf) {
92 uint32_t tid = current->pid;
93 int pos = annotatePos;
94 pos += gator_write_packed_int(&annotateBuf[pos], tid);
95 pos += gator_write_packed_int64(&annotateBuf[pos], 0); // time
96 pos += gator_write_packed_int(&annotateBuf[pos], 0); // cpuid
97 pos += gator_write_packed_int(&annotateBuf[pos], 0); // size
98 annotatePos = pos;
99 }
100 spin_unlock(&annotate_lock);
102 return 0;
103 }
105 static const struct file_operations annotate_fops = {
106 .write = annotate_write,
107 .release = annotate_release
108 };
110 static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
111 {
112 annotateBuf = NULL;
113 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
114 }
116 static int gator_annotate_init(void)
117 {
118 annotateBuf0 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
119 annotateBuf1 = kmalloc(ANNOTATE_SIZE, GFP_KERNEL);
120 if (!annotateBuf0 || !annotateBuf1)
121 return -1;
122 return 0;
123 }
125 static int gator_annotate_start(void)
126 {
127 annotateSel = 0;
128 annotatePos = 1;
129 annotateBuf = annotateBuf0;
130 annotateBuf[0] = FRAME_ANNOTATE;
131 collect_annotations = true;
132 return 0;
133 }
135 static void gator_annotate_stop(void)
136 {
137 collect_annotations = false;
138 }
140 static void gator_annotate_shutdown(void)
141 {
142 spin_lock(&annotate_lock);
143 annotateBuf = NULL;
144 spin_unlock(&annotate_lock);
145 }
147 static void gator_annotate_exit(void)
148 {
149 spin_lock(&annotate_lock);
150 kfree(annotateBuf0);
151 kfree(annotateBuf1);
152 annotateBuf = annotateBuf0 = annotateBuf1 = NULL;
153 spin_unlock(&annotate_lock);
154 }
156 static int gator_annotate_ready(void)
157 {
158 return annotatePos > 1 && annotateBuf;
159 }
161 static int gator_annotate_read(char **buffer)
162 {
163 int len;
165 if (!gator_annotate_ready())
166 return 0;
168 annotateSel = !annotateSel;
170 if (buffer)
171 *buffer = annotateBuf;
173 spin_lock(&annotate_lock);
174 len = annotatePos;
175 annotateBuf = annotateSel ? annotateBuf1 : annotateBuf0;
176 annotateBuf[0] = FRAME_ANNOTATE;
177 annotatePos = 1;
178 spin_unlock(&annotate_lock);
180 return len;
181 }