Add CONFIG_SWAP_HOOK_ENERGY support 98/115798/3
authorDmitry Kovalenko <d.kovalenko@samsung.com>
Wed, 31 Aug 2016 10:03:48 +0000 (13:03 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Thu, 17 Aug 2017 12:16:03 +0000 (15:16 +0300)
Change-Id: If461329d50f914cbe0bffd93c53852e759ea30f7
Signed-off-by: Dmitry Kovalenko <d.kovalenko@samsung.com>
energy/energy.c

index ada5ae3..97e48a9 100644 (file)
 #include <us_manager/sspt/sspt_proc.h>
 #include <us_manager/sspt/sspt_feature.h>
 #include <linux/atomic.h>
+
+#ifdef CONFIG_SWAP_HOOK_SWITCH_TO
+# include <swap/hook_switch_to.h>
+#endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
+
+#ifdef CONFIG_SWAP_HOOK_ENERGY
+# include <swap/hook_syscall.h>
+# include <swap/hook_energy.h>
+# include <kprobe/swap_td_raw.h>
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
+
 #include "energy.h"
 #include "lcd/lcd_base.h"
 #include "tm_stat.h"
 
 
+#ifndef CONFIG_SWAP_HOOK_ENERGY
 /* ============================================================================
  * =                              ENERGY_XXX                                  =
  * ============================================================================
@@ -111,6 +123,7 @@ static void energy_xxx_unset(struct kern_probe p[], int size, int *flag)
 
        *flag = 0;
 }
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
 
 
 
@@ -374,8 +387,7 @@ static void uninit_data_energy(void)
  * =                             __switch_to                                  =
  * ============================================================================
  */
-static int entry_handler_switch(struct kretprobe_instance *ri,
-                               struct pt_regs *regs)
+static void do_entry_handler_switch(struct task_struct *task)
 {
        int cpu;
        struct cpus_time *ct;
@@ -384,24 +396,21 @@ static int entry_handler_switch(struct kretprobe_instance *ri,
 
        cpu = smp_processor_id();
 
-       ct = current->tgid ? &ed_system.ct : &ct_idle;
+       ct = task->tgid ? &ed_system.ct : &ct_idle;
        cpus_time_lock(ct, flags);
        cpus_time_update_running(ct, cpu, get_ntime(), start_time);
        cpus_time_unlock(ct, flags);
 
-       ed = get_energy_data(current);
+       ed = get_energy_data(task);
        if (ed) {
                ct = &ed->ct;
                cpus_time_lock(ct, flags);
                cpus_time_update_running(ct, cpu, get_ntime(), start_time);
                cpus_time_unlock(ct, flags);
        }
-
-       return 0;
 }
 
-static int ret_handler_switch(struct kretprobe_instance *ri,
-                             struct pt_regs *regs)
+static void do_ret_handler_switch(struct task_struct *task)
 {
        int cpu;
        struct cpus_time *ct;
@@ -410,19 +419,32 @@ static int ret_handler_switch(struct kretprobe_instance *ri,
 
        cpu = smp_processor_id();
 
-       ct = current->tgid ? &ed_system.ct : &ct_idle;
+       ct = task->tgid ? &ed_system.ct : &ct_idle;
        cpus_time_lock(ct, flags);
        cpus_time_save_entry(ct, cpu, get_ntime());
        cpus_time_unlock(ct, flags);
 
-       ed = get_energy_data(current);
+       ed = get_energy_data(task);
        if (ed) {
                ct = &ed->ct;
                cpus_time_lock(ct, flags);
                cpus_time_save_entry(ct, cpu, get_ntime());
                cpus_time_unlock(ct, flags);
        }
+}
 
+#ifndef CONFIG_SWAP_HOOK_SWITCH_TO
+static int ret_handler_switch(struct kretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       do_ret_handler_switch(current);
+       return 0;
+}
+
+static int entry_handler_switch(struct kretprobe_instance *ri,
+                               struct pt_regs *regs)
+{
+       do_entry_handler_switch(current);
        return 0;
 }
 
@@ -430,6 +452,7 @@ static struct kretprobe switch_to_krp = {
        .entry_handler = entry_handler_switch,
        .handler = ret_handler_switch,
 };
+#endif /* !CONFIG_SWAP_HOOK_SWITCH_TO */
 
 
 
@@ -443,6 +466,7 @@ struct sys_read_data {
        int fd;
 };
 
+#ifndef CONFIG_SWAP_HOOK_ENERGY
 static int entry_handler_sys_read(struct kretprobe_instance *ri,
                                  struct pt_regs *regs)
 {
@@ -528,6 +552,7 @@ static struct kretprobe sys_write_krp = {
        .handler = ret_handler_sys_write,
        .data_size = sizeof(struct sys_read_data)
 };
+#endif /* !CONFIG_SWAP_HOOK_ENERGY */
 
 
 
@@ -586,11 +611,12 @@ static struct energy_data *get_energy_data_by_socket(struct task_struct *task,
        return ed;
 }
 
+#ifndef CONFIG_SWAP_HOOK_ENERGY
 static int wf_sock_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        struct socket *socket = (struct socket *)swap_get_karg(regs, 0);
 
-       *(struct socket **)ri->data = check_wlan0(socket) ? socket : NULL;
+       *(struct socket **)ri->data = socket;
 
        return 0;
 }
@@ -600,47 +626,53 @@ static int wf_sock_aio_eh(struct kretprobe_instance *ri, struct pt_regs *regs)
        struct kiocb *iocb = (struct kiocb *)swap_get_karg(regs, 0);
        struct socket *socket = iocb->ki_filp->private_data;
 
-       *(struct socket **)ri->data = check_wlan0(socket) ? socket : NULL;
+       *(struct socket **)ri->data = socket;
 
        return 0;
 }
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
 
-static int wf_sock_recv_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
+static void calc_wifi_recv_energy(struct socket *sock, int len)
 {
-       int ret = regs_return_value(regs);
+       struct energy_data *ed;
 
-       if (ret > 0) {
-               struct socket *socket = *(struct socket **)ri->data;
+       if (len <= 0 || check_wlan0(sock));
+               return;
 
-               if (socket) {
-                       struct energy_data *ed;
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_recv);
+       atomic64_add(len, &ed_system.bytes_recv);
+}
 
-                       ed = get_energy_data_by_socket(current, socket);
-                       if (ed)
-                               atomic64_add(ret, &ed->bytes_recv);
-                       atomic64_add(ret, &ed_system.bytes_recv);
-               }
-       }
+static void calc_wifi_send_energy(struct socket *sock, int len)
+{
+       struct energy_data *ed;
 
-       return 0;
+       if (len <= 0 || check_wlan0(sock));
+               return;
+
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_send);
+       atomic64_add(len, &ed_system.bytes_send);
 }
 
