Merge branch 'dev' into kernel
[kernel/swap-modules.git] / driver / probes_manager.c
1 ////////////////////////////////////////////////////////////////////////////////////
2 //
3 //      FILE:           probes_manager.c
4 //
5 //      DESCRIPTION:
6 //      This file is C source for SWAP driver.
7 //
8 //      SEE ALSO:       probes_manager.h
9 //      AUTHOR:         L.Komkov, A.Gerenkov
10 //      COMPANY NAME:   Samsung Research Center in Moscow
11 //      DEPT NAME:      Advanced Software Group
12 //      CREATED:        2008.02.15
13 //      VERSION:        1.0
14 //      REVISION DATE:  2008.12.03
15 //
16 ////////////////////////////////////////////////////////////////////////////////////
17
18 #include <linux/percpu.h>
19 #include <ksyms.h>
20 #include <dbi_kprobes_deps.h>
21 #include "module.h"
22 #include "probes_manager.h"
23
24 int
25 probes_manager_init (void)
26 {
27         int ret;
28 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)
29         spin_lock_init(&ec_spinlock);
30         spin_lock_init(&ec_probe_spinlock);
31 #endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38) */
32
33         ret = init_helper();
34         if (ret)
35                 return ret;
36
37         return storage_init ();
38 }
39
40 void
41 probes_manager_down (void)
42 {
43         detach_selected_probes ();
44         uninit_helper();
45         storage_down ();
46 }
47
48 static int register_kernel_probe(kernel_probe_t *p)
49 {
50         int ret;
51
52         /* register jprobe */
53         ret = dbi_register_jprobe(&p->jprobe);
54         if (ret) {
55                 EPRINTF("dbi_register_jprobe(0x%lx) failure %d", p->addr, ret);
56                 return ret;
57         };
58
59         /* register kretprobe */
60         ret = dbi_register_kretprobe(&p->retprobe);
61         if (ret) {
62                 EPRINTF("dbi_register_kretprobe(0x%lx) failure %d",
63                         p->addr, ret);
64
65                 dbi_unregister_jprobe(&p->jprobe);
66                 return ret;
67         }
68
69         return 0;
70 }
71
72 static int unregister_kernel_probe(kernel_probe_t *p)
73 {
74         dbi_unregister_kretprobe(&p->retprobe);
75         dbi_unregister_jprobe(&p->jprobe);
76
77         return 0;
78 }
79
80 int
81 attach_selected_probes (void)
82 {
83         int result = 0;
84         int partial_result = 0;
85         kernel_probe_t *p;
86         struct hlist_node *node;
87
88         swap_hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
89         {
90                 partial_result = register_kernel_probe (p);
91                 if (partial_result)
92                 {
93                         result = partial_result;
94                         detach_selected_probes ();      // return into safe state
95                         break;
96                 }
97         }
98
99         return result;
100 }
101
102 int
103 detach_selected_probes (void)
104 {
105         kernel_probe_t *p;
106         struct hlist_node *node;
107
108         swap_hlist_for_each_entry_rcu (p, node, &kernel_probes, hlist)
109                 unregister_kernel_probe (p);
110         swap_hlist_for_each_entry_rcu (p, node, &otg_kernel_probes, hlist) {
111                 unregister_kernel_probe(p);
112         }
113
114         return 0;
115 }
116
117 int
118 add_probe (unsigned long addr)
119 {
120         int result = 0;
121         kernel_probe_t **pprobe = NULL;
122
123         DPRINTF("add probe at 0x%0x\n", addr);
124         if (EC_STATE_IDLE != ec_info.ec_state)
125         {
126                 EPRINTF("Probes addition is allowed in IDLE state only.");
127                 return -EINVAL;
128         }
129
130         result = add_probe_to_list (addr, pprobe);
131
132         return result;
133 }
134
135 int reset_probes(void)
136 {
137         struct hlist_node *node, *tnode;
138         kernel_probe_t *p;
139
140         swap_hlist_for_each_entry_safe (p, node, tnode, &kernel_probes, hlist) {
141                 hlist_del(node);
142                 kfree(p);
143         }
144
145         swap_hlist_for_each_entry_safe (p, node, tnode, &otg_kernel_probes, hlist) {
146                 hlist_del(node);
147                 kfree(p);
148         }
149
150         return 0;
151 }
152
153 int
154 remove_probe (unsigned long addr)
155 {
156         int result = 0;
157
158         if (EC_STATE_IDLE != ec_info.ec_state)
159         {
160                 EPRINTF("Probes addition is allowed in IDLE state only.");
161                 return -EINVAL;
162         }
163
164         result = remove_probe_from_list (addr);
165
166         return result;
167 }
168
169 static DEFINE_PER_CPU(kernel_probe_t *, gpKernProbe) = NULL;
170
171 unsigned long
172 def_jprobe_event_pre_handler (kernel_probe_t * probe, struct pt_regs *regs)
173 {
174         __get_cpu_var (gpKernProbe) = probe;
175
176         return 0;
177 }
178
179 void
180 def_jprobe_event_handler (unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6)
181 {
182         //static int nCount;
183         kernel_probe_t *probe = __get_cpu_var(gpKernProbe);
184
185         pack_event_info(KS_PROBE_ID, RECORD_ENTRY, "pxxxxxx", probe->addr, arg1, arg2, arg3, arg4, arg5, arg6);
186         dbi_jprobe_return ();
187 }
188
189 int
190 def_retprobe_event_handler (struct kretprobe_instance *pi, struct pt_regs *regs, kernel_probe_t * probe)
191 {
192         int ret_val;
193
194         ret_val = regs_return_value(regs);
195         pack_event_info(KS_PROBE_ID, RECORD_RET, "pd", probe->addr, ret_val);
196
197         return 0;
198 }
199
200 int install_kern_otg_probe(unsigned long addr,
201                            unsigned long pre_handler,
202                            unsigned long jp_handler,
203                            unsigned long rp_handler)
204 {
205         kernel_probe_t *new_probe = NULL;
206         kernel_probe_t *probe;
207         int ret = 0;
208
209         probe = find_probe(addr);
210         if (probe) {
211                 /* It is not a problem if we have already registered
212                    this probe before */
213                 return 0;
214         }
215
216         new_probe = kmalloc(sizeof (kernel_probe_t), GFP_ATOMIC);
217         if (!new_probe) {
218                 EPRINTF("No memory for new probe");
219                 return -1;
220         }
221         memset(new_probe, 0, sizeof(kernel_probe_t));
222
223         new_probe->addr = addr;
224         new_probe->jprobe.kp.addr = new_probe->retprobe.kp.addr = (kprobe_opcode_t *)addr;
225         new_probe->jprobe.priv_arg = new_probe->retprobe.priv_arg = new_probe;
226
227         if (pre_handler) {
228                 new_probe->jprobe.pre_entry =
229                         (kprobe_pre_entry_handler_t)
230                         pre_handler;
231         } else {
232                 new_probe->jprobe.pre_entry =
233                         (kprobe_pre_entry_handler_t)
234                         def_jprobe_event_pre_handler;
235         }
236
237         if (jp_handler) {
238                 new_probe->jprobe.entry = (kprobe_opcode_t *)jp_handler;
239         } else {
240                 new_probe->jprobe.entry =
241                         (kprobe_opcode_t *)
242                         def_jprobe_event_handler;
243         }
244
245         if (rp_handler) {
246                 new_probe->retprobe.handler = (kretprobe_handler_t)rp_handler;
247         } else {
248                 new_probe->retprobe.handler =
249                         (kretprobe_handler_t)
250                         def_retprobe_event_handler;
251         }
252
253         INIT_HLIST_NODE (&new_probe->hlist);
254         hlist_add_head_rcu (&new_probe->hlist, &kernel_probes);
255
256         ret = register_kernel_probe(new_probe);
257         if (ret) {
258                 EPRINTF("Cannot set kernel probe at addr %lx", addr);
259                 return -1;
260         }
261
262         return 0;
263 }
264 EXPORT_SYMBOL_GPL(install_kern_otg_probe);