• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef __HuaweiLite__
20 #include <pthread.h>
21 #include <shell.h>
22 #include <sys/prctl.h>
23 #include "linux/kernel.h"
24 #endif
25 
26 #include "hi_osal.h"
27 #include "securec.h"
28 
29 #include "hi_type.h"
30 #include "hi_debug.h"
31 #include "proc_ext.h"
32 #include "dev_ext.h"
33 #include "mod_ext.h"
34 #include "mkp_log.h"
35 
36 static hi_s32 g_log_level[HI_ID_BUTT + 1] = {
37     [0 ... HI_ID_BUTT - 1] = HI_DBG_ERR
38 };
39 #define LOG_STATE_INIT  0
40 #define LOG_STATE_OPEN  1
41 #define LOG_STATE_READ  2
42 #define LOG_STATE_WRITE 3
43 #define LOG_STATE_CLOSE 4
44 
45 static hi_u32 g_state = LOG_STATE_INIT;
46 static hi_bool g_wait_data = HI_TRUE;
47 
48 #define LOG_BUFFER_LEN  64 /* unit is KB. the ring buffer's default length is 64KB */
49 #define LOG_MAX_ITEMLEN 512 /* unit is byte. suppose one log is short than 512 byte */
50 
51 typedef struct {
52     hi_u32 max_len; /* the max length of ring buffer    */
53     hi_char *addr; /* the address of ring buffer       */
54     hi_u32 read_pos; /* the read pointer of ring buffer  */
55     hi_u32 write_pos; /* the write pointer of ring buffer */
56     hi_u32 butt_pos; /* leave a blank for circle round   */
57     osal_spinlock_t lock; /* the lock                         */
58     osal_wait_t block_wait; /* wait for read                    */
59 } log_buffer;
60 
61 /* All the mode use the same one buffer. so the time order can be record. */
62 static log_buffer g_log_buf = {0};
63 
search_mod(const char * s)64 static int search_mod(const char *s)
65 {
66     int i;
67     for (i = 0; i < HI_ID_BUTT; i++) {
68         hi_char *pa_name = cmpi_get_module_name(i);
69         if (pa_name && !osal_strcmp(pa_name, s)) {
70             return i;
71         }
72     }
73     return -1;
74 }
75 
76 /* ate all blanks in a line */
strip_string(char * s,char * d,int len)77 static char *strip_string(char *s, char *d, int len)
78 {
79     int i = 0;
80     char *p = d;
81     do {
82         if (*s == '\n') {
83             *s = '\0';
84         }
85         if (*s != ' ') {
86             *p++ = *s;
87         }
88         i++;
89     } while ((*s++ != '\0') && (i < len));
90     return d;
91 }
92 
separate_string(char * s,char ** left,char ** right)93 static int separate_string(char *s, char **left, char **right)
94 {
95     char *p = s;
96     /* find '=' */
97     while (*p != '\0' && *p++ != '=') {
98     };
99 
100     if (*--p != '=') {
101         return -1;
102     }
103 
104     /* separate left from right value by '=' */
105     *p = '\0';
106     *left = s;
107     *right = p + 1;
108     return 0;
109 }
110 
hi_chk_log_level(hi_s32 level,hi_mod_id mod_id)111 hi_s32 hi_chk_log_level(hi_s32 level, hi_mod_id mod_id)
112 {
113     if ((mod_id >= HI_ID_BUTT) ||
114         (level > g_log_level[mod_id])) {
115             return 0;
116         }
117     return 1;
118 }
119 
log_get_time(hi_void)120 static inline hi_u64 log_get_time(hi_void)
121 {
122     osal_timeval_t time;
123     osal_gettimeofday(&time);
124     return time.tv_sec * 1000000LLU + time.tv_usec;
125 }
126 
log_write(hi_s32 level,hi_mod_id mod_id,const char * fmt,osal_va_list args)127 hi_s32 log_write(hi_s32 level, hi_mod_id mod_id, const char *fmt, osal_va_list args)
128 {
129     hi_s32 new_len;
130     hi_s32 tmp_len;
131     hi_u32 old_wp, old_rp, new_wp, new_rp;
132     hi_char *addr = NULL;
133     unsigned long lock_flag;
134     hi_char *mod_name = NULL;
135 
136     if (g_log_buf.addr == NULL) {
137         return 0;
138     }
139     HI_ASSERT(g_log_buf.write_pos <= g_log_buf.max_len);
140     HI_ASSERT(g_log_buf.read_pos <= g_log_buf.max_len);
141 
142     osal_spin_lock_irqsave(&(g_log_buf.lock), &lock_flag);
143 
144     old_wp = new_wp = g_log_buf.write_pos;
145     old_rp = new_rp = g_log_buf.read_pos;
146     mod_name = cmpi_get_module_name(mod_id);
147 
148     if (g_log_buf.max_len - old_wp > LOG_MAX_ITEMLEN) {
149         addr = g_log_buf.addr + old_wp;
150         new_len = snprintf_s(addr, LOG_MAX_ITEMLEN, LOG_MAX_ITEMLEN - 1, "<%d>[%6s] ", level, mod_name);
151         new_len = (new_len < 0) ? 0 : new_len;
152         tmp_len = vsnprintf_s(addr + new_len, LOG_MAX_ITEMLEN - new_len, LOG_MAX_ITEMLEN - new_len - 1, fmt, args);
153         tmp_len = (tmp_len < 0) ? 0 : tmp_len;
154         new_len = new_len + tmp_len;
155 
156         if (new_len >= LOG_MAX_ITEMLEN) {
157             osal_printk("[%6s]: log message is too long!!\n", mod_name);
158         } else {
159             new_wp = old_wp + new_len;
160             if ((new_wp >= old_rp) && (old_wp < old_rp)) {
161                 new_rp = new_wp + 1;
162             }
163         }
164     } else {
165         g_log_buf.butt_pos = old_wp;
166         addr = g_log_buf.addr;
167         new_len = snprintf_s(addr, LOG_MAX_ITEMLEN, LOG_MAX_ITEMLEN - 1, "<%d>[%6s] ", level, mod_name);
168         new_len = (new_len < 0) ? 0 : new_len;
169         tmp_len = vsnprintf_s(addr + new_len, LOG_MAX_ITEMLEN - new_len, LOG_MAX_ITEMLEN - new_len - 1, fmt, args);
170         tmp_len = (tmp_len < 0) ? 0 : tmp_len;
171         new_len = new_len + tmp_len;
172 
173         if (new_len >= LOG_MAX_ITEMLEN) {
174             osal_printk("[%6s]: log message is too long!!\n", mod_name);
175         } else {
176             new_wp = new_len;
177             if (!(((hi_u32)new_len < old_rp) && (old_wp >= old_rp))) {
178                 new_rp = new_len + 1;
179             }
180         }
181     }
182 
183     g_log_buf.write_pos = new_wp;
184     g_log_buf.read_pos = new_rp;
185 
186     osal_spin_unlock_irqrestore(&(g_log_buf.lock), &lock_flag);
187 
188     osal_wakeup(&(g_log_buf.block_wait));
189 
190     return new_len;
191 }
192 
HI_LOG(hi_s32 level,hi_mod_id mod_id,const char * fmt,...)193 int HI_LOG(hi_s32 level, hi_mod_id mod_id, const char *fmt, ...)
194 {
195     osal_va_list args;
196     int r;
197     if (!hi_chk_log_level(level, mod_id)) {
198         return 0;
199     }
200 
201     osal_va_start(args, fmt);
202     r = log_write(level, mod_id, fmt, args);
203     osal_va_end(args);
204     return r;
205 }
206 
207 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
208 /* use the "cat /proc/umap/log"  to get the debug level */
log_proc_read(struct osal_proc_dir_entry * s)209 static hi_s32 log_proc_read(struct osal_proc_dir_entry *s)
210 {
211     hi_u32 i;
212 
213     osal_seq_printf(s, "-----LOG BUFFER STATE----------------------------------------------------------\n");
214     osal_seq_printf(s, "MaxLen  ReadPos WritePos ButtPos\n");
215     osal_seq_printf(s, "%3d(KB) %7d %8d %7d\n",
216                     g_log_buf.max_len >> 10, g_log_buf.read_pos, /* 10,width */
217                     g_log_buf.write_pos, g_log_buf.butt_pos);
218     osal_seq_printf(s, "\n");
219 
220     osal_seq_printf(s, "-----CURRENT LOG LEVEL---------------------------------------------------------\n");
221     for (i = 0; i < HI_ID_BUTT; i++) {
222         hi_char *pa_temp_name = cmpi_get_module_name(i);
223         if (pa_temp_name == NULL) {
224             continue;
225         }
226         osal_seq_printf(s, "%s\t:  %d\n",
227                         pa_temp_name, g_log_level[i]);
228     }
229 
230     return 0;
231 }
232 
233 /* use the "echo 'mode = level' > /proc/umap/log"  to modify the debug level */
log_proc_write(struct osal_proc_dir_entry * s,const char * buf,int count,long long * ppos)234 static hi_s32 log_proc_write(struct osal_proc_dir_entry *s, const char *buf,
235     int count, long long *ppos)
236 {
237 #define TMP_BUF_LEN     32
238     char m[TMP_BUF_LEN] = {0};
239     char d[TMP_BUF_LEN] = { [0 ... TMP_BUF_LEN - 1] = '\0' };
240     int len = TMP_BUF_LEN;
241     char *left = NULL;
242     char *right = NULL;
243     int idx;
244     int level;
245 
246     hi_unused(s);
247     if (*ppos >= TMP_BUF_LEN) {
248         return HI_FAILURE;
249     }
250 
251     if (count <= 0) {
252         return HI_FAILURE;
253     }
254 
255     len = osal_min(len, count);
256     if (osal_copy_from_user(m, buf, len) != 0) {
257         return HI_FAILURE;
258     }
259 
260     m[len - 1] = '\0';
261     strip_string(m, d, len);
262     if (separate_string(d, &left, &right)) {
263         osal_printk("string is unknown!\n");
264         goto out;
265     }
266 
267     level = osal_strtol(right, NULL, 10);  /* 10,base */
268     if (!osal_strcmp("wait", left)) {
269         g_wait_data = level;
270         goto out;
271     }
272 
273     if (!level && *right != '0') {
274         osal_printk("invalid value!\n");
275         goto out;
276     }
277 
278     if (level > HI_DBG_DEBUG) {
279         osal_printk("level: %d illegal!\n", level);
280     }
281 
282     if (!osal_strcmp("all", left)) {
283         int i = 0;
284         for (; i < HI_ID_BUTT; i++) {
285             g_log_level[i] = level;
286         }
287         goto out;
288     }
289     idx = search_mod(left);
290     if ((idx < 0) || (idx >= HI_ID_BUTT)) {
291         osal_printk("%s not found in array!\n", left);
292         return count;
293     }
294     g_log_level[idx] = level;
295 
296 out:
297     return len;
298 #undef TMP_BUF_LEN
299 }
300 #endif
301 
302 static hi_s32 log_close(void *private_data);
303 /* IOCTL operation for get and config the debug level */
do_ioctl(unsigned int cmd,unsigned long arg,void * private_data)304 static hi_s32 do_ioctl(unsigned int cmd, unsigned long arg, void *private_data)
305 {
306     hi_unused(private_data);
307     switch (cmd) {
308         case LOG_SETLOGLEVEL_CTRL: {
309             hi_log_level_conf *conf = (hi_log_level_conf *)(hi_uintptr_t)arg;
310 
311             if (conf->level > HI_DBG_DEBUG) {
312                 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "illegal level: %d\n", conf->level);
313                 return HI_FAILURE;
314             }
315 
316             conf->mod_name[sizeof(conf->mod_name) - 1] = '\0';
317 
318             if (!osal_strcmp("all", conf->mod_name)) {
319                 int i = 0;
320                 for (; i < HI_ID_BUTT; i++) {
321                     g_log_level[i] = conf->level;
322                 }
323             } else {
324                 if (conf->mod_id >= HI_ID_BUTT) {
325                     HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "%s, line: %d, illegal parma, modeid: %d\n",
326                         __FUNCTION__, __LINE__, conf->mod_id);
327                     return HI_FAILURE;
328                 }
329 
330                 g_log_level[conf->mod_id] = conf->level;
331             }
332             break;
333         }
334         case LOG_GETLOGLEVEL_CTRL: {
335             errno_t err_value;
336             hi_log_level_conf *conf = (hi_log_level_conf *)(hi_uintptr_t)arg;
337 
338             if (conf->mod_id >= HI_ID_BUTT) {
339                 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "%s, line: %d, illegal parma, modeid: %d\n",
340                     __FUNCTION__, __LINE__, conf->mod_id);
341                 return HI_FAILURE;
342             }
343 
344             conf->level = g_log_level[conf->mod_id];
345 
346             if (cmpi_get_module_name(conf->mod_id) == NULL) {
347                 return HI_FAILURE;
348             }
349 
350             err_value = strncpy_s(conf->mod_name, sizeof(conf->mod_name),  cmpi_get_module_name(conf->mod_id),
351                 sizeof(conf->mod_name) - 1);
352             if (err_value != EOK) {
353                 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "copy err!\n");
354                 return HI_FAILURE;
355             }
356 
357             break;
358         }
359         case LOG_CLOSE_CTRL: {
360             log_close(HI_NULL);
361             break;
362         }
363         case LOG_SETWAITFLAG_CTRL: {
364             hi_bool wait;
365 
366             wait = *((hi_bool *)(hi_uintptr_t)arg);
367 
368             if ((wait != HI_FALSE) && (wait != HI_TRUE)) {
369                 HI_TRACE(HI_DBG_ERR, HI_ID_CMPI, "%s, line: %d, illegal parma, wait: %d\n",
370                     __FUNCTION__, __LINE__, wait);
371                 return HI_FAILURE;
372             }
373 
374             g_wait_data = wait;
375             break;
376         }
377         default:
378         {
379             break;
380         }
381     }
382 
383     return HI_SUCCESS;
384 }
385 
log_ioctl(unsigned int cmd,unsigned long arg,void * private_data)386 static long log_ioctl(unsigned int cmd, unsigned long arg, void *private_data)
387 {
388     return do_ioctl(cmd, arg, private_data);
389 }
390 
391 #ifdef __HuaweiLite__
read_q(hi_void * data)392 hi_void *read_q(hi_void *data)
393 {
394     int c;
395 
396     hi_unused(data);
397     prctl(PR_SET_NAME, "hi_log_read_q", 0, 0, 0);
398     while (1) {
399         c = getchar();
400         if ((c == 'q') || (c == 'Q')) {
401             log_close(HI_NULL);
402             return 0;
403         }
404     }
405 }
406 #endif
407 
wait_condition_call_back(const void * param)408 int wait_condition_call_back(const void *param)
409 {
410     hi_unused(param);
411     return ((g_log_buf.read_pos != g_log_buf.write_pos) ||
412             (g_state == LOG_STATE_CLOSE) ||
413             (g_wait_data == HI_FALSE));
414 }
415 
416 /* read operation for log information */
log_read(char * buf,int count,long * offset,void * private_data)417 static int log_read(char *buf, int count, long *offset, void *private_data)
418 {
419     hi_s32 read_len = 0;
420     hi_s32 error;
421     hi_char c;
422     unsigned long lock_flag;
423 
424     hi_unused(private_data);
425     hi_unused(offset);
426 #ifdef __HuaweiLite__
427 
428     hi_unused(buf);
429     count = LOG_BUFFER_LEN * 1024;   /* 1024, 1 k bit */
430     pthread_t threadid;
431     pthread_attr_t attr;
432     pthread_attr_init(&attr);
433     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
434     if (pthread_create(&threadid, &attr, read_q, NULL) != 0) {
435         HI_PRINT("cmpi_log read pthread_create error!\n");
436         return -1;
437     }
438 #endif
439 
440     g_state = LOG_STATE_READ;
441 
442     error = osal_wait_event_interruptible(&g_log_buf.block_wait, wait_condition_call_back, NULL);
443     if (error) {
444         return error;
445     }
446 
447     osal_spin_lock_irqsave(&(g_log_buf.lock), &lock_flag);
448     while ((!error) && (read_len < count) &&
449            (g_log_buf.write_pos != g_log_buf.read_pos)) {
450             if (g_log_buf.read_pos > g_log_buf.butt_pos) {
451                 g_log_buf.read_pos = 0;
452             }
453 
454             if (g_log_buf.write_pos == g_log_buf.read_pos) {
455                 break;
456             }
457 
458             c = *(g_log_buf.addr + g_log_buf.read_pos);
459             g_log_buf.read_pos += 1;
460 
461             osal_spin_unlock_irqrestore(&(g_log_buf.lock), &lock_flag);
462 
463 #ifdef __HuaweiLite__
464             printk("%c", c);
465 #else
466             error = osal_copy_to_user(buf, &c, 1);
467             buf++;
468 #endif
469 
470             read_len++;
471             osal_yield();
472             osal_spin_lock_irqsave(&(g_log_buf.lock), &lock_flag);
473         }
474     osal_spin_unlock_irqrestore(&(g_log_buf.lock), &lock_flag);
475 
476     return read_len;
477 }
478 
479 #ifdef __HuaweiLite__
480 /*
481     This function uses Camel_Style ,not Linux_Style.
482     Because it is exported to the sample/app_init.c
483 */
CatLogShell(void)484 void CatLogShell(void)
485 {
486     osCmdReg(CMD_TYPE_EX, "cat_logmpp", 0, (CMD_CBK_FUNC)log_read);
487 }
488 #endif
489 
log_open(void * data)490 static hi_s32 log_open(void *data)
491 {
492     hi_unused(data);
493     g_state = LOG_STATE_OPEN;
494     return HI_SUCCESS;
495 }
496 
log_close(void * data)497 static hi_s32 log_close(void *data)
498 {
499     hi_unused(data);
500     g_state = LOG_STATE_CLOSE;
501     g_wait_data = HI_TRUE;
502     osal_wakeup(&(g_log_buf.block_wait));
503     return HI_SUCCESS;
504 }
505 
506 static struct osal_fileops g_log_file_op = {
507     .open = log_open,
508     .unlocked_ioctl = log_ioctl,
509     .release = log_close,
510     .read = log_read
511 };
512 
513 static osal_dev_t *s_log_device;
514 
cmpi_log_init(hi_u32 log_buf_len)515 hi_s32 cmpi_log_init(hi_u32 log_buf_len)
516 {
517 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
518     osal_proc_entry_t *item = NULL;
519 #endif
520     s_log_device = osal_createdev(UMAP_DEVNAME_LOG_BASE);
521     if (s_log_device == NULL) {
522         osal_printk("log createdev failed!\n");
523         goto OUT0;
524     }
525     s_log_device->fops = &g_log_file_op;
526     s_log_device->minor = UMAP_LOG_MINOR_BASE;
527 
528     if (osal_registerdevice(s_log_device)) {
529         osal_printk("log register device failed!\n");
530         goto OUT1;
531     }
532 
533 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
534     item = osal_create_proc_entry(PROC_ENTRY_LOG, NULL);
535     if (item == NULL) {
536         goto OUT2;
537     }
538     item->read = log_proc_read;
539     item->write = log_proc_write;
540 #endif
541     if (osal_spin_lock_init(&(g_log_buf.lock)) < 0) {
542         osal_printk("spinlock init failed!\n");
543         goto OUT3;
544     }
545 
546     if (osal_wait_init(&(g_log_buf.block_wait)) < 0) {
547         osal_printk("wait init failed!\n");
548         goto OUT4;
549     }
550 
551     if ((log_buf_len >= 2) && (log_buf_len <= 128)) { /* 2,min len. 128 max len */
552         g_log_buf.max_len = log_buf_len * 1024; /* 1024,1kB is 1024 byte */
553     } else {
554         g_log_buf.max_len = LOG_BUFFER_LEN * 1024; /* 1024,1kB is 1024 byte */
555     }
556     g_log_buf.butt_pos = g_log_buf.max_len;
557     g_log_buf.read_pos = g_log_buf.write_pos = 0;
558     g_log_buf.addr = (hi_char *)osal_vmalloc(g_log_buf.max_len);
559     if (g_log_buf.addr == NULL) {
560         osal_printk("log buffer %d_b malloc failed.\n", g_log_buf.max_len);
561         goto OUT5;
562     }
563 
564     return HI_SUCCESS;
565 
566 OUT5:
567     osal_wait_destroy(&(g_log_buf.block_wait));
568 OUT4:
569     osal_spin_lock_destroy(&(g_log_buf.lock));
570 OUT3:
571     osal_remove_proc_entry(PROC_ENTRY_LOG, NULL);
572 OUT2:
573     osal_deregisterdevice(s_log_device);
574 OUT1:
575     osal_destroydev(s_log_device);
576     s_log_device = HI_NULL;
577 OUT0:
578     return HI_FAILURE;
579 }
580 
cmpi_log_exit(hi_void)581 hi_void cmpi_log_exit(hi_void)
582 {
583     if (g_log_buf.addr != NULL) {
584         osal_vfree(g_log_buf.addr);
585         g_log_buf.addr = NULL;
586     }
587     osal_deregisterdevice(s_log_device);
588     osal_destroydev(s_log_device);
589 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
590     osal_remove_proc_entry(PROC_ENTRY_LOG, NULL);
591 #endif
592 
593     osal_spin_lock_destroy(&(g_log_buf.lock));
594     osal_wait_destroy(&(g_log_buf.block_wait));
595 }
596