• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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