[FEATURE] wsp implement (for webkit) 67/39867/3
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 2 Mar 2015 11:38:31 +0000 (14:38 +0300)
committerVyacheslav Cherkashin <v.cherkashin@samsung.com>
Wed, 27 May 2015 10:59:31 +0000 (13:59 +0300)
Change-Id: I7da74b9c5d5c21e070e908ff2f5ab885ead78e8f
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
14 files changed:
Kbuild
packaging/swap-modules.spec
us_manager/pf/pf_group.c
writer/swap_msg.h
wsp/Kbuild [new file with mode: 0644]
wsp/wsp.c [new file with mode: 0644]
wsp/wsp.h [new file with mode: 0644]
wsp/wsp_debugfs.c [new file with mode: 0644]
wsp/wsp_debugfs.h [new file with mode: 0644]
wsp/wsp_module.c [new file with mode: 0644]
wsp/wsp_msg.c [new file with mode: 0644]
wsp/wsp_msg.h [new file with mode: 0644]
wsp/wsp_res.c [new file with mode: 0644]
wsp/wsp_res.h [new file with mode: 0644]

diff --git a/Kbuild b/Kbuild
index cbf9dac..66a3c89 100644 (file)
--- a/Kbuild
+++ b/Kbuild
@@ -17,4 +17,5 @@ obj-m := master/ \
          webprobe/ \
          task_data/ \
          preload/ \
-         fbiprobe/
+         fbiprobe/ \
+         wsp/
index a7af233..0f9f7f9 100755 (executable)
@@ -48,6 +48,7 @@ install -m 666 webprobe/swap_webprobe.ko -t %{buildroot}/opt/swap/sdk
 install -m 666 task_data/swap_task_data.ko -t %{buildroot}/opt/swap/sdk
 install -m 666 preload/swap_preload.ko -t %{buildroot}/opt/swap/sdk
 install -m 666 fbiprobe/swap_fbiprobe.ko -t %{buildroot}/opt/swap/sdk
+install -m 666 wsp/swap_wsp.ko -t %{buildroot}/opt/swap/sdk
 
 %files
 %defattr(-,root,root)
@@ -69,3 +70,4 @@ install -m 666 fbiprobe/swap_fbiprobe.ko -t %{buildroot}/opt/swap/sdk
 /opt/swap/sdk/swap_task_data.ko
 /opt/swap/sdk/swap_preload.ko
 /opt/swap/sdk/swap_fbiprobe.ko
+/opt/swap/sdk/swap_wsp.ko
index 06d85a0..881dde4 100644 (file)
@@ -384,6 +384,7 @@ void put_pf_group(struct pf_group *pfg)
                free_pfg(pfg);
        }
 }
