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 static DEFINE_SPINLOCK(annotate_lock);
19 static bool collect_annotations = false;
21 static int annotate_copy(struct file *file, char const __user *buf, size_t count)
22 {
23 int cpu = 0;
24 int write = per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF];
26 if (file == NULL) {
27 // copy from kernel
28 memcpy(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count);
29 } else {
30 // copy from user space
31 if (copy_from_user(&per_cpu(gator_buffer, cpu)[ANNOTATE_BUF][write], buf, count) != 0)
32 return -1;
33 }
34 per_cpu(gator_buffer_write, cpu)[ANNOTATE_BUF] = (write + count) & gator_buffer_mask[ANNOTATE_BUF];
36 return 0;
37 }
39 static ssize_t annotate_write(struct file *file, char const __user *buf, size_t count_orig, loff_t *offset)
40 {
41 int tid, cpu, header_size, available, contiguous, length1, length2, size, count = count_orig & 0x7fffffff;
43 if (*offset)
44 return -EINVAL;
46 if (!collect_annotations) {
47 return count_orig;
48 }
50 cpu = 0; // Annotation only uses a single per-cpu buffer as the data must be in order to the engine
52 if (file == NULL) {
53 tid = -1; // set the thread id to the kernel thread
54 } else {
55 tid = current->pid;
56 }
58 // synchronize between cores
59 spin_lock(&annotate_lock);
61 // determine total size of the payload
62 header_size = MAXSIZE_PACK32 * 3 + MAXSIZE_PACK64;
63 available = buffer_bytes_available(cpu, ANNOTATE_BUF) - header_size;
64 size = count < available ? count : available;
66 if (size <= 0) {
67 size = 0;
68 goto annotate_write_out;
69 }
71 // synchronize shared variables annotateBuf and annotatePos
72 if (collect_annotations && per_cpu(gator_buffer, cpu)[ANNOTATE_BUF]) {
73 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, smp_processor_id());
74 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, tid);
75 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, gator_get_time());
76 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, size);
78 // determine the sizes to capture, length1 + length2 will equal size
79 contiguous = contiguous_space_available(cpu, ANNOTATE_BUF);
80 if (size < contiguous) {
81 length1 = size;
82 length2 = 0;
83 } else {
84 length1 = contiguous;
85 length2 = size - contiguous;
86 }
88 if (annotate_copy(file, buf, length1) != 0) {
89 size = -EINVAL;
90 goto annotate_write_out;
91 }
93 if (length2 > 0 && annotate_copy(file, &buf[length1], length2) != 0) {
94 size = -EINVAL;
95 goto annotate_write_out;
96 }
98 // Check and commit; commit is set to occur once buffer is 3/4 full
99 buffer_check(cpu, ANNOTATE_BUF);
100 }
102 annotate_write_out:
103 spin_unlock(&annotate_lock);
105 // return the number of bytes written
106 return size;
107 }
109 #include "gator_annotate_kernel.c"
111 static int annotate_release(struct inode *inode, struct file *file)
112 {
113 int cpu = 0;
115 // synchronize between cores
116 spin_lock(&annotate_lock);
118 if (per_cpu(gator_buffer, cpu)[ANNOTATE_BUF] && buffer_check_space(cpu, ANNOTATE_BUF, MAXSIZE_PACK64 + 2 * MAXSIZE_PACK32)) {
119 uint32_t tid = current->pid;
120 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, tid);
121 gator_buffer_write_packed_int64(cpu, ANNOTATE_BUF, 0); // time
122 gator_buffer_write_packed_int(cpu, ANNOTATE_BUF, 0); // size
123 }
125 spin_unlock(&annotate_lock);
127 return 0;
128 }
130 static const struct file_operations annotate_fops = {
131 .write = annotate_write,
132 .release = annotate_release
133 };
135 static int gator_annotate_create_files(struct super_block *sb, struct dentry *root)
136 {
137 return gatorfs_create_file_perm(sb, root, "annotate", &annotate_fops, 0666);
138 }
140 static int gator_annotate_start(void)
141 {
142 collect_annotations = true;
143 return 0;
144 }
146 static void gator_annotate_stop(void)
147 {
148 collect_annotations = false;
149 }