1 /*
2 * linux/arch/arm/mm/alignment.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/compiler.h>
13 #include <linux/signal.h>
14 #include <linux/sched.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/types.h>
19 #include <linux/ptrace.h>
20 #include <linux/mman.h>
21 #include <linux/mm.h>
22 #include <linux/interrupt.h>
23 #include <linux/proc_fs.h>
24 #include <linux/bitops.h>
25 #include <linux/init.h>
26
27 #include <asm/system.h>
28 #include <asm/uaccess.h>
29 #include <asm/pgalloc.h>
30 #include <asm/pgtable.h>
31 #include <asm/unaligned.h>
32
33 extern void
34 do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
35 int error_code, struct pt_regs *regs);
36
37 /*
38 * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
39 * /proc/sys/debug/alignment, modified and integrated into
40 * Linux 2.1 by Russell King
41 *
42 * Speed optimisations and better fault handling by Russell King.
43 *
44 * *** NOTE ***
45 * This code is not portable to processors with late data abort handling.
46 */
47 #define CODING_BITS(i) (i & 0x0e000000)
48
49 #define LDST_I_BIT(i) (i & (1 << 26)) /* Immediate constant */
50 #define LDST_P_BIT(i) (i & (1 << 24)) /* Preindex */
51 #define LDST_U_BIT(i) (i & (1 << 23)) /* Add offset */
52 #define LDST_W_BIT(i) (i & (1 << 21)) /* Writeback */
53 #define LDST_L_BIT(i) (i & (1 << 20)) /* Load */
54
55 #define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
56
57 #define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */
58 #define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
59
60 #define RN_BITS(i) ((i >> 16) & 15) /* Rn */
61 #define RD_BITS(i) ((i >> 12) & 15) /* Rd */
62 #define RM_BITS(i) (i & 15) /* Rm */
63
64 #define REGMASK_BITS(i) (i & 0xffff)
65 #define OFFSET_BITS(i) (i & 0x0fff)
66
67 #define IS_SHIFT(i) (i & 0x0ff0)
68 #define SHIFT_BITS(i) ((i >> 7) & 0x1f)
69 #define SHIFT_TYPE(i) (i & 0x60)
70 #define SHIFT_LSL 0x00
71 #define SHIFT_LSR 0x20
72 #define SHIFT_ASR 0x40
73 #define SHIFT_RORRRX 0x60
74
75 static unsigned long ai_user;
76 static unsigned long ai_sys;
77 static unsigned long ai_skipped;
78 static unsigned long ai_half;
79 static unsigned long ai_word;
80 static unsigned long ai_multi;
81 static int ai_usermode;
82
83 #ifdef CONFIG_PROC_FS
84 static const char *usermode_action[] = {
85 "ignored",
86 "warn",
87 "fixup",
88 "fixup+warn",
89 "signal",
90 "signal+warn"
91 };
92
93 static int
proc_alignment_read(char * page,char ** start,off_t off,int count,int * eof,void * data)94 proc_alignment_read(char *page, char **start, off_t off, int count, int *eof,
95 void *data)
96 {
97 char *p = page;
98 int len;
99
100 p += sprintf(p, "User:\t\t%lu\n", ai_user);
101 p += sprintf(p, "System:\t\t%lu\n", ai_sys);
102 p += sprintf(p, "Skipped:\t%lu\n", ai_skipped);
103 p += sprintf(p, "Half:\t\t%lu\n", ai_half);
104 p += sprintf(p, "Word:\t\t%lu\n", ai_word);
105 p += sprintf(p, "Multi:\t\t%lu\n", ai_multi);
106 p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode,
107 usermode_action[ai_usermode]);
108
109 len = (p - page) - off;
110 if (len < 0)
111 len = 0;
112
113 *eof = (len <= count) ? 1 : 0;
114 *start = page + off;
115
116 return len;
117 }
118
proc_alignment_write(struct file * file,const char * buffer,unsigned long count,void * data)119 static int proc_alignment_write(struct file *file, const char *buffer,
120 unsigned long count, void *data)
121 {
122 int mode;
123
124 if (count > 0) {
125 if (get_user(mode, buffer))
126 return -EFAULT;
127 if (mode >= '0' && mode <= '5')
128 ai_usermode = mode - '0';
129 }
130 return count;
131 }
132
133 /*
134 * This needs to be done after sysctl_init, otherwise sys/ will be
135 * overwritten. Actually, this shouldn't be in sys/ at all since
136 * it isn't a sysctl, and it doesn't contain sysctl information.
137 * We now locate it in /proc/cpu/alignment instead.
138 */
alignment_init(void)139 static int __init alignment_init(void)
140 {
141 struct proc_dir_entry *res;
142
143 res = proc_mkdir("cpu", NULL);
144 if (!res)
145 return -ENOMEM;
146
147 res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res);
148 if (!res)
149 return -ENOMEM;
150
151 res->read_proc = proc_alignment_read;
152 res->write_proc = proc_alignment_write;
153
154 return 0;
155 }
156
157 __initcall(alignment_init);
158 #endif /* CONFIG_PROC_FS */
159
160 union offset_union {
161 unsigned long un;
162 signed long sn;
163 };
164
165 #define TYPE_ERROR 0
166 #define TYPE_FAULT 1
167 #define TYPE_LDST 2
168 #define TYPE_DONE 3
169
170 #define __get8_unaligned_check(ins,val,addr,err) \
171 __asm__( \
172 "1: "ins" %1, [%2], #1\n" \
173 "2:\n" \
174 " .section .fixup,\"ax\"\n" \
175 " .align 2\n" \
176 "3: mov %0, #1\n" \
177 " b 2b\n" \
178 " .previous\n" \
179 " .section __ex_table,\"a\"\n" \
180 " .align 3\n" \
181 " .long 1b, 3b\n" \
182 " .previous\n" \
183 : "=r" (err), "=&r" (val), "=r" (addr) \
184 : "0" (err), "2" (addr))
185
186 #define __get16_unaligned_check(ins,val,addr) \
187 do { \
188 unsigned int err = 0, v, a = addr; \
189 __get8_unaligned_check(ins,val,a,err); \
190 __get8_unaligned_check(ins,v,a,err); \
191 val |= v << 8; \
192 if (err) \
193 goto fault; \
194 } while (0)
195
196 #define get16_unaligned_check(val,addr) \
197 __get16_unaligned_check("ldrb",val,addr)
198
199 #define get16t_unaligned_check(val,addr) \
200 __get16_unaligned_check("ldrbt",val,addr)
201
202 #define __get32_unaligned_check(ins,val,addr) \
203 do { \
204 unsigned int err = 0, v, a = addr; \
205 __get8_unaligned_check(ins,val,a,err); \
206 __get8_unaligned_check(ins,v,a,err); \
207 val |= v << 8; \
208 __get8_unaligned_check(ins,v,a,err); \
209 val |= v << 16; \
210 __get8_unaligned_check(ins,v,a,err); \
211 val |= v << 24; \
212 if (err) \
213 goto fault; \
214 } while (0)
215
216 #define get32_unaligned_check(val,addr) \
217 __get32_unaligned_check("ldrb",val,addr)
218
219 #define get32t_unaligned_check(val,addr) \
220 __get32_unaligned_check("ldrbt",val,addr)
221
222 #define __put16_unaligned_check(ins,val,addr) \
223 do { \
224 unsigned int err = 0, v = val, a = addr; \
225 __asm__( \
226 "1: "ins" %1, [%2], #1\n" \
227 " mov %1, %1, lsr #8\n" \
228 "2: "ins" %1, [%2]\n" \
229 "3:\n" \
230 " .section .fixup,\"ax\"\n" \
231 " .align 2\n" \
232 "4: mov %0, #1\n" \
233 " b 3b\n" \
234 " .previous\n" \
235 " .section __ex_table,\"a\"\n" \
236 " .align 3\n" \
237 " .long 1b, 4b\n" \
238 " .long 2b, 4b\n" \
239 " .previous\n" \
240 : "=r" (err), "=&r" (v), "=&r" (a) \
241 : "0" (err), "1" (v), "2" (a)); \
242 if (err) \
243 goto fault; \
244 } while (0)
245
246 #define put16_unaligned_check(val,addr) \
247 __put16_unaligned_check("strb",val,addr)
248
249 #define put16t_unaligned_check(val,addr) \
250 __put16_unaligned_check("strbt",val,addr)
251
252 #define __put32_unaligned_check(ins,val,addr) \
253 do { \
254 unsigned int err = 0, v = val, a = addr; \
255 __asm__( \
256 "1: "ins" %1, [%2], #1\n" \
257 " mov %1, %1, lsr #8\n" \
258 "2: "ins" %1, [%2], #1\n" \
259 " mov %1, %1, lsr #8\n" \
260 "3: "ins" %1, [%2], #1\n" \
261 " mov %1, %1, lsr #8\n" \
262 "4: "ins" %1, [%2]\n" \
263 "5:\n" \
264 " .section .fixup,\"ax\"\n" \
265 " .align 2\n" \
266 "6: mov %0, #1\n" \
267 " b 5b\n" \
268 " .previous\n" \
269 " .section __ex_table,\"a\"\n" \
270 " .align 3\n" \
271 " .long 1b, 6b\n" \
272 " .long 2b, 6b\n" \
273 " .long 3b, 6b\n" \
274 " .long 4b, 6b\n" \
275 " .previous\n" \
276 : "=r" (err), "=&r" (v), "=&r" (a) \
277 : "0" (err), "1" (v), "2" (a)); \
278 if (err) \
279 goto fault; \
280 } while (0)
281
282 #define put32_unaligned_check(val,addr) \
283 __put32_unaligned_check("strb", val, addr)
284
285 #define put32t_unaligned_check(val,addr) \
286 __put32_unaligned_check("strbt", val, addr)
287
288 static void
do_alignment_finish_ldst(unsigned long addr,unsigned long instr,struct pt_regs * regs,union offset_union offset)289 do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset)
290 {
291 if (!LDST_U_BIT(instr))
292 offset.un = -offset.un;
293
294 if (!LDST_P_BIT(instr))
295 addr += offset.un;
296
297 if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
298 regs->uregs[RN_BITS(instr)] = addr;
299 }
300
301 static int
do_alignment_ldrhstrh(unsigned long addr,unsigned long instr,struct pt_regs * regs)302 do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs)
303 {
304 unsigned int rd = RD_BITS(instr);
305
306 if ((instr & 0x01f00ff0) == 0x01000090)
307 goto swp;
308
309 if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
310 goto bad;
311
312 ai_half += 1;
313
314 if (user_mode(regs))
315 goto user;
316
317 if (LDST_L_BIT(instr)) {
318 unsigned long val;
319 get16_unaligned_check(val, addr);
320
321 /* signed half-word? */
322 if (instr & 0x40)
323 val = (signed long)((signed short) val);
324
325 regs->uregs[rd] = val;
326 } else
327 put16_unaligned_check(regs->uregs[rd], addr);
328
329 return TYPE_LDST;
330
331 user:
332 if (LDST_L_BIT(instr)) {
333 unsigned long val;
334 get16t_unaligned_check(val, addr);
335
336 /* signed half-word? */
337 if (instr & 0x40)
338 val = (signed long)((signed short) val);
339
340 regs->uregs[rd] = val;
341 } else
342 put16t_unaligned_check(regs->uregs[rd], addr);
343
344 return TYPE_LDST;
345
346 swp:
347 printk(KERN_ERR "Alignment trap: not handling swp instruction\n");
348 bad:
349 return TYPE_ERROR;
350
351 fault:
352 return TYPE_FAULT;
353 }
354
355 static int
do_alignment_ldrstr(unsigned long addr,unsigned long instr,struct pt_regs * regs)356 do_alignment_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs)
357 {
358 unsigned int rd = RD_BITS(instr);
359
360 ai_word += 1;
361
362 if ((!LDST_P_BIT(instr) && LDST_W_BIT(instr)) || user_mode(regs))
363 goto trans;
364
365 if (LDST_L_BIT(instr)) {
366 unsigned int val;
367 get32_unaligned_check(val, addr);
368 regs->uregs[rd] = val;
369 } else
370 put32_unaligned_check(regs->uregs[rd], addr);
371 return TYPE_LDST;
372
373 trans:
374 if (LDST_L_BIT(instr)) {
375 unsigned int val;
376 get32t_unaligned_check(val, addr);
377 regs->uregs[rd] = val;
378 } else
379 put32t_unaligned_check(regs->uregs[rd], addr);
380 return TYPE_LDST;
381
382 fault:
383 return TYPE_FAULT;
384 }
385
386 /*
387 * LDM/STM alignment handler.
388 *
389 * There are 4 variants of this instruction:
390 *
391 * B = rn pointer before instruction, A = rn pointer after instruction
392 * ------ increasing address ----->
393 * | | r0 | r1 | ... | rx | |
394 * PU = 01 B A
395 * PU = 11 B A
396 * PU = 00 A B
397 * PU = 10 A B
398 */
399 static int
do_alignment_ldmstm(unsigned long addr,unsigned long instr,struct pt_regs * regs)400 do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *regs)
401 {
402 unsigned int rd, rn, correction, nr_regs, regbits;
403 unsigned long eaddr, newaddr;
404
405 if (LDM_S_BIT(instr))
406 goto bad;
407
408 correction = 4; /* processor implementation defined */
409 regs->ARM_pc += correction;
410
411 ai_multi += 1;
412
413 /* count the number of registers in the mask to be transferred */
414 nr_regs = hweight16(REGMASK_BITS(instr)) * 4;
415
416 rn = RN_BITS(instr);
417 newaddr = eaddr = regs->uregs[rn];
418
419 if (!LDST_U_BIT(instr))
420 nr_regs = -nr_regs;
421 newaddr += nr_regs;
422 if (!LDST_U_BIT(instr))
423 eaddr = newaddr;
424
425 if (LDST_P_EQ_U(instr)) /* U = P */
426 eaddr += 4;
427
428 /*
429 * For alignment faults on the ARM922T/ARM920T the MMU makes
430 * the FSR (and hence addr) equal to the updated base address
431 * of the multiple access rather than the restored value.
432 * Switch this messsage off if we've got a ARM92[02], otherwise
433 * [ls]dm alignment faults are noisy!
434 */
435 #if !(defined CONFIG_CPU_ARM922T) && !(defined CONFIG_CPU_ARM920T)
436 /*
437 * This is a "hint" - we already have eaddr worked out by the
438 * processor for us.
439 */
440 if (addr != eaddr) {
441 printk(KERN_ERR "LDMSTM: PC = %08lx, instr = %08lx, "
442 "addr = %08lx, eaddr = %08lx\n",
443 instruction_pointer(regs), instr, addr, eaddr);
444 show_regs(regs);
445 }
446 #endif
447
448 if (user_mode(regs)) {
449 for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
450 regbits >>= 1, rd += 1)
451 if (regbits & 1) {
452 if (LDST_L_BIT(instr)) {
453 unsigned int val;
454 get32t_unaligned_check(val, eaddr);
455 regs->uregs[rd] = val;
456 } else
457 put32t_unaligned_check(regs->uregs[rd], eaddr);
458 eaddr += 4;
459 }
460 } else {
461 for (regbits = REGMASK_BITS(instr), rd = 0; regbits;
462 regbits >>= 1, rd += 1)
463 if (regbits & 1) {
464 if (LDST_L_BIT(instr)) {
465 unsigned int val;
466 get32_unaligned_check(val, eaddr);
467 regs->uregs[rd] = val;
468 } else
469 put32_unaligned_check(regs->uregs[rd], eaddr);
470 eaddr += 4;
471 }
472 }
473
474 if (LDST_W_BIT(instr))
475 regs->uregs[rn] = newaddr;
476 if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15)))
477 regs->ARM_pc -= correction;
478 return TYPE_DONE;
479
480 fault:
481 regs->ARM_pc -= correction;
482 return TYPE_FAULT;
483
484 bad:
485 printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n");
486 return TYPE_ERROR;
487 }
488
do_alignment(unsigned long addr,int error_code,struct pt_regs * regs)489 int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
490 {
491 union offset_union offset;
492 unsigned long instr, instrptr;
493 int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
494 unsigned int type;
495
496 instrptr = instruction_pointer(regs);
497 instr = *(unsigned long *)instrptr;
498
499 if (user_mode(regs))
500 goto user;
501
502 ai_sys += 1;
503
504 fixup:
505
506 regs->ARM_pc += 4;
507
508 switch (CODING_BITS(instr)) {
509 case 0x00000000: /* ldrh or strh */
510 if (LDSTH_I_BIT(instr))
511 offset.un = (instr & 0xf00) >> 4 | (instr & 15);
512 else
513 offset.un = regs->uregs[RM_BITS(instr)];
514 handler = do_alignment_ldrhstrh;
515 break;
516
517 case 0x04000000: /* ldr or str immediate */
518 offset.un = OFFSET_BITS(instr);
519 handler = do_alignment_ldrstr;
520 break;
521
522 case 0x06000000: /* ldr or str register */
523 offset.un = regs->uregs[RM_BITS(instr)];
524
525 if (IS_SHIFT(instr)) {
526 unsigned int shiftval = SHIFT_BITS(instr);
527
528 switch(SHIFT_TYPE(instr)) {
529 case SHIFT_LSL:
530 offset.un <<= shiftval;
531 break;
532
533 case SHIFT_LSR:
534 offset.un >>= shiftval;
535 break;
536
537 case SHIFT_ASR:
538 offset.sn >>= shiftval;
539 break;
540
541 case SHIFT_RORRRX:
542 if (shiftval == 0) {
543 offset.un >>= 1;
544 if (regs->ARM_cpsr & CC_C_BIT)
545 offset.un |= 1 << 31;
546 } else
547 offset.un = offset.un >> shiftval |
548 offset.un << (32 - shiftval);
549 break;
550 }
551 }
552 handler = do_alignment_ldrstr;
553 break;
554
555 case 0x08000000: /* ldm or stm */
556 handler = do_alignment_ldmstm;
557 break;
558
559 default:
560 goto bad;
561 }
562
563 type = handler(addr, instr, regs);
564
565 if (type == TYPE_ERROR || type == TYPE_FAULT)
566 goto bad_or_fault;
567
568 if (type == TYPE_LDST)
569 do_alignment_finish_ldst(addr, instr, regs, offset);
570
571 return 0;
572
573 bad_or_fault:
574 if (type == TYPE_ERROR)
575 goto bad;
576 regs->ARM_pc -= 4;
577 /*
578 * We got a fault - fix it up, or die.
579 */
580 do_bad_area(current, current->mm, addr, error_code, regs);
581 return 0;
582
583 bad:
584 /*
585 * Oops, we didn't handle the instruction.
586 */
587 printk(KERN_ERR "Alignment trap: not handling instruction "
588 "%08lx at [<%08lx>]\n", instr, instrptr);
589 ai_skipped += 1;
590 return 1;
591
592 user:
593 ai_user += 1;
594
595 if (ai_usermode & 1)
596 printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%08lx "
597 "Address=0x%08lx Code 0x%02x\n", current->comm,
598 current->pid, instrptr, instr, addr, error_code);
599
600 if (ai_usermode & 2)
601 goto fixup;
602
603 if (ai_usermode & 4)
604 force_sig(SIGBUS, current);
605 else
606 set_cr(cr_no_alignment);
607
608 return 0;
609 }
610