[IMPROVE] x86: apply jumper for US probes installing
[kernel/swap-modules.git] / ks_features / ks_features.c
1 /**
2  * ks_features/ks_features.c
3  * @author Vyacheslav Cherkashin: SWAP ks_features implement
4  *
5  * @section LICENSE
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  *
21  * @section COPYRIGHT
22  *
23  * Copyright (C) Samsung Electronics, 2013
24  *
25  * @section DESCRIPTION
26  *
27  *  SWAP kernel features
28  */
29
30
31 #include <linux/module.h>
32 #include <linux/slab.h>
33
34 #include <asm/errno.h>
35 #include <ksyms/ksyms.h>
36 #include <kprobe/swap_kprobes.h>
37 #include <writer/swap_writer_module.h>
38 #include <writer/event_filter.h>
39 #include "ks_features.h"
40 #include "syscall_list.h"
41 #include "features_data.c"
42 #include "file_ops.h"
43
44 /**
45  * @struct ks_probe
46  * @brief Kernel-space probe. Struct used as a container of syscall probes.
47  * @var ks_probe::rp
48  * Pointer to kretprobe.
49  * @var ks_probe::counter
50  * Installed probes counter.
51  * @var ks_probe::args
52  * Pointer to args format string.
53  * @var ks_probe::sub_type
54  * Probe sub type.
55  */
56 struct ks_probe {
57         struct kretprobe rp;
58         int counter;
59         char *args;
60         int sub_type;
61 };
62
63 #define CREATE_RP(name)                                         \
64 {                                                               \
65         .entry_handler = NULL,                                  \
66         .handler = NULL                                         \
67 }
68
69 #define X(name, args) #name
70 static const char *const syscall_name[] = {
71         SYSCALL_LIST
72 };
73 #undef X
74
75 /**
76  * @enum
77  * Syscall name count defenition
78  */
79 enum {
80         syscall_name_cnt = sizeof(syscall_name) / sizeof(char *)
81 };
82
83
84 #define X(name, args__)                                         \
85 {                                                               \
86         .rp = CREATE_RP(name),                                  \
87         .counter = 0,                                           \
88         .args = #args__,                                        \
89         .sub_type = PST_NONE                                    \
90 }
91
92 static struct ks_probe ksp[] = {
93         SYSCALL_LIST
94 };
95 #undef X
96
97 static const char *get_sys_name(size_t id)
98 {
99         return syscall_name[id];
100 }
101
102 static int get_counter(size_t id)
103 {
104         return ksp[id].counter;
105 }
106
107 static void inc_counter(size_t id)
108 {
109         ++ksp[id].counter;
110 }
111
112 static void dec_counter(size_t id)
113 {
114         --ksp[id].counter;
115 }
116
117 /* ========================= HANDLERS ========================= */
118 static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
119 {
120         struct kretprobe *rp = ri->rp;
121
122         if (rp && check_event(current)) {
123                 struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
124                 const char *fmt = ksp->args;
125                 unsigned long addr = (unsigned long)ksp->rp.kp.addr;
126                 int sub_type = ksp->sub_type;
127
128                 entry_event(fmt, addr, regs, PT_KS, sub_type);
129         }
130
131         return 0;
132 }
133
134 static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
135 {
136         struct kretprobe *rp = ri->rp;
137
138         if (rp && check_event(current)) {
139                 struct ks_probe *ksp = container_of(rp, struct ks_probe, rp);
140                 unsigned long func_addr = (unsigned long)rp->kp.addr;
141                 unsigned long ret_addr = (unsigned long)ri->ret_addr;
142                 int sub_type = ksp->sub_type;
143
144                 exit_event('x', regs, PT_KS, sub_type, func_addr, ret_addr);
145         }
146
147         return 0;
148 }
149 /* ========================= HANDLERS ========================= */
150
151
152
153
154 /* ====================== SWITCH_CONTEXT ======================= */
155 static int switch_entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
156 {
157         if (check_event(current))
158                 switch_entry(regs);
159
160         return 0;
161 }
162
163 static int switch_ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
164 {
165         if (check_event(current))
166                 switch_exit(regs);
167
168         return 0;
169 }
170
171 /**
172  * @var switch_rp
173  * Kretprobe for scheduler.
174  */
175 struct kretprobe switch_rp = {
176         .entry_handler = switch_entry_handler,
177         .handler = switch_ret_handler
178 };
179
180 static DEFINE_MUTEX(mutex_sc_enable);
181 static int sc_enable = 0;
182
183 /**
184  * @brief Get scheduler address.
185  *
186  * @return 0 on success, negative error code on error.
187  */
188 int init_switch_context(void)
189 {
190         unsigned long addr;
191
192         addr = swap_ksyms("__switch_to");
193         if (addr == 0) {
194                 printk("ERROR: not found '__switch_to'\n");
195                 return -EINVAL;
196         }
197
198         switch_rp.kp.addr = (kprobe_opcode_t *)addr;
199
200         return 0;
201 }
202
203 /**
204  * @brief Unregisters probe on context switching.
205  *
206  * @return Void.
207  */
208 void exit_switch_context(void)
209 {
210         if (sc_enable)
211                 swap_unregister_kretprobe(&switch_rp);
212 }
213
214 static int register_switch_context(void)
215 {
216         int ret = -EINVAL;
217
218         mutex_lock(&mutex_sc_enable);
219         if (sc_enable) {
220                 printk("switch context profiling is already run!\n");
221                 goto unlock;
222         }
223
224         ret = swap_register_kretprobe(&switch_rp);
225         if (ret == 0)
226                 sc_enable = 1;
227
228 unlock:
229         mutex_unlock(&mutex_sc_enable);
230
231         return ret;
232 }
233
234 static int unregister_switch_context(void)
235 {
236         int ret = 0;
237
238         mutex_lock(&mutex_sc_enable);
239         if (sc_enable == 0) {
240                 printk("switch context profiling is not running!\n");
241                 ret = -EINVAL;
242                 goto unlock;
243         }
244
245         swap_unregister_kretprobe(&switch_rp);
246
247         sc_enable = 0;
248 unlock:
249         mutex_unlock(&mutex_sc_enable);
250
251         return ret;
252 }
253 /* ====================== SWITCH_CONTEXT ======================= */
254
255
256
257
258
259 static int register_syscall(size_t id)
260 {
261         int ret;
262         printk("register_syscall: %s\n", get_sys_name(id));
263
264         if (ksp[id].rp.kp.addr == NULL)
265                 return 0;
266
267         ksp[id].rp.entry_handler = entry_handler;
268         ksp[id].rp.handler = ret_handler;
269
270         ret = swap_register_kretprobe(&ksp[id].rp);
271
272         return ret;
273 }
274
275
276 static int unregister_syscall(size_t id)
277 {
278         printk("unregister_syscall: %s\n", get_sys_name(id));
279
280         if (ksp[id].rp.kp.addr == NULL)
281                 return 0;
282
283         swap_unregister_kretprobe(&ksp[id].rp);
284
285         return 0;
286 }
287
288 static int unregister_multiple_syscalls(size_t *id_p, size_t cnt)
289 {
290         struct kretprobe **rpp;
291         const size_t end = ((size_t) 0) - 1;
292         size_t i = 0, id;
293         int ret = 0;
294
295         if (cnt == 1)
296                 return unregister_syscall(id_p[0]);
297
298         --cnt;
299
300         rpp = kmalloc(GFP_KERNEL, sizeof(&(((struct ks_probe *) 0)->rp)) * cnt);
301         if (rpp == NULL) {
302                 for (; cnt != end; --cnt) {
303                         ret = unregister_syscall(id_p[cnt]);
304                         if (ret)
305                                 return ret;
306         }
307                 return ret;
308         }
309
310         for (; cnt != end; --cnt) {
311                 id = id_p[cnt];
312                 if (ksp[id].rp.kp.addr != NULL) {
313                                 rpp[i] = &ksp[id].rp;
314                                 ++i;
315                 }
316         }
317
318         swap_unregister_kretprobes(rpp, i);
319         kfree(rpp);
320
321         return 0;
322 }
323
324 static void set_pst(struct feature *f, size_t id)
325 {
326         ksp[id].sub_type |= f->sub_type;
327 }
328
329 static void unset_pst(struct feature *f, size_t id)
330 {
331         ksp[id].sub_type &= !f->sub_type;
332 }
333
334 static void do_uninstall_features(struct feature *f, size_t i)
335 {
336         int ret;
337         size_t *id_p;
338         size_t id;
339         size_t cnt = 0;
340         const size_t end = ((size_t) 0) - 1;
341
342         id_p = kmalloc(GFP_KERNEL, sizeof(id) * (i + 1));
343         /* NULL check is below in loop */
344
345         for (; i != end; --i) {
346                 id = f->feature_list[i];
347
348                 if (get_counter(id) == 0) {
349                         printk("syscall %s not installed\n",
350                                get_sys_name(id));
351                         kfree(id_p);
352                         BUG();
353                 }
354
355                 dec_counter(id);
356
357                 if (get_counter(id) == 0) {
358                         if (id_p != NULL) {
359                                 id_p[cnt] = id;
360                                 ++cnt;
361                         } else {
362                                 ret = unregister_syscall(id);
363                                 if (ret)
364                                         printk("syscall %s uninstall error, ret=%d\n",
365                                                    get_sys_name(id), ret);
366                         }
367                 }
368
369                 unset_pst(f, id);
370         }
371
372         if (id_p != NULL) {
373                 unregister_multiple_syscalls(id_p, cnt);
374                 kfree(id_p);
375         }
376 }
377
378 static int do_install_features(struct feature *f)
379 {
380         int ret;
381         size_t i, id;
382
383         for (i = 0; i < f->cnt; ++i) {
384                 id = f->feature_list[i];
385                 set_pst(f, id);
386
387                 if (get_counter(id) == 0) {
388                         ret = register_syscall(id);
389                         if (ret) {
390                                 printk("syscall %s install error, ret=%d\n",
391                                        get_sys_name(id), ret);
392
393                                 do_uninstall_features(f, --i);
394                                 return ret;
395                         }
396                 }
397
398                 inc_counter(id);
399         }
400
401         return 0;
402 }
403
404 static DEFINE_MUTEX(mutex_features);
405
406 static int install_features(struct feature *f)
407 {
408         int ret = 0;
409
410         mutex_lock(&mutex_features);
411         if (f->enable) {
412                 printk("energy profiling is already run!\n");
413                 ret = -EINVAL;
414                 goto unlock;
415         }
416
417         ret = do_install_features(f);
418
419         f->enable = 1;
420 unlock:
421         mutex_unlock(&mutex_features);
422         return ret;
423 }
424
425 static int uninstall_features(struct feature *f)
426 {
427         int ret = 0;
428
429         mutex_lock(&mutex_features);
430         if (f->enable == 0) {
431                 printk("feature[%d] is not running!\n", feature_index(f));
432                 ret = -EINVAL;
433                 goto unlock;
434         }
435         do_uninstall_features(f, f->cnt - 1);
436         f->enable = 0;
437 unlock:
438         mutex_unlock(&mutex_features);
439
440         return ret;
441 }
442
443 static struct feature *get_feature(enum feature_id id)
444 {
445         if (id < 0 || id >= (int)feature_cnt)
446                 return NULL;
447
448         return &features[id];
449 }
450
451 /**
452  * @brief Sets probes related to specified feature.
453  *
454  * @param id Feature id.
455  * @return 0 on success, negative error code on error.
456  */
457 int set_feature(enum feature_id id)
458 {
459         struct feature *f;
460         int ret;
461
462         switch (id) {
463         case FID_FILE:
464                 ret = file_ops_init();
465                 break;
466         case FID_SWITCH:
467                 ret = register_switch_context();
468                 break;
469         default:
470                 f = get_feature(id);
471                 ret = f ? install_features(f): -EINVAL;
472                 break;
473         }
474
475         return ret;
476 }
477 EXPORT_SYMBOL_GPL(set_feature);
478
479 /**
480  * @brief Unsets probes related to specified feature.
481  *
482  * @param id Feature id.
483  * @return 0 on success, negative error code on error.
484  */
485 int unset_feature(enum feature_id id)
486 {
487         struct feature *f;
488         int ret = 0;
489
490         switch (id) {
491         case FID_FILE:
492                 file_ops_exit();
493                 break;
494         case FID_SWITCH:
495                 ret = unregister_switch_context();
496                 break;
497         default:
498                 f = get_feature(id);
499                 ret = f ? uninstall_features(f): -EINVAL;
500                 break;
501         }
502
503         return ret;
504 }
505 EXPORT_SYMBOL_GPL(unset_feature);
506
507 static int init_syscall_features(void)
508 {
509         size_t i;
510         unsigned long addr, ni_syscall;
511         const char *name;
512
513         ni_syscall = swap_ksyms("sys_ni_syscall");
514
515         for (i = 0; i < syscall_name_cnt; ++i) {
516                 name = get_sys_name(i);
517                 addr = swap_ksyms(name);
518                 if (addr == 0) {
519                         printk("INFO: %s() not found\n", name);
520                 } else if (ni_syscall == addr) {
521                         printk("INFO: %s is not install\n", name);
522                         addr = 0;
523                 }
524
525                 ksp[i].rp.kp.addr = (kprobe_opcode_t *)addr;
526         }
527
528         return 0;
529 }
530
531 static void uninit_syscall_features(void)
532 {
533         size_t id;
534
535         for (id = 0; id < syscall_name_cnt; ++id) {
536                 if (get_counter(id) > 0)
537                         unregister_syscall(id);
538         }
539 }
540
541 static int __init init_ks_feature(void)
542 {
543         int ret;
544
545         ret = init_switch_context();
546         if (ret)
547                 return ret;
548
549         ret = init_syscall_features();
550         if (ret)
551                 exit_switch_context();
552
553         return ret;
554 }
555
556 static void __exit exit_ks_feature(void)
557 {
558         uninit_syscall_features();
559         exit_switch_context();
560 }
561
562 module_init(init_ks_feature);
563 module_exit(exit_ks_feature);
564
565 MODULE_LICENSE("GPL");
566
567 /* debug */
568 static void print_feature(struct feature *f)
569 {
570         size_t i;
571
572         for (i = 0; i < f->cnt; ++i) {
573                 printk("    feature[%3u]: %s\n", i, get_sys_name(f->feature_list[i]));
574         }
575 }
576
577 /**
578  * @brief Prints features.
579  *
580  * @return Void.
581  */
582 void print_features(void)
583 {
584         int i;
585
586         printk("print_features:\n");
587         for (i = 0; i < feature_cnt; ++i) {
588                 printk("feature: %d\n", i);
589                 print_feature(&features[i]);
590         }
591 }
592
593 /**
594  * @brief Prints all syscalls.
595  *
596  * @return Void.
597  */
598 void print_all_syscall(void)
599 {
600         int i;
601
602         printk("SYSCALL:\n");
603         for (i = 0; i < syscall_name_cnt; ++i) {
604                 printk("    [%2d] %s\n", get_counter(i), get_sys_name(i));
605         }
606 }
607 /* debug */