1 ////////////////////////////////////////////////////////////////////////////////////
3 // FILE: device_driver.c
6 // This file is C source for SWAP driver.
8 // SEE ALSO: device_driver.h
9 // AUTHOR: L.Komkov, S.Dianov, S.Grekhov, A.Gerenkov
10 // COMPANY NAME: Samsung Research Center in Moscow
11 // DEPT NAME: Advanced Software Group
12 // CREATED: 2008.02.15
14 // REVISION DATE: 2008.12.03
16 ////////////////////////////////////////////////////////////////////////////////////
19 #include "device_driver.h" // device driver
20 #include "handlers_core.h"
21 #include <linux/notifier.h>
24 extern unsigned long swap_sum_time;
25 extern unsigned long swap_sum_hit;
29 extern unsigned long imi_sum_time;
30 extern unsigned long imi_sum_hit;
33 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
34 static BLOCKING_NOTIFIER_HEAD(swap_notifier_list);
37 EXPORT_SYMBOL_GPL(gl_nNotifyTgid);
39 DECLARE_WAIT_QUEUE_HEAD (notification_waiters_queue);
40 volatile unsigned notification_count;
42 static int device_mmap (struct file *filp, struct vm_area_struct *vma);
43 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
44 static int device_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
46 static long device_ioctl (struct file *file, unsigned int cmd, unsigned long arg);
48 static int device_open(struct inode *, struct file *);
49 static int device_release(struct inode *, struct file *);
50 static ssize_t device_read(struct file *, char *, size_t, loff_t *);
51 static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
53 void proc_p_free_all(void);
55 static int gl_nDeviceOpened = 0;
56 static struct file_operations device_fops = {
59 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
60 .ioctl = device_ioctl,
62 .unlocked_ioctl = device_ioctl,
65 .write = device_write,
67 .release = device_release
70 typedef void (* dbi_module_callback)();
72 int device_init (void)
75 nReserved = register_chrdev(0, device_name, &device_fops);
78 unregister_chrdev(nReserved, device_name);
79 EPRINTF("Cannot register character device!");
82 EPRINTF("New device node with major number [%d], was created\n", nReserved);
83 device_major = nReserved;
87 void device_down (void)
89 unregister_chrdev(device_major, device_name);
92 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
93 void swap_register_notify (struct notifier_block *nb)
95 blocking_notifier_chain_register(&swap_notifier_list, nb);
97 EXPORT_SYMBOL_GPL(swap_register_notify);
99 void swap_unregister_notify (struct notifier_block *nb)
101 blocking_notifier_chain_unregister(&swap_notifier_list, nb);
103 EXPORT_SYMBOL_GPL(swap_unregister_notify);
106 void notify_user (event_id_t event_id)
108 ec_info.events_counters[event_id] += 1;
110 if (EVENT_EC_PROBE_RECORD == event_id)
112 // EC_PROBE_RECORD events happen to often. To reduce overhead user
113 // space will be notified only once per each EVENTS_AGGREGATION_USEC
114 static uint64_t timestamp_usec = 0;
116 uint64_t current_usec;
121 do_gettimeofday (&tv);
122 current_usec = 1000000ULL * (unsigned) tv.tv_sec + (unsigned) tv.tv_usec;
124 if (current_usec < timestamp_usec)
126 // Note: time from do_gettimeofday() may go backward
127 EPRINTF ("current_usec=%llu timestamp_usec=%llu", current_usec, timestamp_usec);
131 delta_usec = current_usec - timestamp_usec;
132 if (EVENTS_AGGREGATION_USEC > delta_usec)
134 // wait the time left
136 unsigned UNUSED left_usec = EVENTS_AGGREGATION_USEC - delta_usec;
137 #endif /* defined(__DEBUG) */
138 return; // supress notification
141 timestamp_usec = current_usec; // remember new time for the future use
142 } else if (EVENT_EC_START_CONDITION_SEEN == event_id) {
143 return; // supress notification
144 } else if (EVENT_EC_STOP_CONDITION_SEEN == event_id) {
145 return; // supress notification
148 ++notification_count;
149 wake_up_interruptible (¬ification_waiters_queue);
152 static int device_mmap (struct file *filp UNUSED, struct vm_area_struct *vma)
155 EPRINTF("Null pointer to buffer!");
158 return remap_vmalloc_range (vma, p_buffer, 0);
161 static int device_open(struct inode *inode, struct file *file)
163 /*if (gl_nDeviceOpened)
167 try_module_get(THIS_MODULE);
171 static int device_release(struct inode *inode, struct file *file)
174 module_put(THIS_MODULE);
178 static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset)
180 EPRINTF("Operation <<read>> not supported!");
184 static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
186 EPRINTF("Operation <<write>> not supported!");
190 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
191 static int device_ioctl (struct inode *inode UNUSED, struct file *file UNUSED, unsigned int cmd, unsigned long arg)
193 static long device_ioctl (struct file *file UNUSED, unsigned int cmd, unsigned long arg)
196 unsigned long spinlock_flags = 0L;
198 // DPRINTF("Command=%d", cmd);
199 printk("#1# Command=%d\n", cmd);
200 printk("#2# Command=%d\n", cmd);
204 case EC_IOCTL_SET_EC_MODE:
206 ioctl_general_t param;
207 unsigned long nIgnoredBytes = 0;
208 memset(¶m, '0', sizeof(ioctl_general_t));
209 nIgnoredBytes = copy_from_user (¶m, (void*)arg, sizeof(ioctl_general_t));
210 if (nIgnoredBytes > 0) {
214 if(SetECMode(param.m_unsignedLong) == -1) {
219 DPRINTF("Set EC Mode = %lu", param.m_unsignedLong);
222 case EC_IOCTL_GET_EC_MODE:
224 ioctl_general_t param;
225 unsigned long nIgnoredBytes = 0;
226 memset(¶m, '0', sizeof(ioctl_general_t));
227 param.m_unsignedLong = GetECMode();
228 nIgnoredBytes = copy_to_user ((void*)arg, ¶m, sizeof (ioctl_general_t));
229 if (nIgnoredBytes > 0) {
234 // DPRINTF("Get EC Mode = %lu", param.m_unsignedLong); // Frequent call
237 case EC_IOCTL_SET_BUFFER_SIZE:
239 ioctl_general_t param;
240 unsigned long nIgnoredBytes = 0;
241 memset(¶m, '0', sizeof(ioctl_general_t));
242 nIgnoredBytes = copy_from_user (¶m, (void*)arg, sizeof(ioctl_general_t));
243 if (nIgnoredBytes > 0) {
247 if (SetBufferSize(param.m_unsignedLong) == -1) {
252 DPRINTF("Set Buffer Size = %lu", param.m_unsignedLong);
255 case EC_IOCTL_GET_BUFFER_SIZE:
257 ioctl_general_t param;
258 unsigned long nIgnoredBytes = 0;
259 memset(¶m, '0', sizeof(ioctl_general_t));
260 param.m_unsignedLong = GetBufferSize();
261 nIgnoredBytes = copy_to_user ((void*)arg, ¶m, sizeof (ioctl_general_t));
262 if (nIgnoredBytes > 0) {
267 DPRINTF("Get Buffer Size = %lu", param.m_unsignedLong);
270 case EC_IOCTL_RESET_BUFFER:
272 if (ResetBuffer() == -1) {
277 DPRINTF("Reset Buffer");
280 case EC_IOCTL_GET_EC_INFO:
282 if (copy_ec_info_to_user_space ((ec_info_t *) arg) != 0) {
287 // DPRINTF("Get Buffer Status"); // Frequent call
290 case EC_IOCTL_CONSUME_BUFFER:
292 static ec_info_t ec_info_copy;
293 int nIgnoredBytes = 0;
295 nIgnoredBytes = copy_from_user (&ec_info_copy, (ec_info_t *) arg, sizeof (ec_info_t));
296 if(nIgnoredBytes > 0)
298 EPRINTF ("copy_from_user(%08X,%08X)=%d", (unsigned) arg, (unsigned) &ec_info_copy, nIgnoredBytes);
303 spin_lock_irqsave (&ec_spinlock, spinlock_flags);
306 if(ec_info.after_last > ec_info.first) {
307 ec_info.buffer_effect = ec_info.buffer_size;
309 if (ec_info.after_last == ec_info.buffer_effect) {
312 ec_info.first = ec_info_copy.after_last;
314 ec_info.trace_size = ec_info.trace_size - ec_info_copy.trace_size;
316 spin_unlock_irqrestore (&ec_spinlock, spinlock_flags);
318 // DPRINTF("Consume Buffer"); // Frequent call
321 case EC_IOCTL_ADD_PROBE:
323 unsigned long addr = arg;
324 result = add_probe(addr);
328 //@AGv: remove_probe expects probe address instead of name
329 /*case EC_IOCTL_REMOVE_PROBE:
331 char *probe_name = (char *) arg;
332 result = remove_probe (probe_name);
336 case EC_IOCTL_SET_APPDEPS:
339 result = copy_from_user(&size, (void *)arg, sizeof(size_t));
341 EPRINTF("Cannot copy deps size!");
345 DPRINTF("Deps size has been copied (%d)", size);
348 DPRINTF("Deps are size of 0");
352 deps = vmalloc(size);
354 EPRINTF("Cannot alloc mem for deps!");
358 DPRINTF("Mem for deps has been allocated");
360 result = copy_from_user(deps, (void *)arg, size);
362 EPRINTF("Cannot copy deps!");
366 DPRINTF("Deps has been copied successfully");
370 case EC_IOCTL_SET_PID:
374 result = copy_from_user(&_pid, (void *)arg, sizeof(unsigned int));
376 EPRINTF("Cannot copy pid!");
383 DPRINTF("EC_IOCTL_SET_PID pid:%d", inst_pid);
387 case EC_IOCTL_SET_PROFILEBUNDLE:
391 result = copy_from_user(&size, (void *)arg, sizeof(size_t));
393 EPRINTF("Cannot copy bundle size!");
397 DPRINTF("Bundle size has been copied");
399 bundle = vmalloc(size);
400 if (bundle == NULL) {
401 EPRINTF("Cannot alloc mem for bundle!");
405 DPRINTF("Mem for bundle has been alloced");
407 result = copy_from_user(bundle, (void *)arg, size);
409 EPRINTF("Cannot copy bundle!");
413 DPRINTF("Bundle has been copied successfully");
415 if (link_bundle() == -1) {
416 EPRINTF("Cannot link profile bundle!");
423 case EC_IOCTL_RESET_PROBES:
425 result = reset_probes();
429 case EC_IOCTL_UPDATE_CONDS:
432 struct cond *c, *c_tmp, *p_cond;
433 unsigned char *p_data;
436 err = copy_from_user(&args_cnt, (void *)arg, sizeof(int));
441 /* first, delete all the conds */
442 list_for_each_entry_safe(c, c_tmp, &cond_list.list, list) {
446 /* second, add new conds */
447 p_data = (unsigned char *)(arg + sizeof(int));
448 for (i = 0; i < args_cnt; i++) {
449 p_cond = kmalloc(sizeof(struct cond), GFP_KERNEL);
451 DPRINTF("Cannot alloc cond!");
455 err = copy_from_user(&p_cond->tmpl, p_data, sizeof(struct event_tmpl));
457 DPRINTF("Cannot copy cond from user!");
462 list_add(&(p_cond->list), &(cond_list.list));
463 p_data += sizeof(struct event_tmpl);
467 case EC_IOCTL_ATTACH:
469 unsigned long dbi_flags;
470 struct dbi_modules_handlers *local_mh;
471 struct dbi_modules_handlers_info *local_mhi;
473 dbi_module_callback dmc_start;
475 // call "start"-callback for all modules according module priority
476 local_mh = get_dbi_modules_handlers();
477 spin_lock_irqsave(&local_mh->lock, dbi_flags);
478 for (j = 0; j <= MAX_PRIORITY; j++) {
479 list_for_each_entry_rcu(local_mhi, &local_mh->modules_handlers, dbi_list_head) {
480 if (local_mhi->dbi_module_priority_start == j) {
481 if (local_mhi->dbi_module_callback_start != NULL) {
482 printk("Started module callback (start) %s\n", local_mhi->dbi_module->name);
483 dmc_start = (dbi_module_callback )local_mhi->dbi_module_callback_start;
489 spin_unlock_irqrestore(&local_mh->lock, dbi_flags);
491 result = ec_user_attach ();
492 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
493 DPRINTF("EC_IOCTL_ATTACH calling notification chain");
494 blocking_notifier_call_chain(&swap_notifier_list, EC_IOCTL_ATTACH, (void*)NULL);
496 DPRINTF("Attach Probes");
499 case EC_IOCTL_ACTIVATE:
500 result = ec_user_activate ();
501 DPRINTF("Activate Probes");
503 case EC_IOCTL_STOP_AND_DETACH:
505 unsigned long nIgnoredBytes = 0;
506 unsigned long dbi_flags;
507 struct dbi_modules_handlers *local_mh;
508 struct dbi_modules_handlers_info *local_mhi;
509 unsigned int local_module_refcount = 0;
511 dbi_module_callback dmc_stop;
513 #ifdef OVERHEAD_DEBUG
514 printk("\nswap_sum_time = %ld in kprobe_handler()\n", swap_sum_time);
515 printk("swap_sum_hit = %ld in kprobe_handler()\n", swap_sum_hit);
520 printk("\n### imi_sum_time = %ld in install_mapped_ips()\n", imi_sum_time);
521 printk("### imi_sum_hit = %ld in install_mapped_ips()\n", imi_sum_hit);
523 if (imi_sum_hit != 0) {
524 printk("### time = %ld in install_mapped_ips()\n", imi_sum_time/imi_sum_hit);
530 local_mh = get_dbi_modules_handlers();
531 if(ec_user_stop() != 0) {
535 nIgnoredBytes = copy_ec_info_to_user_space ((ec_info_t*)arg);
536 if(nIgnoredBytes > 0) {
545 DPRINTF("Stop and Detach Probes");
546 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
547 DPRINTF("EC_IOCTL_STOP_AND_DETACH calling notification chain");
548 blocking_notifier_call_chain(&swap_notifier_list, EC_IOCTL_STOP_AND_DETACH, (void*)&gl_nNotifyTgid);
550 // call "stop"-callback for all modules according module priority
551 spin_lock_irqsave(&local_mh->lock, dbi_flags);
552 for (j = 0; j <= MAX_PRIORITY; j++) {
553 list_for_each_entry_rcu(local_mhi, &local_mh->modules_handlers, dbi_list_head) {
554 if (local_mhi->dbi_module_priority_stop == j) {
555 if (local_mhi->dbi_module_callback_stop != NULL) {
556 printk("Started module callback (stop) %s\n", local_mhi->dbi_module->name);
557 dmc_stop = (dbi_module_callback )local_mhi->dbi_module_callback_stop;
563 spin_unlock_irqrestore(&local_mh->lock, dbi_flags);
565 spin_lock_irqsave(&local_mh->lock, dbi_flags);
566 list_for_each_entry_rcu(local_mhi, &local_mh->modules_handlers, dbi_list_head) {
567 local_module_refcount = module_refcount(local_mhi->dbi_module);
568 if (local_module_refcount == 1) {
569 module_put(local_mhi->dbi_module);
571 else if (local_module_refcount > 1) {
572 printk("local_module_refcount too much - force set refcount to zero\n");
573 while (local_module_refcount--)
574 module_put(local_mhi->dbi_module);
577 spin_unlock_irqrestore(&local_mh->lock, dbi_flags);
580 case EC_IOCTL_WAIT_NOTIFICATION:
582 static ec_info_t ec_info_copy;
584 ioctl_wait_notification_t ioctl_args;
586 result = copy_from_user (&ioctl_args, (void *) arg, sizeof (ioctl_args));
593 result = wait_event_interruptible (notification_waiters_queue, ioctl_args.notification_count != notification_count);
596 result = -EINTR; // woken by signal (ERESTARTSYS 512)
600 ioctl_args.notification_count = notification_count;
602 result = copy_to_user ((void *) arg, &ioctl_args, sizeof (ioctl_args));
609 // FIXME: synchronization is necessary here (ec_info must be locked).
610 // ENTER_CRITICAL_SECTION
611 memcpy (&ec_info_copy, &ec_info, sizeof (ec_info_copy));
612 // LEAVE_CRITICAL_SECTION
614 result = copy_to_user ((void *) ioctl_args.p_ec_info, &ec_info_copy, sizeof (ec_info_t));
617 EPRINTF ("copy_to_user(%08X,%08X)=%d", (unsigned) ioctl_args.p_ec_info, (unsigned) &ec_info_copy, result);
624 case EC_IOCTL_US_EVENT:
626 ioctl_us_event_t ioctl_args;
627 result = copy_from_user (&ioctl_args, (void *) arg, sizeof (ioctl_args));
631 EPRINTF ("copy_from_user() failure");
635 if(ioctl_args.len == 0){
637 EPRINTF ("invalid event length!");
640 char *buf = kmalloc(ioctl_args.len, GFP_KERNEL);
643 EPRINTF ("failed to alloc mem for event!");
646 result = copy_from_user (buf, (void *) ioctl_args.data, ioctl_args.len);
649 EPRINTF ("failed to copy event from user space!");
652 result = put_us_event(buf, ioctl_args.len);
657 // DPRINTF("User Space Event"); // Frequent call
661 case EC_IOCTL_SET_EVENT_MASK:
664 result = copy_from_user (&mask, (void *) arg, sizeof (mask));
671 result = set_event_mask (mask);
676 DPRINTF("Set Event Mask = %d", mask);
680 case EC_IOCTL_GET_EVENT_MASK:
683 result = get_event_mask(&mask);
688 result = copy_to_user ((void *) arg, &mask, sizeof (mask));
693 DPRINTF("Get Event Mask = %d", mask);
697 case EC_IOCTL_SET_PREDEF_UPROBES:
702 ioctl_predef_uprobes_info_t data;
703 result = copy_from_user (&data, (void *) arg, sizeof (data));
710 result = set_predef_uprobes (&data);
715 DPRINTF("Set Predefined User Space Probes");
719 case EC_IOCTL_GET_PREDEF_UPROBES:
724 result = get_predef_uprobes((ioctl_predef_uprobes_info_t *)arg);
729 DPRINTF("Get Predefined User Space Probes");
733 case EC_IOCTL_GET_PREDEF_UPROBES_SIZE:
736 result = get_predef_uprobes_size(&size);
741 result = copy_to_user ((void *) arg, &size, sizeof (size));
746 DPRINTF("Get Size of Predefined User Space Probes");
751 EPRINTF ("Unknown driver command = %u", cmd);