• 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/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