Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/frv/kernel/traps.c
10817 views
1
/* traps.c: high-level exception handler for FR-V
2
*
3
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
4
* Written by David Howells ([email protected])
5
*
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version
9
* 2 of the License, or (at your option) any later version.
10
*/
11
12
#include <linux/sched.h>
13
#include <linux/signal.h>
14
#include <linux/kernel.h>
15
#include <linux/mm.h>
16
#include <linux/types.h>
17
#include <linux/user.h>
18
#include <linux/string.h>
19
#include <linux/linkage.h>
20
#include <linux/init.h>
21
#include <linux/module.h>
22
23
#include <asm/asm-offsets.h>
24
#include <asm/setup.h>
25
#include <asm/fpu.h>
26
#include <asm/system.h>
27
#include <asm/uaccess.h>
28
#include <asm/pgtable.h>
29
#include <asm/siginfo.h>
30
#include <asm/unaligned.h>
31
32
void show_backtrace(struct pt_regs *, unsigned long);
33
34
extern asmlinkage void __break_hijack_kernel_event(void);
35
36
/*****************************************************************************/
37
/*
38
* instruction access error
39
*/
40
asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
41
{
42
siginfo_t info;
43
44
die_if_kernel("-- Insn Access Error --\n"
45
"EPCR0 : %08lx\n"
46
"ESR0 : %08lx\n",
47
epcr0, esr0);
48
49
info.si_signo = SIGSEGV;
50
info.si_code = SEGV_ACCERR;
51
info.si_errno = 0;
52
info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
53
54
force_sig_info(info.si_signo, &info, current);
55
} /* end insn_access_error() */
56
57
/*****************************************************************************/
58
/*
59
* handler for:
60
* - illegal instruction
61
* - privileged instruction
62
* - unsupported trap
63
* - debug exceptions
64
*/
65
asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, unsigned long esr0)
66
{
67
siginfo_t info;
68
69
die_if_kernel("-- Illegal Instruction --\n"
70
"EPCR0 : %08lx\n"
71
"ESR0 : %08lx\n"
72
"ESFR1 : %08lx\n",
73
epcr0, esr0, esfr1);
74
75
info.si_errno = 0;
76
info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
77
78
switch (__frame->tbr & TBR_TT) {
79
case TBR_TT_ILLEGAL_INSTR:
80
info.si_signo = SIGILL;
81
info.si_code = ILL_ILLOPC;
82
break;
83
case TBR_TT_PRIV_INSTR:
84
info.si_signo = SIGILL;
85
info.si_code = ILL_PRVOPC;
86
break;
87
case TBR_TT_TRAP2 ... TBR_TT_TRAP126:
88
info.si_signo = SIGILL;
89
info.si_code = ILL_ILLTRP;
90
break;
91
/* GDB uses "tira gr0, #1" as a breakpoint instruction. */
92
case TBR_TT_TRAP1:
93
case TBR_TT_BREAK:
94
info.si_signo = SIGTRAP;
95
info.si_code =
96
(__frame->__status & REG__STATUS_STEPPED) ? TRAP_TRACE : TRAP_BRKPT;
97
break;
98
}
99
100
force_sig_info(info.si_signo, &info, current);
101
} /* end illegal_instruction() */
102
103
/*****************************************************************************/
104
/*
105
* handle atomic operations with errors
106
* - arguments in gr8, gr9, gr10
107
* - original memory value placed in gr5
108
* - replacement memory value placed in gr9
109
*/
110
asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
111
unsigned long esr0)
112
{
113
static DEFINE_SPINLOCK(atomic_op_lock);
114
unsigned long x, y, z;
115
unsigned long __user *p;
116
mm_segment_t oldfs;
117
siginfo_t info;
118
int ret;
119
120
y = 0;
121
z = 0;
122
123
oldfs = get_fs();
124
if (!user_mode(__frame))
125
set_fs(KERNEL_DS);
126
127
switch (__frame->tbr & TBR_TT) {
128
/* TIRA gr0,#120
129
* u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
130
*/
131
case TBR_TT_ATOMIC_CMPXCHG32:
132
p = (unsigned long __user *) __frame->gr8;
133
x = __frame->gr9;
134
y = __frame->gr10;
135
136
for (;;) {
137
ret = get_user(z, p);
138
if (ret < 0)
139
goto error;
140
141
if (z != x)
142
goto done;
143
144
spin_lock_irq(&atomic_op_lock);
145
146
if (__get_user(z, p) == 0) {
147
if (z != x)
148
goto done2;
149
150
if (__put_user(y, p) == 0)
151
goto done2;
152
goto error2;
153
}
154
155
spin_unlock_irq(&atomic_op_lock);
156
}
157
158
/* TIRA gr0,#121
159
* u32 __atomic_kernel_xchg32(void *v, u32 new)
160
*/
161
case TBR_TT_ATOMIC_XCHG32:
162
p = (unsigned long __user *) __frame->gr8;
163
y = __frame->gr9;
164
165
for (;;) {
166
ret = get_user(z, p);
167
if (ret < 0)
168
goto error;
169
170
spin_lock_irq(&atomic_op_lock);
171
172
if (__get_user(z, p) == 0) {
173
if (__put_user(y, p) == 0)
174
goto done2;
175
goto error2;
176
}
177
178
spin_unlock_irq(&atomic_op_lock);
179
}
180
181
/* TIRA gr0,#122
182
* ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
183
*/
184
case TBR_TT_ATOMIC_XOR:
185
p = (unsigned long __user *) __frame->gr8;
186
x = __frame->gr9;
187
188
for (;;) {
189
ret = get_user(z, p);
190
if (ret < 0)
191
goto error;
192
193
spin_lock_irq(&atomic_op_lock);
194
195
if (__get_user(z, p) == 0) {
196
y = x ^ z;
197
if (__put_user(y, p) == 0)
198
goto done2;
199
goto error2;
200
}
201
202
spin_unlock_irq(&atomic_op_lock);
203
}
204
205
/* TIRA gr0,#123
206
* ulong __atomic_kernel_OR_return(ulong i, ulong *v)
207
*/
208
case TBR_TT_ATOMIC_OR:
209
p = (unsigned long __user *) __frame->gr8;
210
x = __frame->gr9;
211
212
for (;;) {
213
ret = get_user(z, p);
214
if (ret < 0)
215
goto error;
216
217
spin_lock_irq(&atomic_op_lock);
218
219
if (__get_user(z, p) == 0) {
220
y = x ^ z;
221
if (__put_user(y, p) == 0)
222
goto done2;
223
goto error2;
224
}
225
226
spin_unlock_irq(&atomic_op_lock);
227
}
228
229
/* TIRA gr0,#124
230
* ulong __atomic_kernel_AND_return(ulong i, ulong *v)
231
*/
232
case TBR_TT_ATOMIC_AND:
233
p = (unsigned long __user *) __frame->gr8;
234
x = __frame->gr9;
235
236
for (;;) {
237
ret = get_user(z, p);
238
if (ret < 0)
239
goto error;
240
241
spin_lock_irq(&atomic_op_lock);
242
243
if (__get_user(z, p) == 0) {
244
y = x & z;
245
if (__put_user(y, p) == 0)
246
goto done2;
247
goto error2;
248
}
249
250
spin_unlock_irq(&atomic_op_lock);
251
}
252
253
/* TIRA gr0,#125
254
* int __atomic_user_sub_return(atomic_t *v, int i)
255
*/
256
case TBR_TT_ATOMIC_SUB:
257
p = (unsigned long __user *) __frame->gr8;
258
x = __frame->gr9;
259
260
for (;;) {
261
ret = get_user(z, p);
262
if (ret < 0)
263
goto error;
264
265
spin_lock_irq(&atomic_op_lock);
266
267
if (__get_user(z, p) == 0) {
268
y = z - x;
269
if (__put_user(y, p) == 0)
270
goto done2;
271
goto error2;
272
}
273
274
spin_unlock_irq(&atomic_op_lock);
275
}
276
277
/* TIRA gr0,#126
278
* int __atomic_user_add_return(atomic_t *v, int i)
279
*/
280
case TBR_TT_ATOMIC_ADD:
281
p = (unsigned long __user *) __frame->gr8;
282
x = __frame->gr9;
283
284
for (;;) {
285
ret = get_user(z, p);
286
if (ret < 0)
287
goto error;
288
289
spin_lock_irq(&atomic_op_lock);
290
291
if (__get_user(z, p) == 0) {
292
y = z + x;
293
if (__put_user(y, p) == 0)
294
goto done2;
295
goto error2;
296
}
297
298
spin_unlock_irq(&atomic_op_lock);
299
}
300
301
default:
302
BUG();
303
}
304
305
done2:
306
spin_unlock_irq(&atomic_op_lock);
307
done:
308
if (!user_mode(__frame))
309
set_fs(oldfs);
310
__frame->gr5 = z;
311
__frame->gr9 = y;
312
return;
313
314
error2:
315
spin_unlock_irq(&atomic_op_lock);
316
error:
317
if (!user_mode(__frame))
318
set_fs(oldfs);
319
__frame->pc -= 4;
320
321
die_if_kernel("-- Atomic Op Error --\n");
322
323
info.si_signo = SIGSEGV;
324
info.si_code = SEGV_ACCERR;
325
info.si_errno = 0;
326
info.si_addr = (void __user *) __frame->pc;
327
328
force_sig_info(info.si_signo, &info, current);
329
}
330
331
/*****************************************************************************/
332
/*
333
*
334
*/
335
asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
336
{
337
siginfo_t info;
338
339
die_if_kernel("-- Media Exception --\n"
340
"MSR0 : %08lx\n"
341
"MSR1 : %08lx\n",
342
msr0, msr1);
343
344
info.si_signo = SIGFPE;
345
info.si_code = FPE_MDAOVF;
346
info.si_errno = 0;
347
info.si_addr = (void __user *) __frame->pc;
348
349
force_sig_info(info.si_signo, &info, current);
350
} /* end media_exception() */
351
352
/*****************************************************************************/
353
/*
354
* instruction or data access exception
355
*/
356
asmlinkage void memory_access_exception(unsigned long esr0,
357
unsigned long ear0,
358
unsigned long epcr0)
359
{
360
siginfo_t info;
361
362
#ifdef CONFIG_MMU
363
unsigned long fixup;
364
365
fixup = search_exception_table(__frame->pc);
366
if (fixup) {
367
__frame->pc = fixup;
368
return;
369
}
370
#endif
371
372
die_if_kernel("-- Memory Access Exception --\n"
373
"ESR0 : %08lx\n"
374
"EAR0 : %08lx\n"
375
"EPCR0 : %08lx\n",
376
esr0, ear0, epcr0);
377
378
info.si_signo = SIGSEGV;
379
info.si_code = SEGV_ACCERR;
380
info.si_errno = 0;
381
info.si_addr = NULL;
382
383
if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
384
info.si_addr = (void __user *) ear0;
385
386
force_sig_info(info.si_signo, &info, current);
387
388
} /* end memory_access_exception() */
389
390
/*****************************************************************************/
391
/*
392
* data access error
393
* - double-word data load from CPU control area (0xFExxxxxx)
394
* - read performed on inactive or self-refreshing SDRAM
395
* - error notification from slave device
396
* - misaligned address
397
* - access to out of bounds memory region
398
* - user mode accessing privileged memory region
399
* - write to R/O memory region
400
*/
401
asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsigned long ear15)
402
{
403
siginfo_t info;
404
405
die_if_kernel("-- Data Access Error --\n"
406
"ESR15 : %08lx\n"
407
"EAR15 : %08lx\n",
408
esr15, ear15);
409
410
info.si_signo = SIGSEGV;
411
info.si_code = SEGV_ACCERR;
412
info.si_errno = 0;
413
info.si_addr = (void __user *)
414
(((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
415
416
force_sig_info(info.si_signo, &info, current);
417
} /* end data_access_error() */
418
419
/*****************************************************************************/
420
/*
421
* data store error - should only happen if accessing inactive or self-refreshing SDRAM
422
*/
423
asmlinkage void data_store_error(unsigned long esfr1, unsigned long esr15)
424
{
425
die_if_kernel("-- Data Store Error --\n"
426
"ESR15 : %08lx\n",
427
esr15);
428
BUG();
429
} /* end data_store_error() */
430
431
/*****************************************************************************/
432
/*
433
*
434
*/
435
asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsigned long isr)
436
{
437
siginfo_t info;
438
439
die_if_kernel("-- Division Exception --\n"
440
"ESR0 : %08lx\n"
441
"ISR : %08lx\n",
442
esr0, isr);
443
444
info.si_signo = SIGFPE;
445
info.si_code = FPE_INTDIV;
446
info.si_errno = 0;
447
info.si_addr = (void __user *) __frame->pc;
448
449
force_sig_info(info.si_signo, &info, current);
450
} /* end division_exception() */
451
452
/*****************************************************************************/
453
/*
454
*
455
*/
456
asmlinkage void compound_exception(unsigned long esfr1,
457
unsigned long esr0, unsigned long esr14, unsigned long esr15,
458
unsigned long msr0, unsigned long msr1)
459
{
460
die_if_kernel("-- Compound Exception --\n"
461
"ESR0 : %08lx\n"
462
"ESR15 : %08lx\n"
463
"ESR15 : %08lx\n"
464
"MSR0 : %08lx\n"
465
"MSR1 : %08lx\n",
466
esr0, esr14, esr15, msr0, msr1);
467
BUG();
468
} /* end compound_exception() */
469
470
/*****************************************************************************/
471
/*
472
* The architecture-independent backtrace generator
473
*/
474
void dump_stack(void)
475
{
476
show_stack(NULL, NULL);
477
}
478
479
EXPORT_SYMBOL(dump_stack);
480
481
void show_stack(struct task_struct *task, unsigned long *sp)
482
{
483
}
484
485
void show_trace_task(struct task_struct *tsk)
486
{
487
printk("CONTEXT: stack=0x%lx frame=0x%p LR=0x%lx RET=0x%lx\n",
488
tsk->thread.sp, tsk->thread.frame, tsk->thread.lr, tsk->thread.sched_lr);
489
}
490
491
static const char *regnames[] = {
492
"PSR ", "ISR ", "CCR ", "CCCR",
493
"LR ", "LCR ", "PC ", "_stt",
494
"sys ", "GR8*", "GNE0", "GNE1",
495
"IACH", "IACL",
496
"TBR ", "SP ", "FP ", "GR3 ",
497
"GR4 ", "GR5 ", "GR6 ", "GR7 ",
498
"GR8 ", "GR9 ", "GR10", "GR11",
499
"GR12", "GR13", "GR14", "GR15",
500
"GR16", "GR17", "GR18", "GR19",
501
"GR20", "GR21", "GR22", "GR23",
502
"GR24", "GR25", "GR26", "GR27",
503
"EFRM", "CURR", "GR30", "BFRM"
504
};
505
506
void show_regs(struct pt_regs *regs)
507
{
508
unsigned long *reg;
509
int loop;
510
511
printk("\n");
512
513
printk("Frame: @%08lx [%s]\n",
514
(unsigned long) regs,
515
regs->psr & PSR_S ? "kernel" : "user");
516
517
reg = (unsigned long *) regs;
518
for (loop = 0; loop < NR_PT_REGS; loop++) {
519
printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
520
521
if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
522
printk("\n");
523
else
524
printk(" | ");
525
}
526
527
printk("Process %s (pid: %d)\n", current->comm, current->pid);
528
}
529
530
void die_if_kernel(const char *str, ...)
531
{
532
char buffer[256];
533
va_list va;
534
535
if (user_mode(__frame))
536
return;
537
538
va_start(va, str);
539
vsprintf(buffer, str, va);
540
va_end(va);
541
542
console_verbose();
543
printk("\n===================================\n");
544
printk("%s\n", buffer);
545
show_backtrace(__frame, 0);
546
547
__break_hijack_kernel_event();
548
do_exit(SIGSEGV);
549
}
550
551
/*****************************************************************************/
552
/*
553
* dump the contents of an exception frame
554
*/
555
static void show_backtrace_regs(struct pt_regs *frame)
556
{
557
unsigned long *reg;
558
int loop;
559
560
/* print the registers for this frame */
561
printk("<-- %s Frame: @%p -->\n",
562
frame->psr & PSR_S ? "Kernel Mode" : "User Mode",
563
frame);
564
565
reg = (unsigned long *) frame;
566
for (loop = 0; loop < NR_PT_REGS; loop++) {
567
printk("%s %08lx", regnames[loop + 0], reg[loop + 0]);
568
569
if (loop == NR_PT_REGS - 1 || loop % 5 == 4)
570
printk("\n");
571
else
572
printk(" | ");
573
}
574
575
printk("--------\n");
576
} /* end show_backtrace_regs() */
577
578
/*****************************************************************************/
579
/*
580
* generate a backtrace of the kernel stack
581
*/
582
void show_backtrace(struct pt_regs *frame, unsigned long sp)
583
{
584
struct pt_regs *frame0;
585
unsigned long tos = 0, stop = 0, base;
586
int format;
587
588
base = ((((unsigned long) frame) + 8191) & ~8191) - sizeof(struct user_context);
589
frame0 = (struct pt_regs *) base;
590
591
if (sp) {
592
tos = sp;
593
stop = (unsigned long) frame;
594
}
595
596
printk("\nProcess %s (pid: %d)\n\n", current->comm, current->pid);
597
598
for (;;) {
599
/* dump stack segment between frames */
600
//printk("%08lx -> %08lx\n", tos, stop);
601
format = 0;
602
while (tos < stop) {
603
if (format == 0)
604
printk(" %04lx :", tos & 0xffff);
605
606
printk(" %08lx", *(unsigned long *) tos);
607
608
tos += 4;
609
format++;
610
if (format == 8) {
611
printk("\n");
612
format = 0;
613
}
614
}
615
616
if (format > 0)
617
printk("\n");
618
619
/* dump frame 0 outside of the loop */
620
if (frame == frame0)
621
break;
622
623
tos = frame->sp;
624
if (((unsigned long) frame) + sizeof(*frame) != tos) {
625
printk("-- TOS %08lx does not follow frame %p --\n",
626
tos, frame);
627
break;
628
}
629
630
show_backtrace_regs(frame);
631
632
/* dump the stack between this frame and the next */
633
stop = (unsigned long) frame->next_frame;
634
if (stop != base &&
635
(stop < tos ||
636
stop > base ||
637
(stop < base && stop + sizeof(*frame) > base) ||
638
stop & 3)) {
639
printk("-- next_frame %08lx is invalid (range %08lx-%08lx) --\n",
640
stop, tos, base);
641
break;
642
}
643
644
/* move to next frame */
645
frame = frame->next_frame;
646
}
647
648
/* we can always dump frame 0, even if the rest of the stack is corrupt */
649
show_backtrace_regs(frame0);
650
651
} /* end show_backtrace() */
652
653
/*****************************************************************************/
654
/*
655
* initialise traps
656
*/
657
void __init trap_init (void)
658
{
659
} /* end trap_init() */
660
661