]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - arch/arm/common/fiq_debugger_arm.c
FIQ: Implement WDT FIQ debugger
[sojka/nv-tegra/linux-3.10.git] / arch / arm / common / fiq_debugger_arm.c
1 /*
2  * Copyright (C) 2014 Google, Inc.
3  * Author: Colin Cross <ccross@android.com>
4  * Copyright (C) 2010-2015 NVIDIA Corporation.  All rights reserved.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/ptrace.h>
18 #include <linux/uaccess.h>
19
20 #include <asm/stacktrace.h>
21
22 #include "fiq_debugger_priv.h"
23
24 static char *mode_name(unsigned cpsr)
25 {
26         switch (cpsr & MODE_MASK) {
27         case USR_MODE: return "USR";
28         case FIQ_MODE: return "FIQ";
29         case IRQ_MODE: return "IRQ";
30         case SVC_MODE: return "SVC";
31         case ABT_MODE: return "ABT";
32         case UND_MODE: return "UND";
33         case SYSTEM_MODE: return "SYS";
34         default: return "???";
35         }
36 }
37
38 void fiq_debugger_dump_pc(struct fiq_debugger_output *output,
39                 const struct pt_regs *regs)
40 {
41         output->printf(output, " pc %08x cpsr %08x mode %s\n",
42                 regs->ARM_pc, regs->ARM_cpsr, mode_name(regs->ARM_cpsr));
43 }
44
45 void fiq_debugger_dump_regs(struct fiq_debugger_output *output,
46                 const struct pt_regs *regs)
47 {
48         output->printf(output,
49                         " r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
50                         regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
51         output->printf(output,
52                         " r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
53                         regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
54         output->printf(output,
55                         " r8 %08x  r9 %08x r10 %08x r11 %08x  mode %s\n",
56                         regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp,
57                         mode_name(regs->ARM_cpsr));
58         output->printf(output,
59                         " ip %08x  sp %08x  lr %08x  pc %08x cpsr %08x\n",
60                         regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc,
61                         regs->ARM_cpsr);
62 }
63
64 struct mode_regs {
65         unsigned long sp_svc;
66         unsigned long lr_svc;
67         unsigned long spsr_svc;
68
69         unsigned long sp_abt;
70         unsigned long lr_abt;
71         unsigned long spsr_abt;
72
73         unsigned long sp_und;
74         unsigned long lr_und;
75         unsigned long spsr_und;
76
77         unsigned long sp_irq;
78         unsigned long lr_irq;
79         unsigned long spsr_irq;
80
81         unsigned long r8_fiq;
82         unsigned long r9_fiq;
83         unsigned long r10_fiq;
84         unsigned long r11_fiq;
85         unsigned long r12_fiq;
86         unsigned long sp_fiq;
87         unsigned long lr_fiq;
88         unsigned long spsr_fiq;
89 };
90
91 static void __naked get_mode_regs(struct mode_regs *regs)
92 {
93         asm volatile (
94         "mrs    r1, cpsr\n"
95         "msr    cpsr_c, #0xd3 @(SVC_MODE | PSR_I_BIT | PSR_F_BIT)\n"
96         "stmia  r0!, {r13 - r14}\n"
97         "mrs    r2, spsr\n"
98         "msr    cpsr_c, #0xd7 @(ABT_MODE | PSR_I_BIT | PSR_F_BIT)\n"
99         "stmia  r0!, {r2, r13 - r14}\n"
100         "mrs    r2, spsr\n"
101         "msr    cpsr_c, #0xdb @(UND_MODE | PSR_I_BIT | PSR_F_BIT)\n"
102         "stmia  r0!, {r2, r13 - r14}\n"
103         "mrs    r2, spsr\n"
104         "msr    cpsr_c, #0xd2 @(IRQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
105         "stmia  r0!, {r2, r13 - r14}\n"
106         "mrs    r2, spsr\n"
107         "msr    cpsr_c, #0xd1 @(FIQ_MODE | PSR_I_BIT | PSR_F_BIT)\n"
108         "stmia  r0!, {r2, r8 - r14}\n"
109         "mrs    r2, spsr\n"
110         "stmia  r0!, {r2}\n"
111         "msr    cpsr_c, r1\n"
112         "bx     lr\n");
113 }
114
115
116 void fiq_debugger_dump_allregs(struct fiq_debugger_output *output,
117                 const struct pt_regs *regs)
118 {
119         struct mode_regs mode_regs;
120         unsigned long mode = regs->ARM_cpsr & MODE_MASK;
121
122         fiq_debugger_dump_regs(output, regs);
123         get_mode_regs(&mode_regs);
124
125         output->printf(output,
126                         "%csvc: sp %08x  lr %08x  spsr %08x\n",
127                         mode == SVC_MODE ? '*' : ' ',
128                         mode_regs.sp_svc, mode_regs.lr_svc, mode_regs.spsr_svc);
129         output->printf(output,
130                         "%cabt: sp %08x  lr %08x  spsr %08x\n",
131                         mode == ABT_MODE ? '*' : ' ',
132                         mode_regs.sp_abt, mode_regs.lr_abt, mode_regs.spsr_abt);
133         output->printf(output,
134                         "%cund: sp %08x  lr %08x  spsr %08x\n",
135                         mode == UND_MODE ? '*' : ' ',
136                         mode_regs.sp_und, mode_regs.lr_und, mode_regs.spsr_und);
137         output->printf(output,
138                         "%cirq: sp %08x  lr %08x  spsr %08x\n",
139                         mode == IRQ_MODE ? '*' : ' ',
140                         mode_regs.sp_irq, mode_regs.lr_irq, mode_regs.spsr_irq);
141         output->printf(output,
142                         "%cfiq: r8 %08x  r9 %08x  r10 %08x  r11 %08x  r12 %08x\n",
143                         mode == FIQ_MODE ? '*' : ' ',
144                         mode_regs.r8_fiq, mode_regs.r9_fiq, mode_regs.r10_fiq,
145                         mode_regs.r11_fiq, mode_regs.r12_fiq);
146         output->printf(output,
147                         " fiq: sp %08x  lr %08x  spsr %08x\n",
148                         mode_regs.sp_fiq, mode_regs.lr_fiq, mode_regs.spsr_fiq);
149 }
150
151 struct stacktrace_state {
152         struct fiq_debugger_output *output;
153         unsigned int depth;
154 };
155
156 static int report_trace(struct stackframe *frame, void *d)
157 {
158         struct stacktrace_state *sts = d;
159
160         if (sts->depth) {
161                 sts->output->printf(sts->output,
162                         "  pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
163                         frame->pc, frame->pc, frame->lr, frame->lr,
164                         frame->sp, frame->fp);
165                 sts->depth--;
166                 return 0;
167         }
168         sts->output->printf(sts->output, "  ...\n");
169
170         return sts->depth == 0;
171 }
172
173 struct frame_tail {
174         struct frame_tail *fp;
175         unsigned long sp;
176         unsigned long lr;
177 } __attribute__((packed));
178
179 static struct frame_tail *user_backtrace(struct fiq_debugger_output *output,
180                                         struct frame_tail *tail)
181 {
182         struct frame_tail buftail[2];
183
184         /* Also check accessibility of one struct frame_tail beyond */
185         if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) {
186                 output->printf(output, "  invalid frame pointer %p\n",
187                                 tail);
188                 return NULL;
189         }
190         if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) {
191                 output->printf(output,
192                         "  failed to copy frame pointer %p\n", tail);
193                 return NULL;
194         }
195
196         output->printf(output, "  %p\n", buftail[0].lr);
197
198         /* frame pointers should strictly progress back up the stack
199          * (towards higher addresses) */
200         if (tail >= buftail[0].fp)
201                 return NULL;
202
203         return buftail[0].fp-1;
204 }
205
206 void fiq_debugger_dump_stacktrace(struct fiq_debugger_output *output,
207                 const struct pt_regs *regs, unsigned int depth, void *ssp)
208 {
209         struct frame_tail *tail;
210         struct thread_info *real_thread_info = THREAD_INFO(ssp);
211         struct stacktrace_state sts;
212
213         sts.depth = depth;
214         sts.output = output;
215         *current_thread_info() = *real_thread_info;
216
217         if (!current)
218                 output->printf(output, "current NULL\n");
219         else
220                 output->printf(output, "pid: %d  comm: %s\n",
221                         current->pid, current->comm);
222         fiq_debugger_dump_regs(output, regs);
223
224         if (!user_mode(regs)) {
225                 struct stackframe frame;
226                 frame.fp = regs->ARM_fp;
227                 frame.sp = regs->ARM_sp;
228                 frame.lr = regs->ARM_lr;
229                 frame.pc = regs->ARM_pc;
230                 output->printf(output,
231                         "  pc: %p (%pF), lr %p (%pF), sp %p, fp %p\n",
232                         regs->ARM_pc, regs->ARM_pc, regs->ARM_lr, regs->ARM_lr,
233                         regs->ARM_sp, regs->ARM_fp);
234                 walk_stackframe(&frame, report_trace, &sts);
235                 return;
236         }
237
238         tail = ((struct frame_tail *) regs->ARM_fp) - 1;
239         while (depth-- && tail && !((unsigned long) tail & 3))
240                 tail = user_backtrace(output, tail);
241 }