1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
/* Copyright (c) 2012-2016, 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, const 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,
const 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 *pc)
{
if (user_mode(regs)) {
coresight_abort();
pr_debug("coresight_event: pc: %p", 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, const 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,
const 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");
|