1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <linux/module.h>
20 #include <linux/kernel.h>
21 #include <linux/printk.h>
22 #include <linux/fs.h>
23 #include <linux/seq_file.h>
24 #include <linux/proc_fs.h>
25 #include <linux/slab.h>
26 #include <asm/uaccess.h>
27 #include <linux/version.h>
28 #include "securec.h"
29 #include "hi_osal.h"
30
31 #define OSAL_PROC_DEBUG 0
32
33 static struct osal_list_head g_list;
34 static osal_proc_entry_t *g_proc_entry = NULL;
35
osal_seq_show(struct seq_file * s,void * p)36 static int osal_seq_show(struct seq_file *s, void *p)
37 {
38 osal_proc_entry_t *oldsentry = s->private;
39 osal_proc_entry_t sentry;
40
41 osal_unused(p);
42 if (oldsentry == NULL) {
43 osal_trace("%s - parameter invalid!\n", __FUNCTION__);
44 return -1;
45 }
46 (void)memset_s(&sentry, sizeof(osal_proc_entry_t), 0, sizeof(osal_proc_entry_t));
47 /* only these two parameters are used */
48 sentry.seqfile = s;
49 sentry.private = oldsentry->private;
50 oldsentry->read(&sentry);
51 return 0;
52 }
53
54 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
osal_procwrite(struct file * file,const char __user * buf,size_t count,loff_t * ppos)55 static ssize_t osal_procwrite(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
56 {
57 osal_proc_entry_t *sentry = ((struct seq_file *)(file->private_data))->private;
58 return sentry->write(sentry, (char *)buf, count, (long long *)ppos);
59 }
60 #else
osal_procwrite(struct file * file,const char __user * buf,size_t count,loff_t * ppos)61 static ssize_t osal_procwrite(struct file *file, const char __user *buf,
62 size_t count, loff_t *ppos)
63 {
64 osal_proc_entry_t *item = PDE_DATA(file_inode(file));
65
66 if ((item != NULL) && (item->write != NULL)) {
67 return item->write(item, buf, count, (long long *)ppos);
68 }
69
70 return -ENOSYS;
71 }
72 #endif
73
osal_procopen(struct inode * inode,struct file * file)74 static int osal_procopen(struct inode *inode, struct file *file)
75 {
76 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
77 osal_proc_entry_t *sentry = PDE(inode)->data;
78 #else
79 osal_proc_entry_t *sentry = PDE_DATA(inode);
80 #endif
81 if ((sentry != NULL) && (sentry->open != NULL)) {
82 sentry->open(sentry);
83 }
84 return single_open(file, osal_seq_show, sentry);
85 }
86
87 #if LINUX_VERSION_CODE > KERNEL_VERSION(5,6,0)
88 static struct proc_ops g_osal_proc_ops = {
89 .proc_open = osal_procopen,
90 .proc_read = seq_read,
91 .proc_write = osal_procwrite,
92 .proc_lseek = seq_lseek,
93 .proc_release = single_release
94 };
95 #else
96 static struct file_operations g_osal_proc_ops = {
97 .owner = THIS_MODULE,
98 .open = osal_procopen,
99 .read = seq_read,
100 .write = osal_procwrite,
101 .llseek = seq_lseek,
102 .release = single_release
103 };
104 #endif
105
osal_create_proc(const char * name,osal_proc_entry_t * parent)106 osal_proc_entry_t *osal_create_proc(const char *name, osal_proc_entry_t *parent)
107 {
108 struct proc_dir_entry *entry = NULL;
109 osal_proc_entry_t *sentry = NULL;
110 void *parent_proc_entry = NULL;
111
112 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
113 if (parent == NULL) {
114 osal_trace("%s - parent is NULL!\n", __FUNCTION__);
115 } else {
116 parent_proc_entry = parent->proc_dir_entry;
117 osal_trace("%s - parent is not NULL! parent=%pK\n", __FUNCTION__, parent->proc_dir_entry);
118 }
119 entry = create_proc_entry(name, 0, parent_proc_entry);
120 if (entry == NULL) {
121 osal_trace("%s - create_proc_entry failed!\n", __FUNCTION__);
122 return NULL;
123 }
124 sentry = kmalloc(sizeof(struct osal_proc_dir_entry), GFP_KERNEL);
125 if (sentry == NULL) {
126 remove_proc_entry(name, parent_proc_entry);
127 osal_trace("%s - kmalloc failed!\n", __FUNCTION__);
128 return NULL;
129 }
130
131 (void)memset_s(sentry, sizeof(struct osal_proc_dir_entry), 0, sizeof(struct osal_proc_dir_entry));
132
133 if (strncpy_s(sentry->name, OSAL_MAX_PROC_NAME_LEN, name, sizeof(sentry->name) - 1) != EOK) {
134 kfree(sentry);
135 remove_proc_entry(name, parent_proc_entry);
136 osal_trace("%s - strncpy_s failed!\n", __FUNCTION__);
137 return NULL;
138 }
139 sentry->proc_dir_entry = entry;
140 sentry->open = NULL;
141 entry->proc_fops = &g_osal_proc_ops;
142 entry->data = sentry;
143 #else
144 sentry = kmalloc(sizeof(struct osal_proc_dir_entry), GFP_KERNEL);
145 if (sentry == NULL) {
146 osal_trace("%s - kmalloc failed!\n", __FUNCTION__);
147 return NULL;
148 }
149
150 (void)memset_s(sentry, sizeof(struct osal_proc_dir_entry), 0, sizeof(struct osal_proc_dir_entry));
151
152 if (strncpy_s(sentry->name, OSAL_MAX_PROC_NAME_LEN, name, sizeof(sentry->name) - 1) != EOK) {
153 osal_trace("%s - strncpy_s failed!\n", __FUNCTION__);
154 kfree(sentry);
155 return NULL;
156 }
157 if (parent != NULL) {
158 parent_proc_entry = parent->proc_dir_entry;
159 }
160 entry = proc_create_data(name, 0, parent_proc_entry, &g_osal_proc_ops, sentry);
161 if (entry == NULL) {
162 osal_trace("%s - create_proc_entry failed!\n", __FUNCTION__);
163 kfree(sentry);
164 return NULL;
165 }
166 sentry->proc_dir_entry = entry;
167 sentry->open = NULL;
168 #endif
169 osal_list_add_tail(&(sentry->node), &g_list);
170 return sentry;
171 }
172
osal_remove_proc(const char * name,osal_proc_entry_t * parent)173 void osal_remove_proc(const char *name, osal_proc_entry_t *parent)
174 {
175 struct osal_proc_dir_entry *sproc = NULL;
176
177 if (name == NULL) {
178 osal_trace("%s - parameter invalid!\n", __FUNCTION__);
179 return;
180 }
181 if (parent != NULL) {
182 remove_proc_entry(name, parent->proc_dir_entry);
183 } else {
184 remove_proc_entry(name, NULL);
185 }
186 osal_list_for_each_entry(sproc, &g_list, node) {
187 if (osal_strncmp(sproc->name, name, sizeof(sproc->name)) == 0) {
188 osal_list_del(&(sproc->node));
189 kfree(sproc);
190 sproc = NULL;
191 break;
192 }
193 }
194 }
195
osal_create_proc_entry(const char * name,osal_proc_entry_t * parent)196 osal_proc_entry_t *osal_create_proc_entry(const char *name, osal_proc_entry_t *parent)
197 {
198 parent = g_proc_entry;
199
200 return osal_create_proc(name, parent);
201 }
202 EXPORT_SYMBOL(osal_create_proc_entry);
203
osal_remove_proc_entry(const char * name,osal_proc_entry_t * parent)204 void osal_remove_proc_entry(const char *name, osal_proc_entry_t *parent)
205 {
206 parent = g_proc_entry;
207 osal_remove_proc(name, parent);
208 return;
209 }
210 EXPORT_SYMBOL(osal_remove_proc_entry);
211
osal_proc_mkdir(const char * name,osal_proc_entry_t * parent)212 osal_proc_entry_t *osal_proc_mkdir(const char *name, osal_proc_entry_t *parent)
213 {
214 struct proc_dir_entry *proc = NULL;
215 struct osal_proc_dir_entry *sproc = NULL;
216 void *parent_proc_entry = NULL;
217
218 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
219 if (parent != NULL) {
220 parent_proc_entry = parent->proc_dir_entry;
221 proc = proc_mkdir(name, parent_proc_entry);
222 osal_trace("%s - parent is not NULL!\n", __FUNCTION__);
223 } else {
224 proc = proc_mkdir(name, parent_proc_entry);
225 osal_trace("%s - parent is NULL! proc=%pK \n", __FUNCTION__, proc);
226 }
227 if (proc == NULL) {
228 osal_trace("%s - proc_mkdir failed!\n", __FUNCTION__);
229 return NULL;
230 }
231 sproc = kmalloc(sizeof(struct osal_proc_dir_entry), GFP_KERNEL);
232 if (sproc == NULL) {
233 remove_proc_entry(name, parent_proc_entry);
234 osal_trace("%s - kmalloc failed!\n", __FUNCTION__);
235 return NULL;
236 }
237
238 (void)memset_s(sproc, sizeof(struct osal_proc_dir_entry), 0, sizeof(struct osal_proc_dir_entry));
239
240 if (strncpy_s(sproc->name, OSAL_MAX_PROC_NAME_LEN, name, sizeof(sproc->name) - 1) != EOK) {
241 remove_proc_entry(name, parent_proc_entry);
242 kfree(sproc);
243 osal_trace("%s - strncpy_s failed!\n", __FUNCTION__);
244 return NULL;
245 }
246 sproc->proc_dir_entry = proc;
247 proc->data = sproc;
248 #else
249 sproc = kmalloc(sizeof(struct osal_proc_dir_entry), GFP_KERNEL);
250 if (sproc == NULL) {
251 osal_trace("%s - kmalloc failed!\n", __FUNCTION__);
252 return NULL;
253 }
254
255 (void)memset_s(sproc, sizeof(struct osal_proc_dir_entry), 0, sizeof(struct osal_proc_dir_entry));
256
257 if (strncpy_s(sproc->name, OSAL_MAX_PROC_NAME_LEN, name, sizeof(sproc->name) - 1) != EOK) {
258 kfree(sproc);
259 osal_trace("%s - strncpy_s failed!\n", __FUNCTION__);
260 return NULL;
261 }
262 if (parent != NULL) {
263 parent_proc_entry = parent->proc_dir_entry;
264 }
265 proc = proc_mkdir_data(name, 0, parent_proc_entry, sproc);
266 if (proc == NULL) {
267 kfree(sproc);
268 osal_trace("%s - proc_mkdir failed!\n", __FUNCTION__);
269 return NULL;
270 }
271 sproc->proc_dir_entry = proc;
272 #endif
273 osal_list_add_tail(&(sproc->node), &g_list);
274 return sproc;
275 }
276 EXPORT_SYMBOL(osal_proc_mkdir);
277
osal_remove_proc_root(const char * name,osal_proc_entry_t * parent)278 void osal_remove_proc_root(const char *name, osal_proc_entry_t *parent)
279 {
280 struct osal_proc_dir_entry *sproc = NULL;
281
282 if (name == NULL) {
283 osal_trace("%s - parameter invalid!\n", __FUNCTION__);
284 return;
285 }
286 if (parent != NULL) {
287 remove_proc_entry(name, parent->proc_dir_entry);
288 } else {
289 remove_proc_entry(name, NULL);
290 }
291 osal_list_for_each_entry(sproc, &g_list, node) {
292 if (osal_strncmp(sproc->name, name, sizeof(sproc->name)) == 0) {
293 osal_list_del(&(sproc->node));
294 break;
295 }
296 }
297 if (sproc != NULL) {
298 kfree(sproc);
299 }
300 }
301
osal_seq_printf(osal_proc_entry_t * entry,const char * fmt,...)302 void osal_seq_printf(osal_proc_entry_t *entry, const char *fmt, ...)
303 {
304 struct seq_file *s = (struct seq_file *)(entry->seqfile);
305 va_list args;
306
307 va_start(args, fmt);
308 #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 3, 0)
309 (void)seq_vprintf(s, fmt, args);
310 #else
311 seq_vprintf(s, fmt, args);
312 #endif
313 va_end(args);
314 }
315 EXPORT_SYMBOL(osal_seq_printf);
316
osal_proc_init(void)317 void osal_proc_init(void)
318 {
319 OSAL_INIT_LIST_HEAD(&g_list);
320 g_proc_entry = osal_proc_mkdir("umap", NULL);
321 if (g_proc_entry == NULL) {
322 osal_trace("test init, proc mkdir error!\n");
323 }
324 }
osal_proc_exit(void)325 void osal_proc_exit(void)
326 {
327 osal_remove_proc_root("umap", NULL);
328 }
329