1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2021 Huawei Technologies Co., Ltd. All rights reserved.
4 */
5
6 #include <linux/blackbox.h>
7 #include <linux/kernel.h>
8 #include <linux/delay.h>
9 #include <linux/kthread.h>
10 #include <linux/list.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14 #include <linux/syscalls.h>
15 #include <linux/time.h>
16 #include <linux/vmalloc.h>
17 #include <linux/version.h>
18 #include <linux/sched/debug.h>
19 #include <linux/blackbox_common.h>
20 #include <linux/blackbox_storage.h>
21
22 /* ---- local macroes ---- */
23 /* bbox/BBOX - blackbox */
24 #define HISTORY_LOG_NAME "history.log"
25 #define LOG_PART_WAIT_TIME 1000 /* unit: ms */
26 #define HISTORY_LOG_MAX_LEN 1024
27 #define TOP_CATEGORY_SYSTEM_RESET "System Reset"
28 #define TOP_CATEGORY_FREEZE "System Freeze"
29 #define TOP_CATEGORY_SYSTEM_POWEROFF "POWEROFF"
30 #define TOP_CATEGORY_SUBSYSTEM_CRASH "Subsystem Crash"
31 #define CATEGORY_SYSTEM_REBOOT "SYSREBOOT"
32 #define CATEGORY_SYSTEM_POWEROFF "POWEROFF"
33 #define CATEGORY_SYSTEM_PANIC "PANIC"
34 #define CATEGORY_SYSTEM_OOPS "OOPS"
35 #define CATEGORY_SYSTEM_CUSTOM "CUSTOM"
36 #define CATEGORY_SYSTEM_WATCHDOG "HWWATCHDOG"
37 #define CATEGORY_SYSTEM_HUNGTASK "HUNGTASK"
38 #define CATEGORY_SUBSYSTEM_CUSTOM "CUSTOM"
39
40 #ifndef CONFIG_BLACKBOX_LOG_ROOT_PATH
41 #error no blackbox log root path
42 #endif
43 #ifndef CONFIG_BLACKBOX_LOG_PART_REPRESENTATIVE
44 #error no representative of the blackbox log part
45 #endif
46
47 /* ---- local prototypes ---- */
48 struct bbox_ops {
49 struct list_head list;
50 struct module_ops ops;
51 };
52
53 struct error_info_to_category {
54 const char *module;
55 struct {
56 const char *event;
57 const char *category;
58 const char *top_category;
59 } map;
60 };
61
62 /* ---- local variables ---- */
63 static LIST_HEAD(ops_list);
64 static DEFINE_SPINLOCK(ops_list_lock);
65 static DEFINE_SEMAPHORE(temp_error_info_sem);
66 static struct error_info_to_category error_info_categorys[] = {
67 {
68 MODULE_SYSTEM,
69 {EVENT_SYSREBOOT, CATEGORY_SYSTEM_REBOOT, TOP_CATEGORY_SYSTEM_RESET}
70 },
71 {
72 MODULE_SYSTEM,
73 {EVENT_LONGPRESS, CATEGORY_SYSTEM_REBOOT, TOP_CATEGORY_SYSTEM_RESET}
74 },
75 {
76 MODULE_SYSTEM,
77 {EVENT_COMBINATIONKEY, CATEGORY_SYSTEM_REBOOT, TOP_CATEGORY_SYSTEM_RESET}
78 },
79 {
80 MODULE_SYSTEM,
81 {EVENT_SUBSYSREBOOT, CATEGORY_SYSTEM_REBOOT, TOP_CATEGORY_SYSTEM_RESET}
82 },
83 {
84 MODULE_SYSTEM,
85 {EVENT_POWEROFF, CATEGORY_SYSTEM_POWEROFF, TOP_CATEGORY_SYSTEM_POWEROFF}
86 },
87 {
88 MODULE_SYSTEM,
89 {EVENT_PANIC, CATEGORY_SYSTEM_PANIC, TOP_CATEGORY_SYSTEM_RESET}
90 },
91 {
92 MODULE_SYSTEM,
93 {EVENT_OOPS, CATEGORY_SYSTEM_OOPS, TOP_CATEGORY_SYSTEM_RESET}
94 },
95 {
96 MODULE_SYSTEM,
97 {EVENT_SYS_WATCHDOG, CATEGORY_SYSTEM_WATCHDOG, TOP_CATEGORY_FREEZE}
98 },
99 {
100 MODULE_SYSTEM,
101 {EVENT_HUNGTASK, CATEGORY_SYSTEM_HUNGTASK, TOP_CATEGORY_FREEZE}
102 },
103 };
104
105 struct error_info *temp_error_info;
106
107 /* ---- local function prototypes ---- */
108 static const char *get_top_category(const char *module, const char *event);
109 static const char *get_category(const char *module, const char *event);
110 static void format_log_dir(char *buf, size_t buf_size,
111 const char *log_root_dir, const char event[EVENT_MAX_LEN],
112 const char *timestamp);
113 static void save_history_log(const char *log_root_dir,
114 struct error_info *info, const char *timestamp, int need_sys_reset);
115 static void wait_for_log_part(void);
116 static void format_error_info(struct error_info *info,
117 const char event[EVENT_MAX_LEN],
118 const char module[MODULE_MAX_LEN],
119 const char error_desc[ERROR_DESC_MAX_LEN]);
120 static void save_last_log(void);
121 static int save_error_log(void *pparam);
122
123 /* ---- global function prototypes ---- */
124
125 /* ---- function definitions ---- */
get_top_category(const char * module,const char * event)126 static const char *get_top_category(const char *module, const char *event)
127 {
128 int i;
129 int count = (int)ARRAY_SIZE(error_info_categorys);
130
131 if (unlikely(!module || !event)) {
132 bbox_print_err("module: %p, event: %p\n", module, event);
133 return TOP_CATEGORY_SUBSYSTEM_CRASH;
134 }
135
136 for (i = 0; i < count; i++) {
137 if (!strcmp(error_info_categorys[i].module, module) &&
138 !strcmp(error_info_categorys[i].map.event, event)) {
139 return error_info_categorys[i].map.top_category;
140 }
141 }
142 if (!strcmp(module, MODULE_SYSTEM))
143 return TOP_CATEGORY_SYSTEM_RESET;
144
145 return TOP_CATEGORY_SUBSYSTEM_CRASH;
146 }
147
get_category(const char * module,const char * event)148 static const char *get_category(const char *module, const char *event)
149 {
150 int i;
151 int count = (int)ARRAY_SIZE(error_info_categorys);
152
153 if (unlikely(!module || !event)) {
154 bbox_print_err("module: %p, event: %p\n", module, event);
155 return CATEGORY_SUBSYSTEM_CUSTOM;
156 }
157
158 for (i = 0; i < count; i++) {
159 if (!strcmp(error_info_categorys[i].module, module) &&
160 !strcmp(error_info_categorys[i].map.event, event)) {
161 return error_info_categorys[i].map.category;
162 }
163 }
164 if (!strcmp(module, MODULE_SYSTEM))
165 return CATEGORY_SYSTEM_CUSTOM;
166
167 return CATEGORY_SUBSYSTEM_CUSTOM;
168 }
169
format_log_dir(char * buf,size_t buf_size,const char * log_root_dir,const char event[EVENT_MAX_LEN],const char * timestamp)170 static void format_log_dir(char *buf, size_t buf_size,
171 const char *log_root_dir, const char event[EVENT_MAX_LEN],
172 const char *timestamp)
173 {
174 if (unlikely(!buf || buf_size == 0 || !log_root_dir ||
175 !event || !timestamp)) {
176 bbox_print_err("buf: %p, buf_size: %u, log_root_dir: %p, event: %p, timestamp: %p\n",
177 buf, (unsigned int)buf_size, log_root_dir, event, timestamp);
178 return;
179 }
180
181 memset(buf, 0, buf_size);
182 scnprintf(buf, buf_size - 1, "%s/%s_%s", log_root_dir, event, timestamp);
183 }
184
format_error_info(struct error_info * info,const char event[EVENT_MAX_LEN],const char module[MODULE_MAX_LEN],const char error_desc[ERROR_DESC_MAX_LEN])185 static void format_error_info(struct error_info *info,
186 const char event[EVENT_MAX_LEN],
187 const char module[MODULE_MAX_LEN],
188 const char error_desc[ERROR_DESC_MAX_LEN])
189 {
190 if (unlikely(!info || !event || !module || !error_desc)) {
191 bbox_print_err("info: %p, event: %p, module: %p, error_desc: %p\n",
192 info, event, module, error_desc);
193 return;
194 }
195
196 memset(info, 0, sizeof(*info));
197 strncpy(info->event, event, min(strlen(event),
198 sizeof(info->event) - 1));
199 strncpy(info->module, module, min(strlen(module),
200 sizeof(info->module) - 1));
201 get_timestamp(info->error_time, TIMESTAMP_MAX_LEN);
202 strncpy(info->error_desc, error_desc, min(strlen(error_desc),
203 sizeof(info->error_desc) - 1));
204 }
205
save_history_log(const char * log_root_dir,struct error_info * info,const char * timestamp,int need_sys_reset)206 static void save_history_log(const char *log_root_dir,
207 struct error_info *info, const char *timestamp, int need_sys_reset)
208 {
209 char history_log_path[PATH_MAX_LEN];
210 char *buf;
211
212 if (unlikely(!log_root_dir || !info || !timestamp)) {
213 bbox_print_err("log_root_dir: %p, info: %p, timestamp: %p\n",
214 log_root_dir, info, timestamp);
215 return;
216 }
217
218 buf = vmalloc(HISTORY_LOG_MAX_LEN + 1);
219 if (!buf)
220 return;
221
222 memset(buf, 0, HISTORY_LOG_MAX_LEN + 1);
223 scnprintf(buf, HISTORY_LOG_MAX_LEN, HISTORY_LOG_FORMAT,
224 get_top_category(info->module, info->event), info->module,
225 get_category(info->module, info->event), info->event, timestamp,
226 need_sys_reset ? "true" : "false", info->error_desc);
227 memset(history_log_path, 0, sizeof(history_log_path));
228 scnprintf(history_log_path, sizeof(history_log_path) - 1,
229 "%s/%s", log_root_dir, HISTORY_LOG_NAME);
230 full_write_file(history_log_path, buf, strlen(buf), 1);
231 change_own_mode(history_log_path, AID_ROOT, AID_SYSTEM, BBOX_FILE_LIMIT);
232 vfree(buf);
233 }
234
is_log_part_mounted(void)235 static bool is_log_part_mounted(void)
236 {
237 int ret;
238 mm_segment_t old_fs;
239
240 old_fs = get_fs();
241 set_fs(KERNEL_DS);
242 ret = sys_access(CONFIG_BLACKBOX_LOG_PART_REPRESENTATIVE, 0);
243 set_fs(old_fs);
244
245 return ret == 0;
246 }
247
wait_for_log_part(void)248 static void wait_for_log_part(void)
249 {
250 bbox_print_info("wait for log part [%s] begin!\n",
251 CONFIG_BLACKBOX_LOG_PART_REPRESENTATIVE);
252 while (!is_log_part_mounted())
253 msleep(LOG_PART_WAIT_TIME);
254
255 bbox_print_info("wait for log part [%s] end!\n",
256 CONFIG_BLACKBOX_LOG_PART_REPRESENTATIVE);
257 }
258
find_module_ops(struct error_info * info,struct bbox_ops ** ops)259 static bool find_module_ops(struct error_info *info, struct bbox_ops **ops)
260 {
261 struct list_head *cur = NULL;
262 struct list_head *next = NULL;
263 bool find_module = false;
264
265 if (unlikely(!info || !ops)) {
266 bbox_print_err("info: %p, ops: %p!\n", info, ops);
267 return find_module;
268 }
269
270 list_for_each_safe(cur, next, &ops_list) {
271 *ops = list_entry(cur, struct bbox_ops, list);
272 if (*ops && !strcmp((*ops)->ops.module, info->module)) {
273 find_module = true;
274 break;
275 }
276 }
277 if (!find_module)
278 bbox_print_err("[%s] hasn't been registered!\n", info->module);
279
280 return find_module;
281 }
282
invoke_module_ops(const char * log_dir,struct error_info * info,struct bbox_ops * ops)283 static void invoke_module_ops(const char *log_dir, struct error_info *info,
284 struct bbox_ops *ops)
285 {
286 if (unlikely(!info || !!ops)) {
287 bbox_print_err("info: %p, ops: %p!\n", info, ops);
288 return;
289 }
290
291 if (ops->ops.dump && log_dir) {
292 bbox_print_info("[%s] starts dumping data!\n", ops->ops.module);
293 ops->ops.dump(log_dir, info);
294 bbox_print_info("[%s] ends dumping data!\n", ops->ops.module);
295 }
296 if (ops->ops.reset) {
297 bbox_print_info("[%s] starts resetting!\n", ops->ops.module);
298 ops->ops.reset(info);
299 bbox_print_info("[%s] ends resetting!\n", ops->ops.module);
300 }
301 }
302
save_log_without_reset(struct error_info * info)303 static void save_log_without_reset(struct error_info *info)
304 {
305 unsigned long flags;
306 struct bbox_ops *ops = NULL;
307 char *log_dir = NULL;
308 char timestamp[TIMESTAMP_MAX_LEN];
309
310 if (unlikely(!info)) {
311 bbox_print_err("info: %p!\n", info);
312 return;
313 }
314
315 /* get timestamp */
316 get_timestamp(timestamp, sizeof(timestamp));
317
318 /* get bbox ops */
319 spin_lock_irqsave(&ops_list_lock, flags);
320 if (!find_module_ops(info, &ops)) {
321 spin_unlock_irqrestore(&ops_list_lock, flags);
322 return;
323 }
324 spin_unlock_irqrestore(&ops_list_lock, flags);
325 create_log_dir(CONFIG_BLACKBOX_LOG_ROOT_PATH);
326 if (ops->ops.dump) {
327 /* create log root path */
328 if (log_dir) {
329 format_log_dir(log_dir, PATH_MAX_LEN,
330 CONFIG_BLACKBOX_LOG_ROOT_PATH, info->event, timestamp);
331 create_log_dir(log_dir);
332 } else
333 bbox_print_err("vmalloc failed!\n");
334 }
335 invoke_module_ops(log_dir, info, ops);
336 save_history_log(CONFIG_BLACKBOX_LOG_ROOT_PATH, info, timestamp, 0);
337 if (log_dir)
338 vfree(log_dir);
339 }
340
save_log_with_reset(struct error_info * info)341 static void save_log_with_reset(struct error_info *info)
342 {
343 struct bbox_ops *ops = NULL;
344
345 if (unlikely(!info)) {
346 bbox_print_err("info: %p!\n", info);
347 return;
348 }
349
350 if (!find_module_ops(info, &ops))
351 return;
352
353 invoke_module_ops("", info, ops);
354 sys_reset();
355 }
356
save_temp_error_info(const char event[EVENT_MAX_LEN],const char module[MODULE_MAX_LEN],const char error_desc[ERROR_DESC_MAX_LEN])357 static void save_temp_error_info(const char event[EVENT_MAX_LEN],
358 const char module[MODULE_MAX_LEN],
359 const char error_desc[ERROR_DESC_MAX_LEN])
360 {
361 if (unlikely(!event || !module || !error_desc)) {
362 bbox_print_err("event: %p, module: %p, error_desc: %p\n",
363 event, module, error_desc);
364 return;
365 }
366
367 down(&temp_error_info_sem);
368 format_error_info(temp_error_info, event, module, error_desc);
369 up(&temp_error_info_sem);
370 }
371
do_save_last_log(const struct bbox_ops * ops,const struct error_info * info)372 static void do_save_last_log(const struct bbox_ops *ops, const struct error_info *info)
373 {
374 char *log_dir = NULL;
375
376 if (unlikely(!ops || !info)) {
377 bbox_print_err("ops: %p, info: %p\n",
378 ops, info);
379 return;
380 }
381
382 memset((void *)info, 0, sizeof(*info));
383 if (ops->ops.get_last_log_info((struct error_info *)info) != 0) {
384 bbox_print_err("[%s] failed to get log info!\n", ops->ops.module);
385 return;
386 }
387 bbox_print_info("[%s] starts saving log!\n", ops->ops.module);
388 bbox_print_info("event: [%s] module: [%s], time is [%s]!\n",
389 info->event, info->module, info->error_time);
390
391 log_dir = vmalloc(PATH_MAX_LEN);
392 if (!log_dir)
393 return;
394
395 if (!strlen(info->error_time))
396 get_timestamp((char *)info->error_time, TIMESTAMP_MAX_LEN);
397
398 format_log_dir(log_dir, PATH_MAX_LEN, CONFIG_BLACKBOX_LOG_ROOT_PATH,
399 info->event, info->error_time);
400 create_log_dir(log_dir);
401 if (ops->ops.save_last_log(log_dir, (struct error_info *)info) == 0)
402 save_history_log(CONFIG_BLACKBOX_LOG_ROOT_PATH,
403 (struct error_info *)info, info->error_time, 1);
404 else
405 bbox_print_err("[%s] failed to save log!\n", ops->ops.module);
406 vfree(log_dir);
407 }
408
save_last_log(void)409 static void save_last_log(void)
410 {
411 unsigned long flags;
412 struct error_info *info = NULL;
413 struct list_head *cur = NULL;
414 struct list_head *next = NULL;
415
416 info = vmalloc(sizeof(*info));
417 if (!info)
418 return;
419
420 spin_lock_irqsave(&ops_list_lock, flags);
421 list_for_each_safe(cur, next, &ops_list) {
422 struct bbox_ops *ops = list_entry(cur, struct bbox_ops, list);
423
424 if (!ops) {
425 bbox_print_err("ops is NULL!\n");
426 continue;
427 }
428
429 if (ops->ops.get_last_log_info &&
430 ops->ops.save_last_log) {
431 spin_unlock_irqrestore(&ops_list_lock, flags);
432 do_save_last_log(ops, info);
433 spin_lock_irqsave(&ops_list_lock, flags);
434 } else {
435 bbox_print_err("[%s] get_last_log_info: %p, %s: %p\n",
436 ops->ops.module, ops->ops.get_last_log_info,
437 __func__, ops->ops.save_last_log);
438 }
439 }
440 spin_unlock_irqrestore(&ops_list_lock, flags);
441 vfree(info);
442 }
443
save_temp_error_log(void)444 static void save_temp_error_log(void)
445 {
446 down(&temp_error_info_sem);
447 if (!temp_error_info) {
448 bbox_print_err("temp_error_info: %p\n", temp_error_info);
449 up(&temp_error_info_sem);
450 return;
451 }
452
453 if (strlen(temp_error_info->event) != 0)
454 save_log_without_reset(temp_error_info);
455
456 vfree(temp_error_info);
457 temp_error_info = NULL;
458 up(&temp_error_info_sem);
459 }
460
save_error_log(void * pparam)461 static int save_error_log(void *pparam)
462 {
463 wait_for_log_part();
464 save_last_log();
465 save_temp_error_log();
466
467 return 0;
468 }
469
470 #ifdef CONFIG_BLACKBOX_DEBUG
print_module_ops(void)471 static void print_module_ops(void)
472 {
473 struct bbox_ops *temp = NULL;
474
475 bbox_print_info("The following modules have been registered!\n");
476 list_for_each_entry(temp, &ops_list, list) {
477 bbox_print_info("module: %s, dump: %p, reset: %p, get_last_log_info: %p,
478 save_last_log: %p\n",
479 temp->ops.module, temp->ops.dump, temp->ops.reset, temp->ops.get_last_log_info,
480 temp->ops.save_last_log);
481 }
482 }
483 #endif
484
bbox_register_module_ops(struct module_ops * ops)485 int bbox_register_module_ops(struct module_ops *ops)
486 {
487 struct bbox_ops *new_ops = NULL;
488 struct bbox_ops *temp = NULL;
489 struct list_head *cur = NULL;
490 struct list_head *next = NULL;
491 unsigned long flags;
492
493 if (unlikely(!ops)) {
494 bbox_print_err("ops: %p\n", ops);
495 return -EINVAL;
496 }
497
498 new_ops = vmalloc(sizeof(*new_ops));
499 if (!new_ops)
500 return -ENOMEM;
501 memset(new_ops, 0, sizeof(*new_ops));
502 memcpy(&new_ops->ops, ops, sizeof(*ops));
503 spin_lock_irqsave(&ops_list_lock, flags);
504 if (list_empty(&ops_list))
505 goto __out;
506
507 list_for_each_safe(cur, next, &ops_list) {
508 temp = list_entry(cur, struct bbox_ops, list);
509 if (!strcmp(temp->ops.module, ops->module)) {
510 spin_unlock_irqrestore(&ops_list_lock, flags);
511 vfree(new_ops);
512 bbox_print_info("[%s] has been registered!\n", temp->ops.module);
513 return -ENODATA;
514 }
515 }
516
517 __out:
518 bbox_print_info("[%s] is registered successfully!\n", ops->module);
519 list_add_tail(&new_ops->list, &ops_list);
520 spin_unlock_irqrestore(&ops_list_lock, flags);
521 #ifdef CONFIG_BLACKBOX_DEBUG
522 print_module_ops();
523 #endif
524
525 return 0;
526 }
527
bbox_notify_error(const char event[EVENT_MAX_LEN],const char module[MODULE_MAX_LEN],const char error_desc[ERROR_DESC_MAX_LEN],int need_sys_reset)528 int bbox_notify_error(const char event[EVENT_MAX_LEN], const char module[MODULE_MAX_LEN],
529 const char error_desc[ERROR_DESC_MAX_LEN], int need_sys_reset)
530 {
531 struct error_info *info = NULL;
532
533 if (unlikely(!event || !module || !error_desc)) {
534 bbox_print_err("event: %p, module: %p, error_desc: %p\n", event,
535 module, error_desc);
536 return -EINVAL;
537 }
538
539 info = vmalloc(sizeof(*info));
540 if (!info)
541 return -ENOMEM;
542
543 format_error_info(info, event, module, error_desc);
544 show_stack(current, NULL, KERN_DEFAULT);
545 if (!need_sys_reset) {
546 /* handle the error which do not need reset */
547 if (!is_log_part_mounted())
548 save_temp_error_info(event, module, error_desc);
549 else
550 save_log_without_reset(info);
551 } else {
552 /* handle the error which need reset */
553 save_log_with_reset(info);
554 }
555
556 vfree(info);
557
558 return 0;
559 }
560
select_storage_material(void)561 static void __init select_storage_material(void)
562 {
563 const struct reboot_crashlog_storage *tmp = NULL;
564
565 if (!storage_material)
566 return;
567
568 for (tmp = storage_lastwords; tmp->material; tmp++) {
569 if (!strcmp(storage_material, tmp->material)) {
570 storage_lastword = tmp;
571 return;
572 }
573 }
574 }
575
blackbox_core_init(void)576 static int __init blackbox_core_init(void)
577 {
578 struct task_struct *tsk = NULL;
579
580 select_storage_material();
581
582 temp_error_info = vmalloc(sizeof(*temp_error_info));
583 if (!temp_error_info)
584 return -ENOMEM;
585
586 memset(temp_error_info, 0, sizeof(*temp_error_info));
587
588 /* Create a kernel thread to save log */
589 tsk = kthread_run(save_error_log, NULL, "save_error_log");
590 if (IS_ERR(tsk)) {
591 vfree(temp_error_info);
592 temp_error_info = NULL;
593 bbox_print_err("kthread_run failed!\n");
594 return -ESRCH;
595 }
596
597 return 0;
598 }
599
600 core_initcall(blackbox_core_init);
601 MODULE_LICENSE("GPL v2");
602 MODULE_DESCRIPTION("Blackbox core framework");
603 MODULE_AUTHOR("OHOS");
604