+EXPORT_SYMBOL_GPL(put_pf_group);
 
 /**
  * @brief Register prober for pf_grpup struct
index 1748a59..24f2c6f 100644 (file)
@@ -47,6 +47,7 @@ enum swap_msg_id {
        MSG_PROC_COMM                   = 0x0014,
        MSG_WEB_FUNCTION_ENTRY          = 0x0015,
        MSG_WEB_FUNCTION_EXIT           = 0x0016,
+       MSG_WSP                         = 0x001a,
        MSG_FBI                         = 0x0020
 };
 
diff --git a/wsp/Kbuild b/wsp/Kbuild
new file mode 100644 (file)
index 0000000..580bb29
--- /dev/null
@@ -0,0 +1,8 @@
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_wsp.o
+swap_wsp-y := wsp_module.o \
+              wsp_msg.o \
+              wsp_debugfs.o \
+              wsp.o \
+              wsp_res.o
diff --git a/wsp/wsp.c b/wsp/wsp.c
new file mode 100644 (file)
index 0000000..908e303
--- /dev/null
+++ b/wsp/wsp.c
@@ -0,0 +1,506 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <us_manager/sspt/sspt.h>
+#include <us_manager/probes/probe_info_new.h>
+#include "wsp.h"
+#include "wsp_res.h"
+#include "wsp_msg.h"
+
+
+struct wsp_probe {
+       const char *name;
+       struct probe_new probe;
+};
+
+struct wsp_bin {
+       const char *name;
+       unsigned long cnt;
+       struct wsp_probe *probe_array;
+};
+
+
+static const char webapp_path[] = "/usr/bin/WebProcess";
+static const char ewebkit_path[] = "/usr/lib/libewebkit2.so";
+
+
+#define WSP_PROBE_MAKE(_name, _info)   \
+{                                      \
+       .name = _name,                  \
+       .probe.offset = 0,              \
+       .probe.info = _info             \
+}
+
+
+static const char *strdup_from_user(const char __user *user_s)
+{
+       enum { max_str_len = 1024 };
+       char *str;
+       int len_s, ret;
+
+       len_s = strnlen_user(user_s, max_str_len - 1);
+       str = kmalloc(len_s + 1, GFP_ATOMIC);
+       if (str == NULL)
+               return NULL;
+
+       ret = strncpy_from_user(str, user_s, len_s);
+       if (ret < 0) {
+               kfree(str);
+               return NULL;
+       }
+
+       str[ret] = '\0';
+
+       return str;
+}
+
+static void do_res_processing_begin(void *data, void *ptr, enum wsp_res_t type)
+{
+       struct wsp_res **save_res = (struct wsp_res **)data;
+       struct wsp_res *res;
+
+       res = wsp_res_find(ptr, type);
+
+       /* save res pointer */
+       *save_res = res;
+       if (res) {
+               wsp_msg(WSP_RES_PROC_BEGIN, res->id, NULL);
+               wsp_res_stat_set_next(res, WRS_ADD_DATA);
+       }
+}
+
+static void do_res_processing_end(struct wsp_res *res)
+{
+       wsp_msg(WSP_RES_PROC_END, res->id, NULL);
+}
+
+static void do_res_finish(struct wsp_res *res)
+{
+       wsp_msg(WSP_RES_LOAD_END, res->id, NULL);
+       wsp_res_stat_set_next(res, WRS_FINISH);
+       wsp_res_del(res);
+}
+
+
+/*
+ * soup_req
+ */
+static int soup_req_handle(struct kprobe *p, struct pt_regs *regs)
+{
+       enum { max_str_len = 512 };
+       const char *path;
+       struct wsp_res *res;
+
+       res = wsp_res_last();
+       if (res == NULL) {
+               pr_err("last wsp_res is not found\n");
+               return 0;
+       }
+
+       path = strdup_from_user((const char __user *)swap_get_uarg(regs, 1));
+       wsp_msg(WSP_RES_LOAD_BEGIN, res->id, path);
+       wsp_res_stat_set_next(res, WRS_SOUP_REQ);
+       kfree(path);
+
+       return 0;
+}
+
+static struct probe_info_new soup_req = MAKE_UPROBE(soup_req_handle);
+
+
+/*
+ * main_res_req
+ */
+static int mres_req_handle(struct kprobe *p, struct pt_regs *regs)
+{
+       void *ptr = (void *)swap_get_uarg(regs, 0);
+       struct wsp_res *res;
+
+       res = wsp_res_new(ptr, WR_MAIN);
+       wsp_res_stat_set_next(res, WRS_WILL_REQ);
+
+       return 0;
+}
+
+static struct probe_info_new mres_req = MAKE_UPROBE(mres_req_handle);
+
+
+/*
+ * main_res_add_data
+ */
+
+static int mres_adata_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       void *ptr = (void *)swap_get_uarg(regs, 0);
+
+       do_res_processing_begin(ri->data, ptr, WR_MAIN);
+
+       return 0;
+}
+
+static int mres_adata_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       struct wsp_res *res = *(struct wsp_res **)ri->data;
+
+       if (res)
+               do_res_processing_end(res);
+
+       return 0;
+}
+
+static struct probe_info_new mres_adata =
+               MAKE_URPROBE(mres_adata_eh, mres_adata_rh,
+                            sizeof(struct wsp_res *));
+
+
+/*
+ * main_res_finish
+ */
+static int mres_finish_handle(struct kprobe *p, struct pt_regs *regs)
+{
+       void *ptr = (void *)swap_get_uarg(regs, 0);
+       struct wsp_res *res;
+
+       res = wsp_res_find(ptr, WR_MAIN);
+       if (res) {
+               wsp_current_set_stat(TDS_FINISH_MAIN_LOAD);
+               do_res_finish(res);
+       }
+
+       return 0;
+}
+
+static struct probe_info_new mres_finish = MAKE_UPROBE(mres_finish_handle);
+
+
+/*
+ * res_request
+ */
+static int res_request_handle(struct kprobe *p, struct pt_regs *regs)
+{
+       void *ptr = (void *)swap_get_uarg(regs, 0);
+       struct wsp_res *res;
+
+       res = wsp_res_last();
+       if (res) {
+               if (res->type == WR_MAIN && res->stat == WRS_WILL_REQ)
+                       /* skip */
+                       return 0;
+       }
+
+       res = wsp_res_new(ptr, WR_ANY);
+       wsp_res_stat_set_next(res, WRS_WILL_REQ);
+
+       return 0;
+}
+
+static struct probe_info_new res_request = MAKE_UPROBE(res_request_handle);
+
+
+/*
+ * res_finish
+ */
+static int res_finish_ehandle(struct uretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       void *ptr = (void *)swap_get_uarg(regs, 0);
+
+       do_res_processing_begin(ri->data, ptr, WR_ANY);
+
+       return 0;
+}
+
+static int res_finish_rhandle(struct uretprobe_instance *ri,
+                             struct pt_regs *regs)
+{
+       struct wsp_res *res = *(struct wsp_res **)ri->data;
+
+       if (res) {
+               do_res_processing_end(res);
+               do_res_finish(res);
+       }
+
+       return 0;
+}
+
+static struct probe_info_new res_finish =
+               MAKE_URPROBE(res_finish_ehandle, res_finish_rhandle,
+                            sizeof(struct wsp_res *));
+
+
+/*
+ * redraw
+ */
+static int redraw_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       enum tdata_stat stat;
+
+       stat = wsp_current_get_stat();
+
+       if (stat == TDS_FINISH_MAIN_LOAD)
+               wsp_msg(WSP_DRAW_BEGIN, 0, NULL);
+
+       return 0;
+}
+
+static int redraw_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+       if (wsp_current_get_stat() == TDS_FINISH_MAIN_LOAD) {
+               wsp_current_set_stat(TDS_DRAW);
+               wsp_msg(WSP_DRAW_END, 0, NULL);
+       }
+
+       return 0;
+}
+
+static struct probe_info_new redraw = MAKE_URPROBE(redraw_eh, redraw_rh, 0);
+
+
+static struct wsp_probe ewebkit_probe_array[] = {
+       /* plt */
+       /* soup_requester_request@plt */
+       WSP_PROBE_MAKE("soup_requester_request@plt", &soup_req),
+
+       /* main_res */
+       /* WebCore::MainResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
+       WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &mres_req),
+       /* WebCore::MainResourceLoader::addData(char const*, int, bool) */
+       WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader7addDataEPKcib", &mres_adata),
+       /* WebCore::MainResourceLoader::didFinishLoading(double) */
+       WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader16didFinishLoadingEd", &mres_finish),
+
+
+       /* res */
+       /* WebCore::ResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
+       WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &res_request),
+       /* WebCore::ResourceLoader::didFinishLoading(WebCore::ResourceHandle*, double) */
+       WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader16didFinishLoadingEPNS_14ResourceHandleEd", &res_finish),
+
+
+       /* redraw */
+       /* WebKit::LayerTreeCoordinator::flushPendingLayerChanges() */
+       WSP_PROBE_MAKE("_ZN6WebKit20LayerTreeCoordinator24flushPendingLayerChangesEv", &redraw),
+};
+
+enum {
+       ewebkit_probes_cnt =
+               sizeof(ewebkit_probe_array) / sizeof(struct wsp_probe)
+};
+
+static struct wsp_bin ewebkit = {
+       .name = ewebkit_path,
+       .cnt = ewebkit_probes_cnt,
+       .probe_array = ewebkit_probe_array
+};
+
+
+/* check ewebkit_probe_array on init address */
+static bool wsp_is_addr_init(void)
+{
+       int i;
+
+       for (i = 0; i < ewebkit_probes_cnt; ++i)
+               if (ewebkit_probe_array[i].probe.offset == 0)
+                       return false;
+
+       return true;
+}
+
+
+static int wsp_probe_register(struct pf_group *pfg, struct dentry *dentry,
+                             struct wsp_probe *wsp_probe)
+{
+       struct probe_new *probe_new = &wsp_probe->probe;
+
+       return pin_register(probe_new, pfg, dentry);
+}
+
+static void wsp_probe_unregister(struct pf_group *pfg, struct dentry *dentry,
+                                struct wsp_probe *wsp_probe)
+{
+       struct probe_new *probe_new = &wsp_probe->probe;
+
+       pin_unregister(probe_new, pfg, dentry);
+}
+
+
+
+
+static int wsp_bin_register(struct pf_group *pfg, struct wsp_bin *bin)
+{
+       int i, ret;
+       struct dentry *dentry;
+
+       dentry = dentry_by_path(bin->name);
+       if (dentry == NULL) {
+               pr_err("dentry not found (path='%s'\n", bin->name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < bin->cnt; ++i) {
+               struct wsp_probe *p = &bin->probe_array[i];
+
+               ret = wsp_probe_register(pfg, dentry, p);
+               if (ret) {
+                       pr_err("ERROR: wsp_probe_register, addr=%lx ret=%d\n",
+                              p->probe.offset, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static void wsp_bin_unregister(struct pf_group *pfg, struct wsp_bin *bin)
+{
+       int i;
+       struct dentry *dentry;
+
+       dentry = dentry_by_path(bin->name);
+       for (i = 0; i < bin->cnt; ++i)
+               wsp_probe_unregister(pfg, dentry, &bin->probe_array[i]);
+}
+
+
+static struct pf_group *g_pfg;
+
+static int wsp_app_register(void)
+{
+       struct dentry *dentry;
+
+       dentry = dentry_by_path(webapp_path);
+       if (dentry == NULL) {
+               pr_err("dentry not found (path='%s'\n", webapp_path);
+               return -EINVAL;
+       }
+
+       g_pfg = get_pf_group_by_dentry(dentry, (void *)dentry);
+       if (g_pfg == NULL) {
+               pr_err("g_pfg is NULL (by dentry=%p)\n", dentry);
+               return -ENOMEM;
+       }
+
+       return wsp_bin_register(g_pfg, &ewebkit);
+}
+
+static void wsp_app_unregister(void)
+{
+       wsp_bin_unregister(g_pfg, &ewebkit);
+       put_pf_group(g_pfg);
+}
+
+
+static int do_wsp_on(void)
+{
+       int ret;
+
+       ret = wsp_res_init();
+       if (ret)
+               return ret;
+
+       ret = wsp_app_register();
+       if (ret)
+               wsp_res_exit();
+
+       return ret;
+}
+
+static void do_wsp_off(void)
+{
+       wsp_app_unregister();
+       wsp_res_exit();
+}
+
+
+static enum wsp_mode g_mode = WSP_OFF;
+static DEFINE_MUTEX(g_mode_mutex);
+
+int wsp_set_addr(const char *name, unsigned long offset)
+{
+       int i, ret = 0;
+
+       if (mutex_trylock(&g_mode_mutex) == 0)
+               return -EBUSY;
+
+       for (i = 0; i < ewebkit_probes_cnt; ++i) {
+               if (0 == strcmp(name, ewebkit_probe_array[i].name)) {
+                       ewebkit_probe_array[i].probe.offset = offset;
+                       goto unlock;
+               }
+       }
+
+       ret = -EINVAL;
+
+unlock:
+       mutex_unlock(&g_mode_mutex);
+       return ret;
+}
+
+int wsp_set_mode(enum wsp_mode mode)
+{
+       int ret = 0;
+
+       mutex_lock(&g_mode_mutex);
+       switch (mode) {
+       case WSP_ON:
+               if (g_mode == WSP_ON) {
+                       ret = -EBUSY;
+                       goto unlock;
+               }
+
+               ret = wsp_is_addr_init() ? do_wsp_on() : -EPERM;
+               break;
+       case WSP_OFF:
+               if (g_mode == WSP_OFF) {
+                       ret = -EBUSY;
+                       goto unlock;
+               }
+
+               do_wsp_off();
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+unlock:
+       if (ret == 0)
+               g_mode = mode;
+
+       mutex_unlock(&g_mode_mutex);
+       return ret;
+}
+
+enum wsp_mode wsp_get_mode(void)
+{
+       return g_mode;
+}
+
+int wsp_init(void)
+{
+       return 0;
+}
+
+void wsp_exit(void)
+{
+       wsp_set_mode(WSP_OFF);
+}
diff --git a/wsp/wsp.h b/wsp/wsp.h
new file mode 100644 (file)
index 0000000..9a1db28
--- /dev/null
+++ b/wsp/wsp.h
@@ -0,0 +1,41 @@
+#ifndef _WSP_H
+#define _WSP_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+enum wsp_mode {
+       WSP_ON,
+       WSP_OFF
+};
+
+
+int wsp_set_addr(const char *name, unsigned long offset);
+
+int wsp_set_mode(enum wsp_mode mode);
+enum wsp_mode wsp_get_mode(void);
+
+int wsp_init(void);
+void wsp_exit(void);
+
+
+#endif /* _WSP_H */
diff --git a/wsp/wsp_debugfs.c b/wsp/wsp_debugfs.c
new file mode 100644 (file)
index 0000000..09189f1
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <master/swap_debugfs.h>
+#include "wsp.h"
+
+
+static int do_write_cmd(const char *buf, size_t count)
+{
+       int n, ret = 0;
+       char *name;
+       unsigned long offset;
+
+       name = kmalloc(count, GFP_KERNEL);
+       if (name == NULL)
+               return -ENOMEM;
+
+       n = sscanf(buf, "%lx %s", &offset, name);
+       if (n != 2) {
+               ret = -EINVAL;
+               goto free_name;
+       }
+
+       ret = wsp_set_addr(name, offset);
+
+free_name:
+       kfree(name);
+       return ret;
+}
+
+/* ============================================================================
+ * ===                         DEBUGFS FOR ENABLE                           ===
+ * ============================================================================
+ */
+static ssize_t write_cmd(struct file *file, const char __user *user_buf,
+                        size_t count, loff_t *ppos)
+{
+       enum { max_count = 1024 };
+       int ret;
+       char *buf;
+
+       if (count > max_count)
+               return -ENOMEM;
+
+       buf = kmalloc(count + 1, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(buf, user_buf, count)) {
+               ret = -EFAULT;
+               goto free_buf;
+       }
+
+       buf[count] = '\0';
+       ret = do_write_cmd(buf, count);
+
+free_buf:
+       kfree(buf);
+       return ret ? ret : count;
+}
+
+static const struct file_operations fops_cmd = {
+       .write =        write_cmd,
+       .llseek =       default_llseek,
+};
+
+
+
+
+/* ============================================================================
+ * ===                         DEBUGFS FOR ENABLE                           ===
+ * ============================================================================
+ */
+static ssize_t read_enabled(struct file *file, char __user *user_buf,
+                           size_t count, loff_t *ppos)
+{
+       char buf[2];
+
+       buf[0] = wsp_get_mode() == WSP_OFF ? '0' : '1';
+       buf[1] = '\n';
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled(struct file *file, const char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       int ret = 0;
+       char buf[32];
+       size_t buf_size;
+
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       switch (buf[0]) {
+       case '1':
+               ret = wsp_set_mode(WSP_ON);
+               break;
+       case '0':
+               ret = wsp_set_mode(WSP_OFF);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static const struct file_operations fops_enabled = {
+       .read =         read_enabled,
+       .write =        write_enabled,
+       .llseek =       default_llseek,
+};
+
+
+static struct dentry *wsp_dir;
+
+void wsp_debugfs_exit(void)
+{
+       if (wsp_dir)
+               debugfs_remove_recursive(wsp_dir);
+
+       wsp_dir = NULL;
+}
+
+int wsp_debugfs_init(void)
+{
+       struct dentry *dentry;
+
+       dentry = swap_debugfs_getdir();
+       if (dentry == NULL)
+               return -ENOENT;
+
+       wsp_dir = debugfs_create_dir("wsp", dentry);
+       if (wsp_dir == NULL)
+               return -ENOMEM;
+
+       dentry = debugfs_create_file("enabled", 0600, wsp_dir, NULL,
+                                    &fops_enabled);
+       if (dentry == NULL)
+               goto fail;
+
+       dentry = debugfs_create_file("cmd", 0600, wsp_dir, NULL, &fops_cmd);
+       if (dentry == NULL)
+               goto fail;
+
+       return 0;
+
+fail:
+       wsp_debugfs_exit();
+       return -ENOMEM;
+}
diff --git a/wsp/wsp_debugfs.h b/wsp/wsp_debugfs.h
new file mode 100644 (file)
index 0000000..b43f664
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _WSP_DEBUGFS_H
+#define _WSP_DEBUGFS_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+int wsp_debugfs_init(void);
+void wsp_debugfs_exit(void);
+
+
+#endif /* _WSP_DEBUGFS_H */
diff --git a/wsp/wsp_module.c b/wsp/wsp_module.c
new file mode 100644 (file)
index 0000000..541d9a5
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <master/swap_initializer.h>
+#include "wsp.h"
+#include "wsp_debugfs.h"
+
+
+SWAP_LIGHT_INIT_MODULE(NULL, wsp_init, wsp_exit,
+                      wsp_debugfs_init, wsp_debugfs_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/wsp/wsp_msg.c b/wsp/wsp_msg.c
new file mode 100644 (file)
index 0000000..2b836a6
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <writer/swap_msg.h>
+#include "wsp_msg.h"
+
+
+/*
+ * MSG_WSP (payload):
+ * +-------------+----------+----------+
+ * | name        | type     | lenght   |
+ * +-------------+----------+----------+
+ * | PID         | int      |      4   |
+ * | wsp_id      | int      |      4   |
+ * | wsp_payload | variable | variable |
+ * +-------------+----------+----------+
+
+ * wsp_id:
+ *   - WSP_RES_LOAD_BEGIN = 0x0001
+ *   - WSP_RES_LOAD_END   = 0x0002
+ *   - WSP_RES_PROC_BEGIN = 0x0003
+ *   - WSP_RES_PROC_END   = 0x0004
+ *   - WSP_DRAW_BEGIN     = 0x0005
+ *   - WSP_DRAW_END       = 0x0006
+ *
+ * wsp_payload:
+ *
+ * 1. WSP_RES_LOAD_BEGIN:
+ *         +--------+--------+----------+
+ *         | name   | type   |  lenght  |
+ *         +--------+--------+----------+
+ *         | res_id | int    |     4    |
+ *         | path   | string | variable |
+ *         +--------+--------+----------+
+ *
+ * 2. WSP_RES_LOAD_END, WSP_RES_PROC_BEGIN, WSP_RES_PROC_END:
+ *         +--------+--------+----------+
+ *         | name   | type   |  lenght  |
+ *         +--------+--------+----------+
+ *         | res_id | int    |     4    |
+ *         +--------+--------+----------+
+ *
+ * 3. WSP_DRAW_BEGIN, WSP_DRAW_END:
+ *         no wsp_payload
+ */
+
+static int pack_wsp_msg(void *data, size_t size, enum wsp_id id,
+                       u32 res_id, const char *path)
+{
+       size_t len;
+       const size_t old_size = size;
+
+       /* write PID */
+       *(u32 *)data = (u32)current->tgid;
+       data += 4;
+       size -= 4;
+
+       /* write wsp_id */
+       *(u32 *)data = (u32)id;
+       data += 4;
+       size -= 4;
+
+       /* pack wsp_payload */
+       switch (id) {
+       case WSP_RES_LOAD_BEGIN:
+               len = strlen(path) + 1;
+               if (size < len + 4)
+                       return -ENOMEM;
+
+               /* '+ 4' - skip space for res_id */
+               memcpy(data + 4, path, len);
+               size -= len;
+       case WSP_RES_LOAD_END:
+       case WSP_RES_PROC_BEGIN:
+       case WSP_RES_PROC_END:
+               /* write res_id */
+               *(u32 *)data = res_id;
+               size -= 4;
+               break;
+
+       case WSP_DRAW_BEGIN:
+       case WSP_DRAW_END:
+               break;
+
+       default:
+               printk(KERN_ERR "unknown wsp_id: id=%u\n", (unsigned)id);
+               return -EINVAL;
+       }
+
+       return old_size - size;
+}
+
+void wsp_msg(enum wsp_id id, u32 res_id, const char *path)
+{
+       int ret;
+       void *data;
+       size_t size;
+       struct swap_msg *m;
+
+       m = swap_msg_get(MSG_WSP);
+       data = swap_msg_payload(m);
+       size = swap_msg_size(m);
+       ret = pack_wsp_msg(data, size, id, res_id, path);
+       if (ret < 0) {
+               printk(KERN_ERR "error MSG_WSP packing, ret=%d\n", ret);
+               goto put_msg;
+       }
+
+       swap_msg_flush(m, ret);
+
+put_msg:
+       swap_msg_put(m);
+}
diff --git a/wsp/wsp_msg.h b/wsp/wsp_msg.h
new file mode 100644 (file)
index 0000000..04dadca
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _WSP_MSG_H
+#define _WSP_MSG_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+
+
+enum wsp_id {
+       WSP_RES_LOAD_BEGIN = 0x0001,
+       WSP_RES_LOAD_END   = 0x0002,
+       WSP_RES_PROC_BEGIN = 0x0003,
+       WSP_RES_PROC_END   = 0x0004,
+       WSP_DRAW_BEGIN     = 0x0005,
+       WSP_DRAW_END       = 0x0006
+};
+
+
+void wsp_msg(enum wsp_id id, u32 res_id, const char *path);
+
+
+#endif /* _WSP_MSG_H */
diff --git a/wsp/wsp_res.c b/wsp/wsp_res.c
new file mode 100644 (file)
index 0000000..74ad258
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include "wsp_res.h"
+
+static atomic_t wsp_res_count;
+
+static int wsp_tdata_get_id(void)
+{
+       return atomic_inc_return(&wsp_res_count);
+}
+
+static struct wsp_tdata *g_tdata;
+
+/* FIXME: get_tdata() need receive for each processes */
+static struct wsp_tdata *get_tdata(void)
+{
+       return g_tdata;
+}
+
+
+
+
+
+/* ============================================================================
+ * =                                  wsp_tdata                               =
+ * ============================================================================
+ */
+struct wsp_tdata {
+       struct list_head res_list;
+       spinlock_t lock;
+
+       enum tdata_stat stat;
+};
+
+static struct wsp_res *wsp_tdata_new_res(struct wsp_tdata *d, void *ptr,
+                                        enum wsp_res_t type)
+{
+       struct wsp_res *res;
+
+       res = kmalloc(sizeof(*res), GFP_ATOMIC);
+       if (res) {
+               INIT_LIST_HEAD(&res->list);
+               res->ptr = ptr;
+               res->id = wsp_tdata_get_id();
+               res->type = type;
+               res->stat = WRS_NEW;
+
+               /* add to list */
+               spin_lock(&d->lock);
+               list_add(&res->list, &d->res_list);
+               spin_unlock(&d->lock);
+       }
+
+       return res;
+}
+
+static void wsp_tdata_del_res(struct wsp_res *res)
+{
+       list_del(&res->list);
+       kfree(res);
+}
+
+static struct wsp_tdata *wsp_tdata_create(void)
+{
+       struct wsp_tdata *d;
+
+       d = kmalloc(sizeof(*d), GFP_ATOMIC);
+       if (d) {
+               INIT_LIST_HEAD(&d->res_list);
+               spin_lock_init(&d->lock);
+               d->stat = TDS_NEW;
+       }
+
+       return d;
+}
+
+static void wsp_tdata_destroy(struct wsp_tdata *d)
+{
+       struct wsp_res *res, *n;
+
+       spin_lock(&d->lock);
+       list_for_each_entry_safe(res, n, &d->res_list, list)
+               wsp_tdata_del_res(res);
+       spin_unlock(&d->lock);
+}
+
+static struct wsp_res *wsp_tdata_last_res(struct wsp_tdata *d)
+{
+       struct wsp_res *res;
+
+       spin_lock(&d->lock);
+       res = list_first_entry_or_null(&d->res_list, struct wsp_res, list);
+       spin_unlock(&d->lock);
+
+       return res;
+}
+
+struct wsp_res *wsp_tdata_find_res(struct wsp_tdata *data, void *ptr,
+                                  enum wsp_res_t type)
+{
+       struct wsp_res *res;
+
+       list_for_each_entry(res, &data->res_list, list) {
+               if (res->type != type)
+                       continue;
+
+               if (res->ptr == ptr) {
+                       if (res->stat == WRS_ERR) {
+                               pr_err("ERR: something went wrong\n");
+                               return NULL;
+                       }
+
+                       return res;
+               }
+       }
+
+       return NULL;
+}
+
+
+
+
+
+/* ============================================================================
+ * =                          wsp_current_[get/set]_stat()                    =
+ * ============================================================================
+ */
+enum tdata_stat wsp_current_get_stat(void)
+{
+       struct wsp_tdata *d;
+
+       d = get_tdata();
+       if (d)
+               return d->stat;
+       else
+               pr_err("ERR: no current tdata\n");
+
+       return TDS_ERR;
+}
+
+void wsp_current_set_stat(enum tdata_stat stat)
+{
+       struct wsp_tdata *d;
+
+       d = get_tdata();
+       if (d)
+               d->stat = stat;
+       else
+               pr_err("ERR: no current tdata\n");
+}
+
+
+
+
+
+/* ============================================================================
+ * =                                   wsp_res                                =
+ * ============================================================================
+ */
+struct wsp_res *wsp_res_new(void *ptr, enum wsp_res_t type)
+{
+       struct wsp_tdata *data;
+
+       data = get_tdata();
+       if (data == NULL) {
+               pr_err("ERR: no current tdata\n");
+               return NULL;
+       }
+
+
+       return wsp_tdata_new_res(data, ptr, type);
+}
+
+void wsp_res_del(struct wsp_res *res)
+{
+       wsp_tdata_del_res(res);
+}
+
+struct wsp_res *wsp_res_find(void *ptr, enum wsp_res_t type)
+{
+       struct wsp_tdata *data;
+
+       data = get_tdata();
+       if (data == NULL) {
+               pr_err("ERR: no current tdata\n");
+               return NULL;
+       }
+
+       return wsp_tdata_find_res(data, ptr, type);
+}
+
+struct wsp_res *wsp_res_last(void)
+{
+       struct wsp_tdata *d;
+
+       d = get_tdata();
+       if (d == NULL) {
+               pr_err("ERR: no current tdata\n");
+               return NULL;
+       }
+
+       return wsp_tdata_last_res(d);
+}
+
+int wsp_res_stat_set_next(struct wsp_res *res, enum wsp_res_stat stat)
+{
+       switch (res->stat) {
+       case WRS_NEW:
+               if (stat == WRS_WILL_REQ) {
+                       res->stat = stat;
+                       return 0;
+               }
+               break;
+
+       case WRS_WILL_REQ:
+               if (stat == WRS_SOUP_REQ) {
+                       res->stat = stat;
+                       return 0;
+               }
+               break;
+
+       case WRS_SOUP_REQ:
+       case WRS_ADD_DATA:
+               if (stat == WRS_ADD_DATA || stat == WRS_FINISH) {
+                       res->stat = stat;
+                       return 0;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       pr_err("ERR: set_next_stat from %d to %d [id=%d]\n",
+              res->stat, stat, res->id);
+
+       res->stat = WRS_ERR;
+
+       return -1;
+}
+
+
+
+
+
+/* ============================================================================
+ * =                                init/exit()                               =
+ * ============================================================================
+ */
+int wsp_res_init(void)
+{
+       g_tdata = wsp_tdata_create();
+       if (g_tdata == NULL)
+               return -ENOMEM;
+
+       atomic_set(&wsp_res_count, 0);
+
+       return 0;
+}
+
+void wsp_res_exit(void)
+{
+       wsp_tdata_destroy(g_tdata);
+       g_tdata = NULL;
+}
diff --git a/wsp/wsp_res.h b/wsp/wsp_res.h
new file mode 100644 (file)
index 0000000..a5249dc
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef _WSP_TDATA_H
+#define _WSP_TDATA_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+
+
+enum tdata_stat {
+       TDS_ERR,
+       TDS_NEW,
+       TDS_FINISH_MAIN_LOAD,
+       TDS_DRAW
+};
+
+enum wsp_res_t {
+       WR_NONE,
+       WR_MAIN,
+       WR_ANY
+};
+
+enum wsp_res_stat {
+       WRS_NEW,
+       WRS_WILL_REQ,
+       WRS_SOUP_REQ,
+       WRS_ADD_DATA,
+       WRS_FINISH,
+       WRS_ERR
+};
+
+struct wsp_res {
+       struct list_head list;
+       void *ptr;
+       int id;
+       enum wsp_res_t type;
+       enum wsp_res_stat stat;
+};
+
+
+enum tdata_stat wsp_current_get_stat(void);
+void wsp_current_set_stat(enum tdata_stat stat);
+
+struct wsp_res *wsp_res_new(void *ptr, enum wsp_res_t type);
+void wsp_res_del(struct wsp_res *res);
+
+struct wsp_res *wsp_res_last(void);
+struct wsp_res *wsp_res_find(void *ptr, enum wsp_res_t type);
+
+int wsp_res_stat_set_next(struct wsp_res *res, enum wsp_res_stat stat);
+
+int wsp_res_init(void);
+void wsp_res_exit(void);
+
+
+#endif /* _WSP_TDATA_H */