#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 =
* ============================================================================
*flag = 0;
}
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
* = __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;
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;
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;
}
.entry_handler = entry_handler_switch,
.handler = ret_handler_switch,
};
+#endif /* !CONFIG_SWAP_HOOK_SWITCH_TO */
int fd;
};
+#ifndef CONFIG_SWAP_HOOK_ENERGY
static int entry_handler_sys_read(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
.handler = ret_handler_sys_write,
.data_size = sizeof(struct sys_read_data)
};
+#endif /* !CONFIG_SWAP_HOOK_ENERGY */
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;
}
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;
}
enum { wifi_probes_cnt = ARRAY_SIZE(wifi_probes) };
static int wifi_flag = 0;
+#endif /* !CONFIG_SWAP_HOOK_ENERGY */
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)
{
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;
}
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;
}
enum { bt_probes_cnt = ARRAY_SIZE(bt_probes) };
static int energy_bt_flag = 0;
+#endif /* CONFIG_SWAP_HOOK_ENERGY */
enum parameter_type {
PT_CPU,
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;
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;
}
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
*