• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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