v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / arch / arm / mm / fault-armv.c
1 /*
2  *  linux/arch/arm/mm/fault-armv.c
3  *
4  *  Copyright (C) 1995  Linus Torvalds
5  *  Modifications for ARM processor (c) 1995-2001 Russell King
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/config.h>
12 #include <linux/signal.h>
13 #include <linux/sched.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/string.h>
17 #include <linux/types.h>
18 #include <linux/ptrace.h>
19 #include <linux/mman.h>
20 #include <linux/mm.h>
21 #include <linux/interrupt.h>
22 #include <linux/proc_fs.h>
23 #include <linux/init.h>
24
25 #include <asm/system.h>
26 #include <asm/uaccess.h>
27 #include <asm/pgalloc.h>
28 #include <asm/pgtable.h>
29 #include <asm/unaligned.h>
30
31 extern void die_if_kernel(const char *str, struct pt_regs *regs, int err);
32 extern void show_pte(struct mm_struct *mm, unsigned long addr);
33 extern int do_page_fault(unsigned long addr, int error_code,
34                          struct pt_regs *regs);
35 extern int do_translation_fault(unsigned long addr, int error_code,
36                                 struct pt_regs *regs);
37 extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
38                         unsigned long addr, int error_code,
39                         struct pt_regs *regs);
40
41 #ifdef CONFIG_ALIGNMENT_TRAP
42 /*
43  * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
44  * /proc/sys/debug/alignment, modified and integrated into
45  * Linux 2.1 by Russell King
46  *
47  * Speed optimisations and better fault handling by Russell King.
48  *
49  * *** NOTE ***
50  * This code is not portable to processors with late data abort handling.
51  */
52 #define CODING_BITS(i)  (i & 0x0e000000)
53
54 #define LDST_I_BIT(i)   (i & (1 << 26))         /* Immediate constant   */
55 #define LDST_P_BIT(i)   (i & (1 << 24))         /* Preindex             */
56 #define LDST_U_BIT(i)   (i & (1 << 23))         /* Add offset           */
57 #define LDST_W_BIT(i)   (i & (1 << 21))         /* Writeback            */
58 #define LDST_L_BIT(i)   (i & (1 << 20))         /* Load                 */
59
60 #define LDST_P_EQ_U(i)  ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
61
62 #define LDSTH_I_BIT(i)  (i & (1 << 22))         /* half-word immed      */
63 #define LDM_S_BIT(i)    (i & (1 << 22))         /* write CPSR from SPSR */
64
65 #define RN_BITS(i)      ((i >> 16) & 15)        /* Rn                   */
66 #define RD_BITS(i)      ((i >> 12) & 15)        /* Rd                   */
67 #define RM_BITS(i)      (i & 15)                /* Rm                   */
68
69 #define REGMASK_BITS(i) (i & 0xffff)
70 #define OFFSET_BITS(i)  (i & 0x0fff)
71
72 #define IS_SHIFT(i)     (i & 0x0ff0)
73 #define SHIFT_BITS(i)   ((i >> 7) & 0x1f)
74 #define SHIFT_TYPE(i)   (i & 0x60)
75 #define SHIFT_LSL       0x00
76 #define SHIFT_LSR       0x20
77 #define SHIFT_ASR       0x40
78 #define SHIFT_RORRRX    0x60
79
80 static unsigned long ai_user;
81 static unsigned long ai_sys;
82 static unsigned long ai_skipped;
83 static unsigned long ai_half;
84 static unsigned long ai_word;
85 static unsigned long ai_multi;
86
87 #ifdef CONFIG_SYSCTL
88 static int proc_alignment_read(char *page, char **start, off_t off,
89                                int count, int *eof, void *data)
90 {
91         char *p = page;
92         int len;
93
94         p += sprintf(p, "User:\t\t%li\n", ai_user);
95         p += sprintf(p, "System:\t\t%li\n", ai_sys);
96         p += sprintf(p, "Skipped:\t%li\n", ai_skipped);
97         p += sprintf(p, "Half:\t\t%li\n", ai_half);
98         p += sprintf(p, "Word:\t\t%li\n", ai_word);
99         p += sprintf(p, "Multi:\t\t%li\n", ai_multi);
100
101         len = (p - page) - off;
102         if (len < 0)
103                 len = 0;
104
105         *eof = (len <= count) ? 1 : 0;
106         *start = page + off;
107
108         return len;
109 }
110
111 /*
112  * This needs to be done after sysctl_init, otherwise sys/
113  * will be overwritten.
114  */
115 static int __init alignment_init(void)
116 {
117         create_proc_read_entry("sys/debug/alignment", 0, NULL,
118                                 proc_alignment_read, NULL);
119         return 0;
120 }
121
122 __initcall(alignment_init);
123 #endif /* CONFIG_SYSCTL */
124
125 union offset_union {
126         unsigned long un;
127           signed long sn;
128 };
129
130 #define TYPE_ERROR      0
131 #define TYPE_FAULT      1
132 #define TYPE_LDST       2
133 #define TYPE_DONE       3
134
135 #define get8_unaligned_check(val,addr,err)              \
136         __asm__(                                        \
137         "1:     ldrb    %1, [%2], #1\n"                 \
138         "2:\n"                                          \
139         "       .section .fixup,\"ax\"\n"               \
140         "       .align  2\n"                            \
141         "3:     mov     %0, #1\n"                       \
142         "       b       2b\n"                           \
143         "       .previous\n"                            \
144         "       .section __ex_table,\"a\"\n"            \
145         "       .align  3\n"                            \
146         "       .long   1b, 3b\n"                       \
147         "       .previous\n"                            \
148         : "=r" (err), "=&r" (val), "=r" (addr)          \
149         : "0" (err), "2" (addr))
150
151 #define get8t_unaligned_check(val,addr,err)             \
152         __asm__(                                        \
153         "1:     ldrbt   %1, [%2], #1\n"                 \
154         "2:\n"                                          \
155         "       .section .fixup,\"ax\"\n"               \
156         "       .align  2\n"                            \
157         "3:     mov     %0, #1\n"                       \
158         "       b       2b\n"                           \
159         "       .previous\n"                            \
160         "       .section __ex_table,\"a\"\n"            \
161         "       .align  3\n"                            \
162         "       .long   1b, 3b\n"                       \
163         "       .previous\n"                            \
164         : "=r" (err), "=&r" (val), "=r" (addr)          \
165         : "0" (err), "2" (addr))
166
167 #define get16_unaligned_check(val,addr)                         \
168         do {                                                    \
169                 unsigned int err = 0, v, a = addr;              \
170                 get8_unaligned_check(val,a,err);                \
171                 get8_unaligned_check(v,a,err);                  \
172                 val |= v << 8;                                  \
173                 if (err)                                        \
174                         goto fault;                             \
175         } while (0)
176
177 #define put16_unaligned_check(val,addr)                         \
178         do {                                                    \
179                 unsigned int err = 0, v = val, a = addr;        \
180                 __asm__(                                        \
181                 "1:     strb    %1, [%2], #1\n"                 \
182                 "       mov     %1, %1, lsr #8\n"               \
183                 "2:     strb    %1, [%2]\n"                     \
184                 "3:\n"                                          \
185                 "       .section .fixup,\"ax\"\n"               \
186                 "       .align  2\n"                            \
187                 "4:     mov     %0, #1\n"                       \
188                 "       b       3b\n"                           \
189                 "       .previous\n"                            \
190                 "       .section __ex_table,\"a\"\n"            \
191                 "       .align  3\n"                            \
192                 "       .long   1b, 4b\n"                       \
193                 "       .long   2b, 4b\n"                       \
194                 "       .previous\n"                            \
195                 : "=r" (err), "=&r" (v), "=&r" (a)              \
196                 : "0" (err), "1" (v), "2" (a));                 \
197                 if (err)                                        \
198                         goto fault;                             \
199         } while (0)
200
201 #define __put32_unaligned_check(ins,val,addr)                   \
202         do {                                                    \
203                 unsigned int err = 0, v = val, a = addr;        \
204                 __asm__(                                        \
205                 "1:     "ins"   %1, [%2], #1\n"                 \
206                 "       mov     %1, %1, lsr #8\n"               \
207                 "2:     "ins"   %1, [%2], #1\n"                 \
208                 "       mov     %1, %1, lsr #8\n"               \
209                 "3:     "ins"   %1, [%2], #1\n"                 \
210                 "       mov     %1, %1, lsr #8\n"               \
211                 "4:     "ins"   %1, [%2]\n"                     \
212                 "5:\n"                                          \
213                 "       .section .fixup,\"ax\"\n"               \
214                 "       .align  2\n"                            \
215                 "6:     mov     %0, #1\n"                       \
216                 "       b       5b\n"                           \
217                 "       .previous\n"                            \
218                 "       .section __ex_table,\"a\"\n"            \
219                 "       .align  3\n"                            \
220                 "       .long   1b, 6b\n"                       \
221                 "       .long   2b, 6b\n"                       \
222                 "       .long   3b, 6b\n"                       \
223                 "       .long   4b, 6b\n"                       \
224                 "       .previous\n"                            \
225                 : "=r" (err), "=&r" (v), "=&r" (a)              \
226                 : "0" (err), "1" (v), "2" (a));                 \
227                 if (err)                                        \
228                         goto fault;                             \
229         } while (0)
230
231 #define get32_unaligned_check(val,addr)                         \
232         do {                                                    \
233                 unsigned int err = 0, v, a = addr;              \
234                 get8_unaligned_check(val,a,err);                \
235                 get8_unaligned_check(v,a,err);                  \
236                 val |= v << 8;                                  \
237                 get8_unaligned_check(v,a,err);                  \
238                 val |= v << 16;                                 \
239                 get8_unaligned_check(v,a,err);                  \
240                 val |= v << 24;                                 \
241                 if (err)                                        \
242                         goto fault;                             \
243         } while (0)
244
245 #define put32_unaligned_check(val,addr)  \
246         __put32_unaligned_check("strb", val, addr)
247
248 #define get32t_unaligned_check(val,addr)                        \
249         do {                                                    \
250                 unsigned int err = 0, v, a = addr;              \
251                 get8t_unaligned_check(val,a,err);               \
252                 get8t_unaligned_check(v,a,err);                 \
253                 val |= v << 8;                                  \
254                 get8t_unaligned_check(v,a,err);                 \
255                 val |= v << 16;                                 \
256                 get8t_unaligned_check(v,a,err);                 \
257                 val |= v << 24;                                 \
258                 if (err)                                        \
259                         goto fault;                             \
260         } while (0)
261
262 #define put32t_unaligned_check(val,addr) \
263         __put32_unaligned_check("strbt", val, addr)
264
265 static void
266 do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset)
267 {
268         if (!LDST_U_BIT(instr))
269                 offset.un = -offset.un;
270
271         if (!LDST_P_BIT(instr))
272                 addr += offset.un;
273
274         if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
275                 regs->uregs[RN_BITS(instr)] = addr;
276 }
277
278 static int
279 do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs)
280 {
281         unsigned int rd = RD_BITS(instr);
282
283         if ((instr & 0x01f00ff0) == 0x01000090)
284                 goto swp;
285
286         if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
287                 goto bad;
288
289         ai_half += 1;
290
291         if (LDST_L_BIT(instr)) {
292                 unsigned long val;
293                 get16_unaligned_check(val, addr);
294
295                 /* signed half-word? */
296                 if (instr & 0x40)
297                         val = (signed long)((signed short) val);
298
299                 regs->uregs[rd] = val;
300         } else
301                 put16_unaligned_check(regs->uregs[rd], addr);
302
303         return TYPE_LDST;
304
305 swp:
306         printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
307 bad:
308         return TYPE_ERROR;
309
310 fault:
311         return TYPE_FAULT;
312 }
313
314 static int
315 do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs)
316 {
317         unsigned int rd = RD_BITS(instr);
318
319         ai_word += 1;
320
321         if (!LDST_P_BIT(instr) && LDST_W_BIT(instr))
322                 goto trans;
323
324         if (LDST_L_BIT(instr))
325                 get32_unaligned_check(regs->uregs[rd], addr);
326         else
327                 put32_unaligned_check(regs->uregs[rd], addr);
328         return TYPE_LDST;
329
330 trans:
331         if (LDST_L_BIT(instr))
332                 get32t_unaligned_check(regs->uregs[rd], addr);
333         else
334                 put32t_unaligned_check(regs->uregs[rd], addr);
335         return TYPE_LDST;
336
337 fault:
338         return TYPE_FAULT;
339 }
340
341 /*
342  * LDM/STM alignment handler.
343  *
344  * There are 4 variants of this instruction:
345  *
346  * B = rn pointer before instruction, A = rn pointer after instruction
347  *              ------ increasing address ----->
348  *              |    | r0 | r1 | ... | rx |    |
349  * PU = 01             B                    A
350  * PU = 11        B                    A
351  * PU = 00        A                    B
352  * PU = 10             A                    B
353  */
354 static int
355 do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
356 {
357         unsigned int rd, rn, correction, nr_regs, regbits;
358         unsigned long eaddr, newaddr;
359
360         if (LDM_S_BIT(instr))
361                 goto bad;
362
363         correction = 4; /* processor implementation defined */
364         regs->ARM_pc += correction;
365
366         ai_multi += 1;
367
368         /* count the number of registers in the mask to be transferred */
369         for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
370                 nr_regs += 4;
371
372         rn = RN_BITS(instr);
373         newaddr = eaddr = regs->uregs[rn];
374
375         if (!LDST_U_BIT(instr))
376                 nr_regs = -nr_regs;
377         newaddr += nr_regs;
378         if (!LDST_U_BIT(instr))
379                 eaddr = newaddr;
380
381         if (LDST_P_EQ_U(instr)) /* U = P */
382                 eaddr += 4;
383
384         /*
385          * This is a "hint" - we already have eaddr worked out by the
386          * processor for us.
387          */
388         if (addr != eaddr)
389                 printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
390                         "addr = %08lx, eaddr = %08lx\n",
391                          instruction_pointer(regs), instr, addr, eaddr);
392
393         for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
394                 if (regbits & 1) {
395                         if (LDST_L_BIT(instr))
396                                 get32_unaligned_check(regs->uregs[rd], eaddr);
397                         else
398                                 put32_unaligned_check(regs->uregs[rd], eaddr);
399                         eaddr += 4;
400                 }
401
402         if (LDST_W_BIT(instr))
403                 regs->uregs[rn] = newaddr;
404         if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
405                 regs->ARM_pc -= correction;
406         return TYPE_DONE;
407
408 fault:
409         regs->ARM_pc -= correction;
410         return TYPE_FAULT;
411
412 bad:
413         printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
414         return TYPE_ERROR;
415 }
416
417 static int
418 do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
419 {
420         union offset_union offset;
421         unsigned long instr, instrptr;
422         int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
423         unsigned int type;
424
425         if (user_mode(regs))
426                 goto user;
427
428         ai_sys += 1;
429
430         instrptr = instruction_pointer(regs);
431         instr = *(unsigned long *)instrptr;
432
433         regs->ARM_pc += 4;
434
435         switch (CODING_BITS(instr)) {
436         case 0x00000000:        /* ldrh or strh */
437                 if (LDSTH_I_BIT(instr))
438                         offset.un = (instr & 0xf00) >> 4 | (instr & 15);
439                 else
440                         offset.un = regs->uregs[RM_BITS(instr)];
441                 handler = do_alignment_ldrhstrh;
442                 break;
443
444         case 0x04000000:        /* ldr or str immediate */
445                 offset.un = OFFSET_BITS(instr);
446                 handler = do_alignment_ldrstr;
447                 break;
448
449         case 0x06000000:        /* ldr or str register */
450                 offset.un = regs->uregs[RM_BITS(instr)];
451
452                 if (IS_SHIFT(instr)) {
453                         unsigned int shiftval = SHIFT_BITS(instr);
454
455                         switch(SHIFT_TYPE(instr)) {
456                         case SHIFT_LSL:
457                                 offset.un <<= shiftval;
458                                 break;
459
460                         case SHIFT_LSR:
461                                 offset.un >>= shiftval;
462                                 break;
463
464                         case SHIFT_ASR:
465                                 offset.sn >>= shiftval;
466                                 break;
467
468                         case SHIFT_RORRRX:
469                                 if (shiftval == 0) {
470                                         offset.un >>= 1;
471                                         if (regs->ARM_cpsr & CC_C_BIT)
472                                                 offset.un |= 1 << 31;
473                                 } else
474                                         offset.un = offset.un >> shiftval |
475                                                           offset.un << (32 - shiftval);
476                                 break;
477                         }
478                 }
479                 handler = do_alignment_ldrstr;
480                 break;
481
482         case 0x08000000:        /* ldm or stm */
483                 handler = do_alignment_ldmstm;
484                 break;
485
486         default:
487                 goto bad;
488         }
489
490         type = handler(addr, instr, regs);
491
492         if (type == TYPE_ERROR || type == TYPE_FAULT)
493                 goto bad_or_fault;
494
495         if (type == TYPE_LDST)
496                 do_alignment_finish_ldst(addr, instr, regs, offset);
497
498         return 0;
499
500 bad_or_fault:
501         if (type == TYPE_ERROR)
502                 goto bad;
503         regs->ARM_pc -= 4;
504         /*
505          * We got a fault - fix it up, or die.
506          */
507         do_bad_area(current, current->mm, addr, error_code, regs);
508         return 0;
509
510 bad:
511         /*
512          * Oops, we didn't handle the instruction.
513          */
514         printk(KERN_ERR "Alignment trap: not handling instruction "
515                 "%08lx at [<%08lx>]", instr, instrptr);
516         ai_skipped += 1;
517         return 1;
518
519 user:
520         set_cr(cr_no_alignment);
521         ai_user += 1;
522         return 0;
523 }
524
525 #else
526
527 #define do_alignment NULL
528
529 #endif
530
531 /*
532  * Some section permission faults need to be handled gracefully, for
533  * instance, when they happen due to a __{get,put}_user during an oops).
534  */
535 static int
536 do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs)
537 {
538         struct task_struct *tsk = current;
539         do_bad_area(tsk, tsk->active_mm, addr, error_code, regs);
540         return 0;
541 }
542
543 /*
544  * Hook for things that need to trap external faults.  Note that
545  * we don't guarantee that this will be the final version of the
546  * interface.
547  */
548 int (*external_fault)(unsigned long addr, struct pt_regs *regs);
549
550 static int
551 do_external_fault(unsigned long addr, int error_code, struct pt_regs *regs)
552 {
553         if (external_fault)
554                 return external_fault(addr, regs);
555         return 1;
556 }
557
558 static const struct fsr_info {
559         int     (*fn)(unsigned long addr, int error_code, struct pt_regs *regs);
560         int     sig;
561         char    *name;
562 } fsr_info[] = {
563         { NULL,                 SIGSEGV, "vector exception"                },
564         { do_alignment,         SIGILL,  "alignment exception"             },
565         { NULL,                 SIGKILL, "terminal exception"              },
566         { do_alignment,         SIGILL,  "alignment exception"             },
567         { do_external_fault,    SIGBUS,  "external abort on linefetch"     },
568         { do_translation_fault, SIGSEGV, "section translation fault"       },
569         { do_external_fault,    SIGBUS,  "external abort on linefetch"     },
570         { do_page_fault,        SIGSEGV, "page translation fault"          },
571         { do_external_fault,    SIGBUS,  "external abort on non-linefetch" },
572         { NULL,                 SIGSEGV, "section domain fault"            },
573         { do_external_fault,    SIGBUS,  "external abort on non-linefetch" },
574         { NULL,                 SIGSEGV, "page domain fault"               },
575         { NULL,                 SIGBUS,  "external abort on translation"   },
576         { do_sect_fault,        SIGSEGV, "section permission fault"        },
577         { NULL,                 SIGBUS,  "external abort on translation"   },
578         { do_page_fault,        SIGSEGV, "page permission fault"           }
579 };
580
581 /*
582  * Currently dropped down to debug level
583  */
584 asmlinkage void
585 do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr)
586 {
587         const struct fsr_info *inf = fsr_info + (fsr & 15);
588
589 #if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS)
590         if (addr == regs->ARM_pc)
591                 goto sa1_weirdness;
592 #endif
593
594         if (!inf->fn)
595                 goto bad;
596
597         if (!inf->fn(addr, error_code, regs))
598                 return;
599 bad:
600         force_sig(inf->sig, current);
601         printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n",
602                 inf->name, fsr, addr);
603         show_pte(current->mm, addr);
604         die_if_kernel("Oops", regs, 0);
605         return;
606
607 #if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100) || defined(CONFIG_DEBUG_ERRORS)
608 sa1_weirdness:
609         if (user_mode(regs)) {
610                 static int first = 1;
611                 if (first) {
612                         printk(KERN_DEBUG "Fixing up bad data abort at %08lx\n", addr);
613 #ifdef CONFIG_DEBUG_ERRORS
614                         show_pte(current->mm, addr);
615 #endif
616                 }
617                 first = 0;
618                 return;
619         }
620
621         if (!inf->fn || inf->fn(addr, error_code, regs))
622                 goto bad;
623         return;
624 #endif
625 }
626
627 asmlinkage void
628 do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
629 {
630         do_translation_fault(addr, 0, regs);
631 }
632
633 /*
634  * if PG_dcache_dirty is set for the page, we need to ensure that any
635  * cache entries for the kernels virtual memory range are written
636  * back to the page.
637  */
638 void check_pgcache_dirty(struct page *page)
639 {
640         if (VALID_PAGE(page) && page->mapping &&
641             test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
642                 unsigned long kvirt = (unsigned long)page_address(page);
643                 cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
644         }
645 }