From 45c9abf9a7831dee1d3665e9f7aad613224f264b Mon Sep 17 00:00:00 2001 From: Vyacheslav Cherkashin Date: Mon, 2 Mar 2015 14:38:31 +0300 Subject: [PATCH] [FEATURE] wsp implement (for webkit) Change-Id: I7da74b9c5d5c21e070e908ff2f5ab885ead78e8f Signed-off-by: Vyacheslav Cherkashin --- Kbuild | 3 +- packaging/swap-modules.spec | 2 + us_manager/pf/pf_group.c | 1 + writer/swap_msg.h | 1 + wsp/Kbuild | 8 + wsp/wsp.c | 506 ++++++++++++++++++++++++++++++++++++++++++++ wsp/wsp.h | 41 ++++ wsp/wsp_debugfs.c | 179 ++++++++++++++++ wsp/wsp_debugfs.h | 30 +++ wsp/wsp_module.c | 31 +++ wsp/wsp_msg.c | 134 ++++++++++++ wsp/wsp_msg.h | 42 ++++ wsp/wsp_res.c | 287 +++++++++++++++++++++++++ wsp/wsp_res.h | 75 +++++++ 14 files changed, 1339 insertions(+), 1 deletion(-) create mode 100644 wsp/Kbuild create mode 100644 wsp/wsp.c create mode 100644 wsp/wsp.h create mode 100644 wsp/wsp_debugfs.c create mode 100644 wsp/wsp_debugfs.h create mode 100644 wsp/wsp_module.c create mode 100644 wsp/wsp_msg.c create mode 100644 wsp/wsp_msg.h create mode 100644 wsp/wsp_res.c create mode 100644 wsp/wsp_res.h diff --git a/Kbuild b/Kbuild index cbf9dac..66a3c89 100644 --- a/Kbuild +++ b/Kbuild @@ -17,4 +17,5 @@ obj-m := master/ \ webprobe/ \ task_data/ \ preload/ \ - fbiprobe/ + fbiprobe/ \ + wsp/ diff --git a/packaging/swap-modules.spec b/packaging/swap-modules.spec index a7af233..0f9f7f9 100755 --- a/packaging/swap-modules.spec +++ b/packaging/swap-modules.spec @@ -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 diff --git a/us_manager/pf/pf_group.c b/us_manager/pf/pf_group.c index 06d85a0..881dde4 100644 --- a/us_manager/pf/pf_group.c +++ b/us_manager/pf/pf_group.c @@ -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 diff --git a/writer/swap_msg.h b/writer/swap_msg.h index 1748a59..24f2c6f 100644 --- a/writer/swap_msg.h +++ b/writer/swap_msg.h @@ -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 index 0000000..580bb29 --- /dev/null +++ b/wsp/Kbuild @@ -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 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 + * + */ + + +#include +#include +#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 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 + * + */ + + +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 index 0000000..09189f1 --- /dev/null +++ b/wsp/wsp_debugfs.c @@ -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 + * + */ + + +#include +#include +#include +#include +#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 index 0000000..b43f664 --- /dev/null +++ b/wsp/wsp_debugfs.h @@ -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 + * + */ + + +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 index 0000000..541d9a5 --- /dev/null +++ b/wsp/wsp_module.c @@ -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 + * + */ + + +#include +#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 index 0000000..2b836a6 --- /dev/null +++ b/wsp/wsp_msg.c @@ -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 + * + */ + + +#include +#include +#include +#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 index 0000000..04dadca --- /dev/null +++ b/wsp/wsp_msg.h @@ -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 + * + */ + + +#include + + +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 index 0000000..74ad258 --- /dev/null +++ b/wsp/wsp_res.c @@ -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 + * + */ + + +#include +#include +#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 index 0000000..a5249dc --- /dev/null +++ b/wsp/wsp_res.h @@ -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 + * + */ + + +#include + + +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 */ -- 2.7.4