Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d16ae5dd authored by Rama Aparna Mallavarapu's avatar Rama Aparna Mallavarapu
Browse files

coresight: abort coresight tracing on kernel crash



Add trace events to control aborting CoreSight trace
dynamically based on module parameter.
Coresight driver will dump any trace present in the current sink
in case we hit a kernel panic, user fault or an undefined instruction.

Change-Id: I668c8cda285250a0b8dcccd2c1d2a8471977ce5c
Signed-off-by: default avatarSatyajit Desai <sadesai@codeaurora.org>
Signed-off-by: default avatarRama Aparna Mallavarapu <aparnam@codeaurora.org>
parent f3fbc3a3
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include <asm/exception.h>
#include <asm/system_misc.h>
#include <asm/sysreg.h>
#include <trace/events/exception.h>

static const char *handler[]= {
	"Synchronous Abort",
@@ -458,6 +459,8 @@ void arm64_notify_segfault(struct pt_regs *regs, unsigned long addr)

asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
{
	void __user *pc = (void __user *)instruction_pointer(regs);

	/* check for AArch32 breakpoint instructions */
	if (!aarch32_break_handler(regs))
		return;
@@ -465,6 +468,8 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
	if (call_undef_hook(regs) == 0)
		return;

	trace_undef_instr(regs, pc);

	force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
}

+3 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <soc/qcom/scm.h>
#include <trace/events/exception.h>

struct fault_info {
	int	(*fn)(unsigned long addr, unsigned int esr,
@@ -212,6 +213,8 @@ static void __do_user_fault(struct task_struct *tsk, unsigned long addr,
	struct siginfo si;
	const struct fault_info *inf;

	trace_user_fault(tsk, addr, esr);

	if (unhandled_signal(tsk, sig) && show_unhandled_signals_ratelimited()) {
		inf = esr_to_fault_info(esr);
		pr_info("%s[%d]: unhandled %s (%d) at 0x%08lx, esr 0x%03x\n",
+8 −0
Original line number Diff line number Diff line
@@ -148,6 +148,14 @@ config CORESIGHT_CTI
	  hardware component to another. It can also be used to pass
	  software generated events.

config CORESIGHT_EVENT
        tristate "CoreSight Event driver"
        help
          This driver provides support for registering with various events
          and performing CoreSight actions like aborting trace on their
          occurrence. These events can be controlled by using module
          parameters.

config CORESIGHT_CSR
	bool "CoreSight Slave Register driver"
	help
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o
obj-$(CONFIG_CORESIGHT_OST) += coresight-ost.o
obj-$(CONFIG_CORESIGHT_TPDA) += coresight-tpda.o
obj-$(CONFIG_CORESIGHT_TPDM) += coresight-tpdm.o
obj-$(CONFIG_CORESIGHT_EVENT) += coresight-event.o
obj-$(CONFIG_CORESIGHT_CTI) += coresight-cti.o
obj-$(CONFIG_CORESIGHT_CSR) += coresight-csr.o
obj-$(CONFIG_CORESIGHT_HWEVENT) += coresight-hwevent.o
+169 −0
Original line number Diff line number Diff line
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/coresight.h>

#include <trace/events/exception.h>

static int event_abort_enable;
static int event_abort_set(const char *val, struct kernel_param *kp);
module_param_call(event_abort_enable, event_abort_set, param_get_int,
		  &event_abort_enable, 0644);

static int event_abort_early_panic = 1;
static int event_abort_on_panic_set(const char *val, struct kernel_param *kp);
module_param_call(event_abort_early_panic, event_abort_on_panic_set,
		  param_get_int, &event_abort_early_panic, 0644);

static void event_abort_user_fault(void *ignore,
				   struct task_struct *task,
				   unsigned long addr,
				   unsigned int fsr)
{
	coresight_abort();
	pr_debug("coresight_event: task_name: %s, addr: %lu, fsr:%u",
		(char *)task->comm, addr, fsr);
}

static void event_abort_undef_instr(void *ignore,
				    struct pt_regs *regs,
				    void __user *pc)
{
	if (user_mode(regs)) {
		coresight_abort();
		pr_debug("coresight_event: pc: %pK", pc);
	}
}

static void event_abort_unhandled_abort(void *ignore,
					struct pt_regs *regs,
					unsigned long addr,
					unsigned int fsr)
{
	if (user_mode(regs)) {
		coresight_abort();
		pr_debug("coresight_event: addr: %lu, fsr:%u", addr, fsr);
	}
}

static void event_abort_kernel_panic(void *ignore, long state)
{
	coresight_abort();
}

static int event_abort_register(void)
{
	int ret;

	ret = register_trace_user_fault(event_abort_user_fault, NULL);
	if (ret)
		goto err_usr_fault;
	ret = register_trace_undef_instr(event_abort_undef_instr, NULL);
	if (ret)
		goto err_undef_instr;
	ret = register_trace_unhandled_abort(event_abort_unhandled_abort, NULL);
	if (ret)
		goto err_unhandled_abort;

	return 0;

err_unhandled_abort:
	unregister_trace_undef_instr(event_abort_undef_instr, NULL);
err_undef_instr:
	unregister_trace_user_fault(event_abort_user_fault, NULL);
err_usr_fault:
	return ret;
}

static void event_abort_unregister(void)
{
	unregister_trace_user_fault(event_abort_user_fault, NULL);
	unregister_trace_undef_instr(event_abort_undef_instr, NULL);
	unregister_trace_unhandled_abort(event_abort_unhandled_abort, NULL);
}

static int event_abort_set(const char *val, struct kernel_param *kp)
{
	int ret;

	ret = param_set_int(val, kp);
	if (ret) {
		pr_err("coresight_event: error setting value %d\n", ret);
		return ret;
	}

	if (event_abort_enable)
		ret = event_abort_register();
	else
		event_abort_unregister();

	return ret;
}

static int event_abort_on_panic_set(const char *val, struct kernel_param *kp)
{
	int ret;

	ret = param_set_int(val, kp);
	if (ret) {
		pr_err("coresight_event: error setting val on panic %d\n", ret);
		return ret;
	}

	if (event_abort_early_panic) {
		unregister_trace_kernel_panic_late(event_abort_kernel_panic,
						   NULL);
		 ret = register_trace_kernel_panic(event_abort_kernel_panic,
						  NULL);
		if (ret)
			goto err;
	} else {
		unregister_trace_kernel_panic(event_abort_kernel_panic, NULL);
		ret = register_trace_kernel_panic_late(event_abort_kernel_panic,
							NULL);
		if (ret)
			goto err;
	}
	return 0;
err:
	pr_err("coresight_event: error registering panic event %d\n", ret);
	return ret;
}

static int __init event_init(void)
{
	int ret;

	ret = register_trace_kernel_panic(event_abort_kernel_panic, NULL);
	if (ret) {
		/* We do not want to fail module init. This module can still
		 * be used to register other abort events.
		 */
		pr_err("coresight_event: error registering on panic %d\n", ret);
	}
	return 0;
}
module_init(event_init);

static void __exit event_exit(void)
{
	unregister_trace_kernel_panic(event_abort_kernel_panic, NULL);
}
module_exit(event_exit);

MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Coresight Event driver to abort tracing");
Loading