1 /* drivers/misc/qemu_sysfs.c
2 *
3 * Copyright (C) 2007-2008 Google, Inc.
4 * Author: Jack Veenstra
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17 #include <linux/list.h>
18 #include <linux/module.h>
19 #include <linux/miscdevice.h>
20 #include <linux/sysdev.h>
21 #include <linux/fs.h>
22 #include <linux/poll.h>
23 #include <linux/interrupt.h>
24 #include <linux/delay.h>
25 #include <linux/clk.h>
26 #include <linux/wait.h>
27 #include "qemu_trace.h"
28
29 MODULE_DESCRIPTION("Qemu Trace Driver");
30 MODULE_LICENSE("GPL");
31 MODULE_VERSION("1.0");
32
33 static struct kobject *qemu_trace_kobj;
34
state_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)35 static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
36 {
37 int val = qemu_trace_get_tracing();
38 buf[0] = '0' + val;
39 buf[1] = '\n';
40 return 2;
41 }
42
state_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t n)43 static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char * buf, size_t n)
44 {
45 if (n <= 0)
46 return -EINVAL;
47 if (buf[0] == '0')
48 qemu_trace_stop();
49 else if (buf[0] == '1')
50 qemu_trace_start();
51 else
52 return -EINVAL;
53 return n;
54 }
55
symbol_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)56 static ssize_t symbol_show(struct kobject *kobj, struct kobj_attribute *attr, char * buf)
57 {
58 return 0;
59 }
60
61 // We are expecting a string of the form "addr symbol" where 'addr' is a hex address
62 // (without the leading '0x') and symbol is a newline-terminated string. This symbol
63 // with its corresponding address will be added to the trace file.
64 //
65 // To remove the mapping for (addr, symbol) in the trace file, write just the
66 // address. As before, the address is in hex without the leading '0x'. It can
67 // be newline-terminated or zero-terminated.
symbol_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t n)68 static ssize_t symbol_store(struct kobject *kobj, struct kobj_attribute *attr, const char * buf, size_t n)
69 {
70 const char *cp;
71 unsigned int addr = 0;
72 int len;
73 char *sym;
74
75 if (n <= 0 || buf == NULL)
76 return -EINVAL;
77 for (cp = buf; *cp != ' '; ++cp) {
78 unsigned int digit;
79
80 if (*cp >= '0' && *cp <= '9')
81 digit = *cp - '0';
82 else if (*cp >= 'a' && *cp <= 'f')
83 digit = *cp - 'a' + 10;
84 else if (*cp == 0 || *cp == '\n') {
85 qemu_trace_remove_mapping(addr);
86 return n;
87 } else
88 return -EINVAL;
89 addr = (addr << 4) + digit;
90 }
91 // Move past the space
92 cp += 1;
93
94 // Copy the string to a new buffer so that we can replace the newline
95 // with '\0'.
96 len = strlen(cp);
97 sym = kzalloc(len + 1, GFP_KERNEL);
98 strcpy(sym, cp);
99 if (sym[len - 1] == '\n')
100 sym[len - 1] = 0;
101
102 qemu_trace_add_mapping(addr, sym);
103 kfree(sym);
104 return n;
105 }
106
process_name_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)107 static ssize_t process_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
108 {
109 return 0;
110 }
111
112 /* This expects a string that is the process name. If the string contains
113 * a trailing newline, that is removed in the emulator tracing code because
114 * it is simpler to do it there.
115 */
process_name_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t n)116 static ssize_t process_name_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
117 {
118 if (n <= 0 || buf == NULL)
119 return -EINVAL;
120
121 qemu_trace_process_name(buf);
122 return n;
123 }
124
125
126 #define qemu_trace_attr(_name) \
127 static struct kobj_attribute _name##_attr = { \
128 .attr = { \
129 .name = __stringify(_name), \
130 .mode = 0666, \
131 }, \
132 .show = _name##_show, \
133 .store = _name##_store, \
134 }
135
136 qemu_trace_attr(state);
137 qemu_trace_attr(symbol);
138 qemu_trace_attr(process_name);
139
140 static struct attribute * qemu_trace_attrs[] = {
141 &state_attr.attr,
142 &symbol_attr.attr,
143 &process_name_attr.attr,
144 NULL,
145 };
146
147 static struct attribute_group qemu_trace_attr_group = {
148 .attrs = qemu_trace_attrs,
149 };
150
qemu_trace_init(void)151 static int __init qemu_trace_init(void)
152 {
153 int ret;
154
155 qemu_trace_kobj = kobject_create_and_add("qemu_trace", NULL);
156 if (qemu_trace_kobj == NULL) {
157 printk("qemu_trace_init: kobject_create_and_add failed\n");
158 ret = -ENOMEM;
159 return ret;
160 }
161 ret = sysfs_create_group(qemu_trace_kobj, &qemu_trace_attr_group);
162 if (ret) {
163 printk("qemu_trace_init: sysfs_create_group failed\n");
164 goto err;
165 }
166
167 return 0;
168
169 err:
170 kobject_del(qemu_trace_kobj);
171 qemu_trace_kobj = NULL;
172 return ret;
173 }
174
qemu_trace_exit(void)175 static void __exit qemu_trace_exit(void)
176 {
177 sysfs_remove_group(qemu_trace_kobj, &qemu_trace_attr_group);
178 kobject_del(qemu_trace_kobj);
179 }
180
181 core_initcall(qemu_trace_init);
182 module_exit(qemu_trace_exit);
183