| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #include <linux/clk.h> |
| #include <linux/console.h> |
| #include <linux/delay.h> |
| #include <linux/init.h> |
| #include <linux/io.h> |
| #include <linux/module.h> |
| #include <linux/kernel.h> |
| #include <linux/of.h> |
| #include <linux/platform_device.h> |
| #include <linux/serial.h> |
| #include <linux/serial_core.h> |
| #include <linux/tty.h> |
| #include <linux/tty_flip.h> |
| #include <linux/pinctrl/consumer.h> |
| #include <linux/trace_events.h> |
| #include <trace/hooks/printk.h> |
| #include <linux/irqflags.h> |
| |
| static bool print_task_name_bool; |
| /* notice: this param only used by build module */ |
| module_param(print_task_name_bool, bool, 0664); |
| MODULE_PARM_DESC(print_task_name_bool, "\n statistical log printing\n"); |
| |
| void printk_caller_id(void *data, u32 *caller_id) |
| { |
| unsigned long irqflags; |
| unsigned long preempt_value = preempt_count(); |
| u8 cpu = raw_smp_processor_id(); |
| u8 irq_trace; |
| |
| #ifdef CONFIG_AMLOGIC_APU |
| if (apu_enable && cpu == apu_id) |
| cpu = 0; |
| #endif |
| |
| local_save_flags(irqflags); |
| irq_trace = |
| (irqs_disabled_flags(irqflags) ? TRACE_FLAG_IRQS_OFF : 0) | |
| ((preempt_value & NMI_MASK) ? TRACE_FLAG_NMI : 0) | |
| ((preempt_value & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) | |
| ((preempt_value & SOFTIRQ_OFFSET) ? TRACE_FLAG_SOFTIRQ : 0) | |
| (tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) | |
| (test_preempt_need_resched() ? TRACE_FLAG_PREEMPT_RESCHED : 0); |
| |
| *caller_id = (cpu << 28 | irq_trace << 20 | current->pid); |
| } |
| |
| void printk_caller(void *data, char *caller, size_t size, u32 id, int *ret) |
| { |
| struct task_struct *task = NULL; |
| char task_name[TASK_COMM_LEN] = ""; |
| u8 cpu = id >> 28; |
| u8 irq_trace = (id >> 20) & 0xff; |
| pid_t pid = id & 0xfffff; |
| |
| char hardsoft_irq; |
| char irqs_off; |
| int hardirq; |
| int softirq; |
| int nmi; |
| |
| nmi = irq_trace & TRACE_FLAG_NMI; |
| hardirq = irq_trace & TRACE_FLAG_HARDIRQ; |
| softirq = irq_trace & TRACE_FLAG_SOFTIRQ; |
| |
| irqs_off = |
| (irq_trace & TRACE_FLAG_IRQS_OFF) ? 'd' : |
| (irq_trace & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' : |
| '.'; |
| |
| hardsoft_irq = |
| (nmi && hardirq) ? 'Z' : |
| nmi ? 'z' : |
| (hardirq && softirq) ? 'H' : |
| hardirq ? 'h' : |
| softirq ? 's' : |
| '.'; |
| |
| if (print_task_name_bool) { |
| rcu_read_lock(); |
| task = find_task_by_vpid(pid); |
| rcu_read_unlock(); |
| if (task) |
| __get_task_comm(task_name, TASK_COMM_LEN, task); |
| } else { |
| sprintf(task_name, "T%u", pid); |
| } |
| |
| *ret = snprintf(caller, size, "%d %-6.6s %c%c", |
| cpu, |
| task_name, |
| irqs_off, hardsoft_irq); |
| } |
| |
| #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_ANDROID_VENDOR_HOOKS) |
| int printk_vendor_hook_init(void) |
| { |
| int ret; |
| |
| ret = register_trace_android_vh_printk_caller_id(printk_caller_id, NULL); |
| if (ret) |
| pr_err("register_trace_android_vh_printk_caller_id fail ret=%d\n", ret); |
| |
| ret = register_trace_android_vh_printk_caller(printk_caller, NULL); |
| if (ret) |
| pr_err("register_trace_android_vh_printk_caller fail ret=%d\n", ret); |
| |
| return ret; |
| } |
| |
| void printk_vendor_hook_exit(void) |
| { |
| int ret; |
| |
| ret = unregister_trace_android_vh_printk_caller_id(printk_caller_id, NULL); |
| if (ret) |
| pr_err("unregister_trace_android_vh_printk_caller_id fail ret=%d\n", ret); |
| |
| ret = unregister_trace_android_vh_printk_caller(printk_caller, NULL); |
| if (ret) |
| pr_err("unregister_trace_android_vh_printk_caller fail ret=%d\n", ret); |
| } |
| #else |
| int printk_vendor_hook_init(void) |
| { |
| return 0; |
| } |
| |
| void printk_vendor_hook_exit(void) |
| { |
| } |
| |
| void trace_android_vh_printk_caller_id(u32 *caller_id) |
| { |
| printk_caller_id(NULL, caller_id); |
| } |
| EXPORT_SYMBOL(trace_android_vh_printk_caller_id); |
| |
| void trace_android_vh_printk_caller(char *caller, size_t size, u32 id, int *ret) |
| { |
| printk_caller(NULL, caller, size, id, ret); |
| } |
| EXPORT_SYMBOL(trace_android_vh_printk_caller); |
| |
| #endif /* END CONFIG_ANDROID_VENDOR_HOOKS */ |
| |
| #if IS_BUILTIN(CONFIG_AMLOGIC_DEBUG_PRINTK) |
| early_initcall(printk_vendor_hook_init); |
| module_exit(printk_vendor_hook_exit); |
| #endif |