Pull thermal into release branch
[linux-drm-fsl-dcu.git] / arch / parisc / kernel / unwind.c
1 /*
2  * Kernel unwinding support
3  *
4  * (c) 2002-2004 Randolph Chung <tausq@debian.org>
5  *
6  * Derived partially from the IA64 implementation. The PA-RISC
7  * Runtime Architecture Document is also a useful reference to
8  * understand what is happening here
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <linux/slab.h>
15 #include <linux/kallsyms.h>
16
17 #include <asm/uaccess.h>
18 #include <asm/assembly.h>
19
20 #include <asm/unwind.h>
21
22 /* #define DEBUG 1 */
23 #ifdef DEBUG
24 #define dbg(x...) printk(x)
25 #else
26 #define dbg(x...)
27 #endif
28
29 extern struct unwind_table_entry __start___unwind[];
30 extern struct unwind_table_entry __stop___unwind[];
31
32 static spinlock_t unwind_lock;
33 /*
34  * the kernel unwind block is not dynamically allocated so that
35  * we can call unwind_init as early in the bootup process as 
36  * possible (before the slab allocator is initialized)
37  */
38 static struct unwind_table kernel_unwind_table __read_mostly;
39 static LIST_HEAD(unwind_tables);
40
41 static inline const struct unwind_table_entry *
42 find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
43 {
44         const struct unwind_table_entry *e = NULL;
45         unsigned long lo, hi, mid;
46
47         lo = 0; 
48         hi = table->length - 1; 
49         
50         while (lo <= hi) {
51                 mid = (hi - lo) / 2 + lo;
52                 e = &table->table[mid];
53                 if (addr < e->region_start)
54                         hi = mid - 1;
55                 else if (addr > e->region_end)
56                         lo = mid + 1;
57                 else
58                         return e;
59         }
60
61         return NULL;
62 }
63
64 static const struct unwind_table_entry *
65 find_unwind_entry(unsigned long addr)
66 {
67         struct unwind_table *table;
68         const struct unwind_table_entry *e = NULL;
69
70         if (addr >= kernel_unwind_table.start && 
71             addr <= kernel_unwind_table.end)
72                 e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
73         else 
74                 list_for_each_entry(table, &unwind_tables, list) {
75                         if (addr >= table->start && 
76                             addr <= table->end)
77                                 e = find_unwind_entry_in_table(table, addr);
78                         if (e)
79                                 break;
80                 }
81
82         return e;
83 }
84
85 static void
86 unwind_table_init(struct unwind_table *table, const char *name,
87                   unsigned long base_addr, unsigned long gp,
88                   void *table_start, void *table_end)
89 {
90         struct unwind_table_entry *start = table_start;
91         struct unwind_table_entry *end = 
92                 (struct unwind_table_entry *)table_end - 1;
93
94         table->name = name;
95         table->base_addr = base_addr;
96         table->gp = gp;
97         table->start = base_addr + start->region_start;
98         table->end = base_addr + end->region_end;
99         table->table = (struct unwind_table_entry *)table_start;
100         table->length = end - start + 1;
101         INIT_LIST_HEAD(&table->list);
102
103         for (; start <= end; start++) {
104                 if (start < end && 
105                     start->region_end > (start+1)->region_start) {
106                         printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
107                 }
108
109                 start->region_start += base_addr;
110                 start->region_end += base_addr;
111         }
112 }
113
114 static void
115 unwind_table_sort(struct unwind_table_entry *start,
116                   struct unwind_table_entry *finish)
117 {
118         struct unwind_table_entry el, *p, *q;
119
120         for (p = start + 1; p < finish; ++p) {
121                 if (p[0].region_start < p[-1].region_start) {
122                         el = *p;
123                         q = p;
124                         do {
125                                 q[0] = q[-1];
126                                 --q;
127                         } while (q > start && 
128                                  el.region_start < q[-1].region_start);
129                         *q = el;
130                 }
131         }
132 }
133
134 struct unwind_table *
135 unwind_table_add(const char *name, unsigned long base_addr, 
136                  unsigned long gp,
137                  void *start, void *end)
138 {
139         struct unwind_table *table;
140         unsigned long flags;
141         struct unwind_table_entry *s = (struct unwind_table_entry *)start;
142         struct unwind_table_entry *e = (struct unwind_table_entry *)end;
143
144         unwind_table_sort(s, e);
145
146         table = kmalloc(sizeof(struct unwind_table), GFP_USER);
147         if (table == NULL)
148                 return NULL;
149         unwind_table_init(table, name, base_addr, gp, start, end);
150         spin_lock_irqsave(&unwind_lock, flags);
151         list_add_tail(&table->list, &unwind_tables);
152         spin_unlock_irqrestore(&unwind_lock, flags);
153
154         return table;
155 }
156
157 void unwind_table_remove(struct unwind_table *table)
158 {
159         unsigned long flags;
160
161         spin_lock_irqsave(&unwind_lock, flags);
162         list_del(&table->list);
163         spin_unlock_irqrestore(&unwind_lock, flags);
164
165         kfree(table);
166 }
167
168 /* Called from setup_arch to import the kernel unwind info */
169 static int unwind_init(void)
170 {
171         long start, stop;
172         register unsigned long gp __asm__ ("r27");
173
174         start = (long)&__start___unwind[0];
175         stop = (long)&__stop___unwind[0];
176
177         spin_lock_init(&unwind_lock);
178
179         printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", 
180             start, stop,
181             (stop - start) / sizeof(struct unwind_table_entry));
182
183         unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
184                           gp, 
185                           &__start___unwind[0], &__stop___unwind[0]);
186 #if 0
187         {
188                 int i;
189                 for (i = 0; i < 10; i++)
190                 {
191                         printk("region 0x%x-0x%x\n", 
192                                 __start___unwind[i].region_start, 
193                                 __start___unwind[i].region_end);
194                 }
195         }
196 #endif
197         return 0;
198 }
199
200 static void unwind_frame_regs(struct unwind_frame_info *info)
201 {
202         const struct unwind_table_entry *e;
203         unsigned long npc;
204         unsigned int insn;
205         long frame_size = 0;
206         int looking_for_rp, rpoffset = 0;
207
208         e = find_unwind_entry(info->ip);
209         if (e == NULL) {
210                 unsigned long sp;
211                 extern char _stext[], _etext[];
212
213                 dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
214
215 #ifdef CONFIG_KALLSYMS
216                 /* Handle some frequent special cases.... */
217                 {
218                         char symname[KSYM_NAME_LEN+1];
219
220                         kallsyms_lookup(info->ip, NULL, NULL, NULL, symname);
221
222                         dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
223
224                         if (strcmp(symname, "_switch_to_ret") == 0) {
225                                 info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
226                                 info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
227                                 dbg("_switch_to_ret @ %lx - setting "
228                                     "prev_sp=%lx prev_ip=%lx\n", 
229                                     info->ip, info->prev_sp, 
230                                     info->prev_ip);
231                                 return;
232                         } else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
233                                    strcmp(symname, "syscall_exit") == 0) {
234                                 info->prev_ip = info->prev_sp = 0;
235                                 return;
236                         }
237                 }
238 #endif
239
240                 /* Since we are doing the unwinding blind, we don't know if
241                    we are adjusting the stack correctly or extracting the rp
242                    correctly. The rp is checked to see if it belongs to the
243                    kernel text section, if not we assume we don't have a 
244                    correct stack frame and we continue to unwind the stack.
245                    This is not quite correct, and will fail for loadable
246                    modules. */
247                 sp = info->sp & ~63;
248                 do {
249                         unsigned long tmp;
250
251                         info->prev_sp = sp - 64;
252                         info->prev_ip = 0;
253                         if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
254                                 break;
255                         info->prev_ip = tmp;
256                         sp = info->prev_sp;
257                 } while (info->prev_ip < (unsigned long)_stext ||
258                          info->prev_ip > (unsigned long)_etext);
259
260                 info->rp = 0;
261
262                 dbg("analyzing func @ %lx with no unwind info, setting "
263                     "prev_sp=%lx prev_ip=%lx\n", info->ip, 
264                     info->prev_sp, info->prev_ip);
265         } else {
266                 dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
267                     "Save_RP = %d, Millicode = %d size = %u\n", 
268                     e->region_start, e->region_end, e->Save_SP, e->Save_RP, 
269                     e->Millicode, e->Total_frame_size);
270
271                 looking_for_rp = e->Save_RP;
272
273                 for (npc = e->region_start; 
274                      (frame_size < (e->Total_frame_size << 3) || 
275                       looking_for_rp) && 
276                      npc < info->ip; 
277                      npc += 4) {
278
279                         insn = *(unsigned int *)npc;
280
281                         if ((insn & 0xffffc000) == 0x37de0000 ||
282                             (insn & 0xffe00000) == 0x6fc00000) {
283                                 /* ldo X(sp), sp, or stwm X,D(sp) */
284                                 frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
285                                         ((insn & 0x3fff) >> 1);
286                                 dbg("analyzing func @ %lx, insn=%08x @ "
287                                     "%lx, frame_size = %ld\n", info->ip,
288                                     insn, npc, frame_size);
289                         } else if ((insn & 0xffe00008) == 0x73c00008) {
290                                 /* std,ma X,D(sp) */
291                                 frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
292                                         (((insn >> 4) & 0x3ff) << 3);
293                                 dbg("analyzing func @ %lx, insn=%08x @ "
294                                     "%lx, frame_size = %ld\n", info->ip,
295                                     insn, npc, frame_size);
296                         } else if (insn == 0x6bc23fd9) { 
297                                 /* stw rp,-20(sp) */
298                                 rpoffset = 20;
299                                 looking_for_rp = 0;
300                                 dbg("analyzing func @ %lx, insn=stw rp,"
301                                     "-20(sp) @ %lx\n", info->ip, npc);
302                         } else if (insn == 0x0fc212c1) {
303                                 /* std rp,-16(sr0,sp) */
304                                 rpoffset = 16;
305                                 looking_for_rp = 0;
306                                 dbg("analyzing func @ %lx, insn=std rp,"
307                                     "-16(sp) @ %lx\n", info->ip, npc);
308                         }
309                 }
310
311                 info->prev_sp = info->sp - frame_size;
312                 if (e->Millicode)
313                         info->rp = info->r31;
314                 else if (rpoffset)
315                         info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
316                 info->prev_ip = info->rp;
317                 info->rp = 0;
318
319                 dbg("analyzing func @ %lx, setting prev_sp=%lx "
320                     "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
321                     info->prev_ip, npc);
322         }
323 }
324
325 void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
326                        struct pt_regs *regs)
327 {
328         memset(info, 0, sizeof(struct unwind_frame_info));
329         info->t = t;
330         info->sp = regs->gr[30];
331         info->ip = regs->iaoq[0];
332         info->rp = regs->gr[2];
333         info->r31 = regs->gr[31];
334
335         dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
336             t ? (int)t->pid : -1, info->sp, info->ip);
337 }
338
339 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
340 {
341         struct pt_regs *r = &t->thread.regs;
342         struct pt_regs *r2;
343
344         r2 = kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
345         if (!r2)
346                 return;
347         *r2 = *r;
348         r2->gr[30] = r->ksp;
349         r2->iaoq[0] = r->kpc;
350         unwind_frame_init(info, t, r2);
351         kfree(r2);
352 }
353
354 void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
355 {
356         unwind_frame_init(info, current, regs);
357 }
358
359 int unwind_once(struct unwind_frame_info *next_frame)
360 {
361         unwind_frame_regs(next_frame);
362
363         if (next_frame->prev_sp == 0 ||
364             next_frame->prev_ip == 0)
365                 return -1;
366
367         next_frame->sp = next_frame->prev_sp;
368         next_frame->ip = next_frame->prev_ip;
369         next_frame->prev_sp = 0;
370         next_frame->prev_ip = 0;
371
372         dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
373             next_frame->t ? (int)next_frame->t->pid : -1, 
374             next_frame->sp, next_frame->ip);
375
376         return 0;
377 }
378
379 int unwind_to_user(struct unwind_frame_info *info)
380 {
381         int ret;
382         
383         do {
384                 ret = unwind_once(info);
385         } while (!ret && !(info->ip & 3));
386
387         return ret;
388 }
389
390 module_init(unwind_init);