Tizen 2.4.0 rev3 SDK Public Release
[kernel/swap-modules.git] / nsp / nsp_debugfs.c
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  *
16  * Copyright (C) Samsung Electronics, 2014
17  *
18  * 2014         Vyacheslav Cherkashin <v.cherkashin@samsung.com>
19  *
20  */
21
22
23 #include <linux/slab.h>
24 #include <linux/limits.h>
25 #include <linux/debugfs.h>
26 #include <linux/uaccess.h>
27 #include <master/swap_debugfs.h>
28 #include "nsp.h"
29
30
31 /* remove end-line symbols */
32 static void rm_endline_symbols(char *buf, size_t len)
33 {
34         char *p, *buf_end;
35
36         buf_end = buf + len;
37         for (p = buf; p != buf_end; ++p)
38                 if (*p == '\n' || *p == '\r')
39                         *p = '\0';
40 }
41
42 /*
43  * format:
44  *      main:app_path
45  *
46  * sample:
47  *      0x00000d60:/bin/app_sample
48  */
49 static int do_add(const char *buf, size_t len)
50 {
51         int n, ret;
52         char *app_path;
53         unsigned long main_addr;
54         const char fmt[] = "%%lx:/%%%ds";
55         char fmt_buf[64];
56
57         n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
58         if (n <= 0)
59                 return -EINVAL;
60
61         app_path = kmalloc(PATH_MAX, GFP_KERNEL);
62         if (app_path == NULL)
63                 return -ENOMEM;
64
65         n = sscanf(buf, fmt_buf, &main_addr, app_path + 1);
66         if (n != 2) {
67                 ret = -EINVAL;
68                 goto free_app_path;
69         }
70         app_path[0] = '/';
71
72         ret = nsp_add(app_path, main_addr);
73
74 free_app_path:
75         kfree(app_path);
76         return ret;
77 }
78
79 /*
80  * format:
81  *      path
82  *
83  * sample:
84  *      /tmp/sample
85  */
86 static int do_rm(const char *buf, size_t len)
87 {
88         return nsp_rm(buf);
89 }
90
91 static int do_rm_all(const char *buf, size_t len)
92 {
93         return nsp_rm_all();
94 }
95
96 /*
97  * format:
98  *      dlopen_addr@plt:dlsym_addr@plt:launchpad_path
99  *
100  * sample:
101  *      0x000234:0x000342:/usr/bin/launchpad-loader
102  */
103 static int do_set_lpad_info(const char *data, size_t len)
104 {
105         int n, ret;
106         unsigned long dlopen_addr;
107         unsigned long dlsym_addr;
108         char *lpad_path;
109         const char fmt[] = "%%lx:%%lx:/%%%ds";
110         char fmt_buf[64];
111
112         n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
113         if (n <= 0)
114                 return -EINVAL;
115
116         lpad_path = kmalloc(PATH_MAX, GFP_KERNEL);
117         if (lpad_path == NULL)
118                 return -ENOMEM;
119
120         n = sscanf(data, fmt_buf, &dlopen_addr, &dlsym_addr, lpad_path + 1);
121         if (n != 3) {
122                 ret = -EINVAL;
123                 goto free_lpad_path;
124         }
125         lpad_path[0] = '/';
126
127         ret = nsp_set_lpad_info(lpad_path, dlopen_addr, dlsym_addr);
128
129 free_lpad_path:
130         kfree(lpad_path);
131         return ret;
132 }
133
134 /*
135  * format:
136  *      appcore_efl_main:__do_app:appcore_init@plt:elm_run@plt:libappcore-efl
137  *
138  * sample:
139  *      0x3730:0x2960:0x1810:0x1c70:/usr/lib/libappcore-efl.so.1
140  */
141 static int do_set_appcore_info(const char *data, size_t len)
142 {
143         int n, ret;
144         struct appcore_info_data info;
145         const char fmt[] = "%%lx:%%lx:%%lx:%%lx:/%%%ds";
146         char fmt_buf[64];
147         char *path;
148
149         n = snprintf(fmt_buf, sizeof(fmt_buf), fmt, PATH_MAX - 2);
150         if (n <= 0)
151                 return -EINVAL;
152
153         path = kmalloc(PATH_MAX, GFP_KERNEL);
154         if (path == NULL)
155                 return -ENOMEM;
156
157         n = sscanf(data, fmt_buf,
158                    &info.ac_efl_main, &info.do_app,
159                    &info.ac_init, &info.elm_run, path + 1);
160         if (n != 5) {
161                 ret = -EINVAL;
162                 goto free_lib_path;
163         }
164         path[0] = '/';
165
166         info.path = path;
167         ret = nsp_set_appcore_info(&info);
168
169 free_lib_path:
170         kfree(path);
171         return ret;
172 }
173
174 /*
175  * format:
176  *      0 byte - type
177  *      1 byte - ' '
178  *      2.. bytes - data
179  */
180 static int do_cmd(const char *data, size_t len)
181 {
182         char type;
183         size_t len_data;
184         const char *cmd_data;
185
186         if (len) {
187                 if (data[0] == 'c')
188                         return do_rm_all(data + 1, len - 1);
189         }
190         /*
191          * 0 byte - type
192          * 1 byte - ' '
193          */
194         if (len < 2 || data[1] != ' ')
195                 return -EINVAL;
196
197         len_data = len - 2;
198         cmd_data = data + 2;
199         type = data[0];
200         switch (type) {
201         case 'a':
202                 return do_add(cmd_data, len_data);
203         case 'b':
204                 return do_set_lpad_info(cmd_data, len_data);
205         case 'l':
206                 return do_set_appcore_info(cmd_data, len_data);
207         case 'r':
208                 return do_rm(cmd_data, len_data);
209         default:
210                 return -EINVAL;
211         }
212
213         return 0;
214 }
215
216
217
218
219 /* ============================================================================
220  * ===                          DEBUGFS FOR CMD                             ===
221  * ============================================================================
222  */
223 static ssize_t write_cmd(struct file *file, const char __user *user_buf,
224                          size_t count, loff_t *ppos)
225 {
226         char *buf;
227         ssize_t ret = count;
228
229         buf = kmalloc(count + 1, GFP_KERNEL);
230         if (buf == NULL)
231                 return -ENOMEM;
232
233         if (copy_from_user(buf, user_buf, count)) {
234                 ret = -EFAULT;
235                 goto free_buf;
236         }
237
238         buf[count] = '\0';
239         rm_endline_symbols(buf, count);
240
241         if (do_cmd(buf, count))
242                 ret = -EINVAL;
243
244 free_buf:
245         kfree(buf);
246
247         return ret;
248 }
249
250 static ssize_t read_cmd(struct file *file, char __user *user_buf,
251                         size_t count, loff_t *ppos)
252 {
253         const char help[] =
254                         "use:\n"
255                         "\ta $app_path - add\n"
256                         "\tr $app_path - remove\n"
257                         "\tc - remove all\n"
258                         "\tb dlopen_addr@plt:dlsym_addr@plt:launchpad_path\n"
259                         "\tl appcore_efl_main:__do_app:appcore_init@plt:elm_run@plt:libappcore-efl_path\n";
260         ssize_t ret;
261
262         ret = simple_read_from_buffer(user_buf, count, ppos,
263                                       help, sizeof(help));
264
265         return ret;
266 }
267
268 static const struct file_operations fops_cmd = {
269         .read =         read_cmd,
270         .write =        write_cmd,
271         .llseek =       default_llseek
272 };
273
274
275
276
277 /* ============================================================================
278  * ===                         DEBUGFS FOR ENABLE                           ===
279  * ============================================================================
280  */
281 static ssize_t read_enabled(struct file *file, char /*__user*/ *user_buf,
282                             size_t count, loff_t *ppos)
283 {
284         char buf[2];
285
286         buf[0] = nsp_get_stat() == NS_OFF ? '0' : '1';
287         buf[1] = '\n';
288
289         return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
290 }
291
292 static ssize_t write_enabled(struct file *file, const char /*__user*/ *user_buf,
293                              size_t count, loff_t *ppos)
294 {
295         int ret = 0;
296         char buf[32];
297         size_t buf_size;
298
299         buf_size = min(count, (sizeof(buf) - 1));
300         if (copy_from_user(buf, user_buf, buf_size))
301                 return -EFAULT;
302
303         buf[buf_size] = '\0';
304         switch (buf[0]) {
305         case '1':
306                 ret = nsp_set_stat(NS_ON);
307                 break;
308         case '0':
309                 ret = nsp_set_stat(NS_OFF);
310                 break;
311         default:
312                 return -EINVAL;
313         }
314
315         if (ret)
316                 return ret;
317
318         return count;
319 }
320
321 static const struct file_operations fops_enabled = {
322         .read =         read_enabled,
323         .write =        write_enabled,
324         .llseek =       default_llseek,
325 };
326
327
328
329
330 static struct dentry *nsp_dir = NULL;
331
332 void nsp_debugfs_exit(void)
333 {
334         if (nsp_dir)
335                 debugfs_remove_recursive(nsp_dir);
336
337         nsp_dir = NULL;
338 }
339
340 int nsp_debugfs_init(void)
341 {
342         struct dentry *dentry;
343
344         dentry = swap_debugfs_getdir();
345         if (dentry == NULL)
346                 return -ENOENT;
347
348         nsp_dir = debugfs_create_dir("nsp", dentry);
349         if (nsp_dir == NULL)
350                 return -ENOMEM;
351
352         dentry = debugfs_create_file("cmd", 0600, nsp_dir, NULL,
353                                      &fops_cmd);
354         if (dentry == NULL)
355                 goto fail;
356
357         dentry = debugfs_create_file("enabled", 0600, nsp_dir, NULL,
358                                      &fops_enabled);
359         if (dentry == NULL)
360                 goto fail;
361
362         return 0;
363
364 fail:
365         nsp_debugfs_exit();
366         return -ENOMEM;
367 }