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