-static int wf_sock_send_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
+#ifndef CONFIG_SWAP_HOOK_ENERGY
+static int wf_sock_recv_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
 {
        int ret = regs_return_value(regs);
 
-       if (ret > 0) {
-               struct socket *socket = *(struct socket **)ri->data;
+       calc_wifi_recv_energy(*(struct socket **)ri->data, ret);
 
-               if (socket) {
-                       struct energy_data *ed;
+       return 0;
+}
 
-                       ed = get_energy_data_by_socket(current, socket);
-                       if (ed)
-                               atomic64_add(ret, &ed->bytes_send);
-                       atomic64_add(ret, &ed_system.bytes_send);
-               }
-       }
+static int wf_sock_send_rh(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+       int ret = regs_return_value(regs);
+
+       calc_wifi_send_energy(*(struct socket **)ri->data, ret);
 
        return 0;
 }
@@ -698,6 +730,7 @@ static struct kern_probe wifi_probes[] = {
 
 enum { wifi_probes_cnt = ARRAY_SIZE(wifi_probes) };
 static int wifi_flag = 0;
+#endif /* !CONFIG_SWAP_HOOK_ENERGY */
 
 
 
@@ -712,6 +745,33 @@ struct swap_bt_data {
        struct socket *socket;
 };
 
+static void calc_bt_recv_energy(struct socket *sock, int len)
+{
+       struct energy_data *ed;
+
+       if (len <= 0 || !sock)
+               return;
+
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_l2cap_recv_acldata);
+       atomic64_add(len, &ed_system.bytes_l2cap_recv_acldata);
+}
+
+static void calc_bt_send_energy(struct socket *sock, int len)
+{
+       struct energy_data *ed;
+
+       if (len <= 0 || !sock)
+               return;
+
+       ed = get_energy_data_by_socket(current, sock);
+       if (ed)
+               atomic64_add(len, &ed->bytes_hci_send_sco);
+       atomic64_add(len, &ed_system.bytes_hci_send_sco);
+}
+
+#ifndef CONFIG_SWAP_HOOK_ENERGY
 static int bt_entry_handler(struct kretprobe_instance *ri,
                            struct pt_regs *regs)
 {
@@ -729,18 +789,7 @@ static int bt_recvmsg_handler(struct kretprobe_instance *ri,
        int ret = regs_return_value(regs);
        struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
 
-       if (ret > 0) {
-               struct socket *socket = data->socket;
-
-               if (socket) {
-                       struct energy_data *ed;
-
-                       ed = get_energy_data_by_socket(current, socket);
-                       if (ed)
-                               atomic64_add(ret, &ed->bytes_l2cap_recv_acldata);
-               }
-               atomic64_add(ret, &ed_system.bytes_l2cap_recv_acldata);
-       }
+       calc_bt_recv_energy(data->socket, ret);
 
        return 0;
 }
@@ -751,18 +800,7 @@ static int bt_sendmsg_handler(struct kretprobe_instance *ri,
        int ret = regs_return_value(regs);
        struct swap_bt_data *data = (struct swap_bt_data *)ri->data;
 
-       if (ret > 0) {
-               struct socket *socket = data->socket;
-
-               if (socket) {
-                       struct energy_data *ed;
-
-                       ed = get_energy_data_by_socket(current, socket);
-                       if (ed)
-                               atomic64_add(ret, &ed->bytes_hci_send_sco);
-               }
-               atomic64_add(ret, &ed_system.bytes_hci_send_sco);
-       }
+       calc_bt_send_energy(data->socket, ret);
 
        return 0;
 }
@@ -851,6 +889,7 @@ static struct kern_probe bt_probes[] = {
 
 enum { bt_probes_cnt = ARRAY_SIZE(bt_probes) };
 static int energy_bt_flag = 0;
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
 
 enum parameter_type {
        PT_CPU,
@@ -1014,6 +1053,128 @@ int get_parameter_energy(enum parameter_energy pe, void *buf, size_t sz)
        return ret;
 }
 
+#ifdef CONFIG_SWAP_HOOK_ENERGY
+static struct swap_hook_energy hook_energy = {
+       .bt_recvmsg = calc_bt_recv_energy,
+       .bt_sendmsg = calc_bt_send_energy,
+       .wifi_recvmsg = calc_wifi_recv_energy ,
+       .wifi_sendmsg = calc_wifi_send_energy
+};
+
+
+static struct td_raw sys_call_tdraw;
+
+static void entry_hook_sys_rw(struct hook_syscall *self, struct pt_regs *regs)
+{
+       struct sys_read_data *srd =
+               (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
+       srd->fd = (int)swap_get_sarg(regs, 0);
+}
+
+static void return_hook_sys_read(struct hook_syscall *self,
+                                struct pt_regs *regs)
+{
+       struct sys_read_data *srd;
+       struct energy_data *ed;
+       int ret = regs_return_value(regs);
+
+       if (ret <= 0)
+               return;
+
+       srd = (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
+       if (!check_file(srd->fd))
+               return;
+
+       ed = get_energy_data(current);
+       if (ed)
+               atomic64_add(ret, &ed->bytes_read);
+       atomic64_add(ret, &ed_system.bytes_read);
+}
+
+static void return_hook_sys_write(struct hook_syscall *self,
+                                 struct pt_regs *regs)
+{
+       struct sys_read_data *srd;
+       struct energy_data *ed;
+       int ret = regs_return_value(regs);
+
+       if (ret > 0)
+               return;
+
+       srd = (struct sys_read_data *)swap_td_raw(&sys_call_tdraw, current);
+       if (!check_file(srd->fd))
+               return;
+
+       ed = get_energy_data(current);
+       if (ed)
+               atomic64_add(ret, &ed->bytes_written);
+       atomic64_add(ret, &ed_system.bytes_written);
+}
+
+static struct hook_syscall sys_read_hook = {
+       .entry = entry_hook_sys_rw,
+       .exit = return_hook_sys_read
+};
+
+static struct hook_syscall sys_write_hook = {
+       .entry = entry_hook_sys_rw,
+       .exit = return_hook_sys_write
+};
+
+
+# ifdef CONFIG_SWAP_HOOK_SWITCH_TO
+static void handler_switch(struct task_struct *prev,
+                          struct task_struct *next)
+{
+       do_entry_handler_switch(prev);
+       do_ret_handler_switch(next);
+}
+
+static struct swap_hook_ctx switch_to_hook = {
+       .hook = handler_switch
+};
+# endif /* CONFIG_SWAP_HOOK_SWITCH_TO */
+
+int do_set_energy(void)
+{
+       int ret = 0;
+
+       init_data_energy();
+
+       swap_hook_ctx_reg(&switch_to_hook);
+       ret = swap_td_raw_reg(&sys_call_tdraw, sizeof(struct sys_read_data));
+       if (ret)
+               return ret;
+
+       hook_syscall_reg(&sys_read_hook, __NR_read);
+       hook_syscall_reg(&sys_write_hook, __NR_write);
+
+       /* TODO: add compat mode support */
+
+       swap_hook_energy_set(&hook_energy);
+       /* TODO: init lcd */
+
+       return ret;
+}
+
+void do_unset_energy(void)
+{
+       /* TODO: uinit lcd */
+       swap_hook_energy_unset();
+       swap_hook_ctx_unreg(&switch_to_hook);
+       hook_syscall_unreg(&sys_write_hook);
+       hook_syscall_unreg(&sys_read_hook);
+
+       swap_td_raw_unreg(&sys_call_tdraw);
+       uninit_data_energy();
+}
+
+int energy_once(void)
+{
+       return 0;
+}
+#else /* CONFIG_SWAP_HOOK_ENERGY */
+
 int do_set_energy(void)
 {
        int ret = 0;
@@ -1072,6 +1233,37 @@ void do_unset_energy(void)
        uninit_data_energy();
 }
 
+int energy_once(void)
+{
+       const char *sym;
+
+       sym = "__switch_to";
+       switch_to_krp.kp.addr = swap_ksyms(sym);
+       if (switch_to_krp.kp.addr == 0)
+               goto not_found;
+
+       sym = "sys_read";
+       sys_read_krp.kp.addr = swap_ksyms(sym);
+       if (sys_read_krp.kp.addr == 0)
+               goto not_found;
+
+       sym = "sys_write";
+       sys_write_krp.kp.addr = swap_ksyms(sym);
+       if (sys_write_krp.kp.addr == 0)
+               goto not_found;
+
+       energy_xxx_once(bt_probes, bt_probes_cnt);
+       energy_xxx_once(wifi_probes, wifi_probes_cnt);
+
+       return 0;
+
+not_found:
+       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+       return -ESRCH;
+}
+
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
+
 static DEFINE_MUTEX(mutex_enable);
 static int energy_enable;
 
@@ -1127,35 +1319,6 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(unset_energy);
 
-int energy_once(void)
-{
-       const char *sym;
-
-       sym = "__switch_to";
-       switch_to_krp.kp.addr = swap_ksyms(sym);
-       if (switch_to_krp.kp.addr == 0)
-               goto not_found;
-
-       sym = "sys_read";
-       sys_read_krp.kp.addr = swap_ksyms(sym);
-       if (sys_read_krp.kp.addr == 0)
-               goto not_found;
-
-       sym = "sys_write";
-       sys_write_krp.kp.addr = swap_ksyms(sym);
-       if (sys_write_krp.kp.addr == 0)
-               goto not_found;
-
-       energy_xxx_once(bt_probes, bt_probes_cnt);
-       energy_xxx_once(wifi_probes, wifi_probes_cnt);
-
-       return 0;
-
-not_found:
-       printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
-       return -ESRCH;
-}
-
 /**
  * @brief Initialization energy
  *