1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #include <stdarg.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 
10 #include "debug_api.h"
11 
12 #define MIN(x,y) (((x)<(y))?(x):(y))
13 
14 #if DEBUG_LAST_WORD_ENABLE
15 #ifdef CONFIG_VFS_LSOPEN
16 static void debug_paniclog_to_file(void);
17 #endif
18 static int  panic_header_init(debug_panic_info_head_t *panic_header);
19 static int  panic_header_show(debug_panic_info_head_t *panic_header);
20 static int  panic_header_set(debug_panic_info_head_t *panic_header);
21 static int  panic_header_get(debug_panic_info_head_t *panic_header);
22 static int  panic_log_set(uint8_t *info, uint32_t len);
23 static int  panic_log_get(uint8_t *info_buffer, uint32_t len);
24 static void panic_log_clean(void);
25 
clear_silent_reboot_flag(void)26 __attribute__((weak))  int clear_silent_reboot_flag(void)
27 {
28     return 0;
29 }
30 
set_silent_reboot_flag(void)31 __attribute__((weak))  int set_silent_reboot_flag(void)
32 {
33     return 0;
34 }
35 
k_dcache_clean(uint32_t addr,uint32_t len)36 __attribute__((weak))  void k_dcache_clean(uint32_t addr, uint32_t len)
37 {
38     return;
39 }
40 
41 /* set ram attributes for some mcu*/
alios_debug_lastword_init_hook()42 __attribute__((weak)) void alios_debug_lastword_init_hook()
43 {
44     return;
45 }
46 
47 #define HEADER_START_ADDR (DEBUG_LASTWORD_RAM_ADDR)
48 #define LOG_START_ADDR    (DEBUG_LASTWORD_RAM_ADDR   + sizeof(debug_panic_info_head_t))
49 #define LOG_REGION_LEN    (DEBUG_LASTWORD_REGION_LEN - sizeof(debug_panic_info_head_t))
50 #define LOG_END_ADDR      (DEBUG_LASTWORD_RAM_ADDR   + DEBUG_LASTWORD_REGION_LEN)
51 #define CRC_CALC_LEN      (uint32_t)(&(((debug_panic_info_head_t *)0)->crc16))
52 
53 static debug_panic_info_head_t panic_header_buffer;
54 
55 #define POLY        0x1021
56 
crc16_calc(uint8_t * addr,uint32_t num,uint16_t crc)57 uint16_t crc16_calc(uint8_t *addr, uint32_t num, uint16_t crc)
58 {
59     int i;
60     for (; num > 0; num--) {
61         crc = crc ^ (*addr++ << 8);
62         for (i = 0; i < 8; i++) {
63             if (crc & 0x8000) {
64                 crc = (crc << 1) ^ POLY;
65             } else {
66                 crc <<= 1;
67             }
68         }
69         crc &= 0xFFFF;
70     }
71     return (crc);
72 }
73 
debug_lastword_init(void)74 void debug_lastword_init(void)
75 {
76     printf("init lastword\r\n");
77 
78 #ifdef CONFIG_VFS_LSOPEN
79     mkdir(DEBUG_LOG_DIR_NAME, 0777);
80 #endif
81 
82     panic_header_get(&panic_header_buffer);
83 
84     if (crc16_calc((uint8_t *)&panic_header_buffer, CRC_CALC_LEN, 0xffff) != panic_header_buffer.crc16) {
85         panic_header_init(&panic_header_buffer);
86         panic_header_set(&panic_header_buffer);
87         panic_log_clean();
88         printf("[Error] lastword: init crc fail!\r\n");
89         return;
90     }
91 
92     printf("lastword: CRC check is OK\r\n");
93 #ifdef CONFIG_VFS_LSOPEN
94     if (panic_header_buffer.log_magic == DEBUG_PANIC_LOG_MAGIC) {
95         char path[64];
96         int fd = -1;
97         printf("lastword: try to read lastword to file!\r\n");
98         /* open /data/smartbox_abort as a flag for panic */
99         memset(path, 0, sizeof(path));
100         snprintf(path, sizeof(path) - 1, "/data/smartbox_abort");
101         fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
102         if (fd < 0) {
103             printf("open panic flag file fail\r\n");
104         } else {
105             printf("open panic flag file fd %d\r\n", fd);
106             close(fd);
107         }
108         printf("store panic log to file\r\n");
109         debug_paniclog_to_file();
110     }
111 #endif
112     panic_log_clean();
113     panic_header_buffer.log_magic = 0;
114 
115     if (panic_header_buffer.header_magic != DEBUG_PANIC_HEADER_MAGIC) {
116         panic_header_init(&panic_header_buffer);
117     } else {
118         panic_header_buffer.reboot_sum_count++;
119     }
120 
121     panic_header_show(&panic_header_buffer);
122     panic_header_set(&panic_header_buffer);
123     clear_silent_reboot_flag();
124 
125     alios_debug_lastword_init_hook();
126 }
127 
debug_reboot_reason_update(unsigned int reason)128 void debug_reboot_reason_update(unsigned int reason)
129 {
130     int ret = -1;
131     static int reason_id_update_flag = 0;
132 
133     panic_header_get(&panic_header_buffer);
134 
135     if (reason_id_update_flag == 0) {
136         panic_header_buffer.reboot_reason_id++;
137         reason_id_update_flag = 1;
138     }
139 
140     panic_header_buffer.reboot_reason = reason;
141 
142     if ((DEBUG_REBOOT_REASON_PANIC == reason) || (DEBUG_REBOOT_REASON_FATAL_ERR == reason)) {
143         set_silent_reboot_flag();
144 
145         panic_header_buffer.runtime_before_painc[panic_header_buffer.runtime_record_id] = krhino_ticks_to_ms(
146                             krhino_sys_tick_get());
147         panic_header_buffer.runtime_record_id++;
148         if (panic_header_buffer.runtime_record_id >= RUNTIME_COUNT) {
149             panic_header_buffer.runtime_record_id = 0;
150         }
151         panic_header_buffer.panic_count++;
152     }
153 
154     ret = panic_header_set(&panic_header_buffer);
155     if (ret) {
156         print_str("reboot reason set err\n");
157     }
158 }
159 
debug_reboot_reason_get()160 unsigned int debug_reboot_reason_get()
161 {
162     panic_header_get(&panic_header_buffer);
163 
164     if (panic_header_buffer.header_magic != DEBUG_PANIC_HEADER_MAGIC) {
165         panic_header_init(&panic_header_buffer);
166         panic_header_set(&panic_header_buffer);
167         return DEFAULT_REBOOT_REASON;
168     }
169 
170     if (panic_header_buffer.reboot_sum_count > panic_header_buffer.reboot_reason_id) {
171         panic_header_buffer.reboot_reason_id = panic_header_buffer.reboot_sum_count;
172         panic_header_buffer.reboot_reason    = DEBUG_REBOOT_UNKNOWN_REASON;
173         panic_header_set(&panic_header_buffer);
174         return DEBUG_REBOOT_UNKNOWN_REASON;
175     }
176 
177     return panic_header_buffer.reboot_reason;
178 }
179 
debug_get_painc_runtime(int panic_count,int * real_panic_count)180 int64_t debug_get_painc_runtime(int panic_count, int *real_panic_count)
181 {
182     int32_t idx = 0, count = 0;
183     int64_t duration = 0;
184 
185     panic_header_get(&panic_header_buffer);
186 
187     if (panic_header_buffer.header_magic != DEBUG_PANIC_HEADER_MAGIC) {
188         panic_header_init(&panic_header_buffer);
189         panic_header_set(&panic_header_buffer);
190         *real_panic_count = 0;
191         return -1;
192     }
193 
194     if (panic_header_buffer.panic_count == 0) {
195         *real_panic_count = 0;
196         return -1;
197     }
198 
199     if (panic_count > RUNTIME_COUNT) {
200         printf("panic count is larger than %d\r\n", RUNTIME_COUNT);
201     }
202 
203     idx = panic_header_buffer.runtime_record_id;
204 
205     for (count = 0; count < RUNTIME_COUNT; count++) {
206         if (count >= panic_count) {
207             break;
208         }
209 
210         idx--;
211         if (idx < 0) {
212             idx = RUNTIME_COUNT - 1;
213         }
214         if (panic_header_buffer.runtime_before_painc[idx] != -1) {
215             duration += panic_header_buffer.runtime_before_painc[idx];
216         } else {
217             break;
218         }
219     }
220 
221     *real_panic_count = count;
222     return duration;
223 }
224 
225 #ifdef CONFIG_VFS_LSOPEN
debug_paniclog_to_file(void)226 static void debug_paniclog_to_file(void)
227 {
228     int  i  = 0, index = 0;
229     int  fd = -1, indexfile_fd = -1;
230     char path[64];
231     char info_buffer[128], index_buffer[10];
232     int  len;
233 
234     if (panic_header_buffer.log_magic != DEBUG_PANIC_LOG_MAGIC) {
235         return;
236     }
237 
238     for (i = 0; i < DEBUG_LOG_FILE_NUM; i++) {
239         memset(path, 0, sizeof(path));
240         snprintf(path, sizeof(path), "%s_%02d", DEBUG_LOG_FILE_NAME, i);
241         /* if file not exit, create it, and output debug info to it */
242         if (access(path, R_OK) != 0) {
243             fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
244             if (fd >= 0) {
245                 break;
246             }
247         }
248     }
249 
250     if (i == DEBUG_LOG_FILE_NUM) {
251         if (access(DEBUG_LOG_FILE_INDEX_NAME, R_OK) != 0) {
252             indexfile_fd  = open(DEBUG_LOG_FILE_INDEX_NAME, O_CREAT | O_WRONLY | O_TRUNC, 0666);
253             index = 0;
254         } else {
255             indexfile_fd  = open(DEBUG_LOG_FILE_INDEX_NAME, O_CREAT | O_RDWR, 0666);
256             read(indexfile_fd, index_buffer, sizeof(index_buffer));
257             sscanf(index_buffer, "%02d", &index);
258 
259             if ((index < 0) || (index >= DEBUG_LOG_FILE_NUM)) {
260                 index = 0;
261             } else {
262                 index++;
263                 if (index >= DEBUG_LOG_FILE_NUM) {
264                     index = 0;
265                 }
266             }
267             lseek(indexfile_fd, SEEK_SET, 0);
268         }
269 
270         if (indexfile_fd >= 0) {
271             memset(index_buffer, 0, sizeof(index_buffer));
272             len = snprintf(index_buffer, sizeof(index_buffer), "%02d", index);
273             write(indexfile_fd, index_buffer, len);
274             close(indexfile_fd);
275         }
276 
277         memset(path, 0, sizeof(path));
278         snprintf(path, sizeof(path), "%s_%02d", DEBUG_LOG_FILE_NAME, index);
279         fd = open(path, O_CREAT | O_WRONLY | O_TRUNC, 0666);
280     }
281 
282     if (fd < 0) {
283         printf("open file %s error, %s, %d\r\n", path, __FILE__, __LINE__);
284         return;
285     }
286 
287     while (1) {
288         len = sizeof(info_buffer);
289         len = panic_log_get((uint8_t *)info_buffer, len);
290         if (len <= 0) {
291             break;
292         }
293         len = write(fd, info_buffer, len);
294         if (len < 0) {
295             printf("write file %s error, %s, %d\r\n", path, __FILE__, __LINE__);
296             //break;
297         }
298     }
299 
300     close(fd);
301     fd = -1;
302 
303     return;
304 }
305 #endif
306 
panic_header_init(debug_panic_info_head_t * panic_header)307 static int panic_header_init(debug_panic_info_head_t *panic_header)
308 {
309     uint32_t i;
310     panic_header->header_magic      = DEBUG_PANIC_HEADER_MAGIC;
311     panic_header->log_magic         = 0;
312     panic_header->reboot_reason     = DEFAULT_REBOOT_REASON;
313     panic_header->reboot_sum_count  = 0;
314     panic_header->reboot_reason_id  = 0;
315     panic_header->panic_count       = 0;
316     panic_header->runtime_record_id = 0;
317 
318     for (i = 0; i < RUNTIME_COUNT; i++) {
319         panic_header->runtime_before_painc[i] = -1;
320     }
321     return 0;
322 }
323 
panic_header_show(debug_panic_info_head_t * panic_header)324 static int panic_header_show(debug_panic_info_head_t *panic_header)
325 {
326     printf("===========show panic header===========\r\n");
327     printf("panic header reboot reason %d\r\n", (int)panic_header->reboot_reason);
328     printf("panic header reboot sum count %d\r\n", (int)panic_header->reboot_sum_count);
329     printf("panic header reboot reason reason id %d\r\n", (int)panic_header->reboot_reason_id);
330     printf("panic header panic  count %d\r\n", (int)panic_header->panic_count);
331     printf("===========end===========\r\n");
332     return 0;
333 }
334 
panic_header_set(debug_panic_info_head_t * panic_header)335 static int panic_header_set(debug_panic_info_head_t *panic_header)
336 {
337     if (panic_header == NULL) {
338         return -1;
339     }
340 
341     debug_panic_info_head_t *log_header = (debug_panic_info_head_t *)HEADER_START_ADDR;
342     /* calculate the crc */
343     panic_header->crc16 = crc16_calc((uint8_t *)panic_header, CRC_CALC_LEN, 0xffff);
344 
345     memcpy(log_header, panic_header, sizeof(debug_panic_info_head_t));
346     k_dcache_clean((uintptr_t)log_header, sizeof(debug_panic_info_head_t));
347 
348     return 0;
349 }
350 
panic_header_get(debug_panic_info_head_t * panic_header)351 static int panic_header_get(debug_panic_info_head_t *panic_header)
352 {
353     if (panic_header == NULL) {
354         return -1;
355     }
356 
357     debug_panic_info_head_t *log_header = (debug_panic_info_head_t *)HEADER_START_ADDR;
358     memcpy(panic_header, log_header, sizeof(debug_panic_info_head_t));
359 
360     return 0;
361 }
362 
panic_log_set(uint8_t * info,uint32_t len)363 static int panic_log_set(uint8_t *info, uint32_t len)
364 {
365     if ((info == NULL) || (len == 0)) {
366         return -1;
367     }
368 
369     static uint8_t *log_ram_addr_cur = (uint8_t *)LOG_START_ADDR;
370 
371     if ((uintptr_t)(len + log_ram_addr_cur) <= (uintptr_t)LOG_END_ADDR) {
372         memcpy(log_ram_addr_cur, info, len);
373         k_dcache_clean((uintptr_t)log_ram_addr_cur, len);
374         log_ram_addr_cur += len;
375         return 0;
376     }
377 
378     return -1;
379 }
380 
panic_log_get(uint8_t * info_buffer,uint32_t len)381 static int panic_log_get(uint8_t *info_buffer, uint32_t len)
382 {
383     if (info_buffer == NULL) {
384         return -1;
385     }
386 
387     static uint8_t *log_ram_addr_cur = (uint8_t *)LOG_START_ADDR;
388     int32_t         len_tmp;
389 
390     if (log_ram_addr_cur >= (uint8_t *)LOG_END_ADDR) {
391         return -1;
392     }
393 
394     len = MIN(len, (uint8_t *)LOG_END_ADDR - log_ram_addr_cur);
395     memcpy(info_buffer, log_ram_addr_cur, len);
396     log_ram_addr_cur += len;
397 
398     len_tmp = len - 1;
399     while (len_tmp >= 0) {
400         if (info_buffer[len_tmp] != 0) {
401             break;
402         }
403         len--;
404         len_tmp--;
405     }
406 
407     return len;
408 }
409 
panic_log_clean(void)410 static void panic_log_clean(void)
411 {
412     static uint8_t *log_ram_addr_cur = (uint8_t *)LOG_START_ADDR;
413     memset(log_ram_addr_cur, 0, LOG_REGION_LEN);
414 }
415 
print_str(const char * fmt,...)416 int print_str(const char *fmt, ...)
417 {
418     int ret = -1;
419     char strbuf[400];
420 
421     va_list args;
422 
423     va_start(args, fmt);
424     ret = vsnprintf((char *)strbuf, sizeof(strbuf) - 1, fmt, args);
425     va_end(args);
426 
427     if (ret > 0) {
428         panic_log_set((uint8_t *)strbuf, ret);
429         if (panic_header_buffer.log_magic != DEBUG_PANIC_LOG_MAGIC) {
430             panic_header_buffer.log_magic = DEBUG_PANIC_LOG_MAGIC;
431             panic_header_set(&panic_header_buffer);
432         }
433     }
434 
435     return ret;
436 }
437 
vprint_str(const char * fmt,va_list ap)438 int vprint_str(const char *fmt, va_list ap)
439 {
440     int ret = -1;
441     char strbuf[400];
442 
443     ret = vsnprintf((char *)strbuf, sizeof(strbuf) - 1, fmt, ap);
444 
445     if (ret > 0) {
446         panic_log_set((uint8_t *)strbuf, ret);
447         if (panic_header_buffer.log_magic != DEBUG_PANIC_LOG_MAGIC) {
448             panic_header_buffer.log_magic = DEBUG_PANIC_LOG_MAGIC;
449             panic_header_set(&panic_header_buffer);
450         }
451     }
452 
453     return ret;
454 }
455 
456 #endif
457 
458