diff options
Diffstat (limited to 'arch/arm/mm/alignment.c')
-rw-r--r-- | arch/arm/mm/alignment.c | 55 |
1 files changed, 32 insertions, 23 deletions
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index 4b39d867ac14..705c98921c37 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c | |||
@@ -111,7 +111,7 @@ proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, | |||
111 | } | 111 | } |
112 | 112 | ||
113 | static int proc_alignment_write(struct file *file, const char __user *buffer, | 113 | static int proc_alignment_write(struct file *file, const char __user *buffer, |
114 | unsigned long count, void *data) | 114 | unsigned long count, void *data) |
115 | { | 115 | { |
116 | char mode; | 116 | char mode; |
117 | 117 | ||
@@ -119,7 +119,7 @@ static int proc_alignment_write(struct file *file, const char __user *buffer, | |||
119 | if (get_user(mode, buffer)) | 119 | if (get_user(mode, buffer)) |
120 | return -EFAULT; | 120 | return -EFAULT; |
121 | if (mode >= '0' && mode <= '5') | 121 | if (mode >= '0' && mode <= '5') |
122 | ai_usermode = mode - '0'; | 122 | ai_usermode = mode - '0'; |
123 | } | 123 | } |
124 | return count; | 124 | return count; |
125 | } | 125 | } |
@@ -262,7 +262,7 @@ union offset_union { | |||
262 | goto fault; \ | 262 | goto fault; \ |
263 | } while (0) | 263 | } while (0) |
264 | 264 | ||
265 | #define put32_unaligned_check(val,addr) \ | 265 | #define put32_unaligned_check(val,addr) \ |
266 | __put32_unaligned_check("strb", val, addr) | 266 | __put32_unaligned_check("strb", val, addr) |
267 | 267 | ||
268 | #define put32t_unaligned_check(val,addr) \ | 268 | #define put32t_unaligned_check(val,addr) \ |
@@ -306,19 +306,19 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r | |||
306 | return TYPE_LDST; | 306 | return TYPE_LDST; |
307 | 307 | ||
308 | user: | 308 | user: |
309 | if (LDST_L_BIT(instr)) { | 309 | if (LDST_L_BIT(instr)) { |
310 | unsigned long val; | 310 | unsigned long val; |
311 | get16t_unaligned_check(val, addr); | 311 | get16t_unaligned_check(val, addr); |
312 | 312 | ||
313 | /* signed half-word? */ | 313 | /* signed half-word? */ |
314 | if (instr & 0x40) | 314 | if (instr & 0x40) |
315 | val = (signed long)((signed short) val); | 315 | val = (signed long)((signed short) val); |
316 | 316 | ||
317 | regs->uregs[rd] = val; | 317 | regs->uregs[rd] = val; |
318 | } else | 318 | } else |
319 | put16t_unaligned_check(regs->uregs[rd], addr); | 319 | put16t_unaligned_check(regs->uregs[rd], addr); |
320 | 320 | ||
321 | return TYPE_LDST; | 321 | return TYPE_LDST; |
322 | 322 | ||
323 | fault: | 323 | fault: |
324 | return TYPE_FAULT; | 324 | return TYPE_FAULT; |
@@ -330,6 +330,9 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
330 | { | 330 | { |
331 | unsigned int rd = RD_BITS(instr); | 331 | unsigned int rd = RD_BITS(instr); |
332 | 332 | ||
333 | if (((rd & 1) == 1) || (rd == 14)) | ||
334 | goto bad; | ||
335 | |||
333 | ai_dword += 1; | 336 | ai_dword += 1; |
334 | 337 | ||
335 | if (user_mode(regs)) | 338 | if (user_mode(regs)) |
@@ -339,11 +342,11 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
339 | unsigned long val; | 342 | unsigned long val; |
340 | get32_unaligned_check(val, addr); | 343 | get32_unaligned_check(val, addr); |
341 | regs->uregs[rd] = val; | 344 | regs->uregs[rd] = val; |
342 | get32_unaligned_check(val, addr+4); | 345 | get32_unaligned_check(val, addr + 4); |
343 | regs->uregs[rd+1] = val; | 346 | regs->uregs[rd + 1] = val; |
344 | } else { | 347 | } else { |
345 | put32_unaligned_check(regs->uregs[rd], addr); | 348 | put32_unaligned_check(regs->uregs[rd], addr); |
346 | put32_unaligned_check(regs->uregs[rd+1], addr+4); | 349 | put32_unaligned_check(regs->uregs[rd + 1], addr + 4); |
347 | } | 350 | } |
348 | 351 | ||
349 | return TYPE_LDST; | 352 | return TYPE_LDST; |
@@ -353,15 +356,16 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
353 | unsigned long val; | 356 | unsigned long val; |
354 | get32t_unaligned_check(val, addr); | 357 | get32t_unaligned_check(val, addr); |
355 | regs->uregs[rd] = val; | 358 | regs->uregs[rd] = val; |
356 | get32t_unaligned_check(val, addr+4); | 359 | get32t_unaligned_check(val, addr + 4); |
357 | regs->uregs[rd+1] = val; | 360 | regs->uregs[rd + 1] = val; |
358 | } else { | 361 | } else { |
359 | put32t_unaligned_check(regs->uregs[rd], addr); | 362 | put32t_unaligned_check(regs->uregs[rd], addr); |
360 | put32t_unaligned_check(regs->uregs[rd+1], addr+4); | 363 | put32t_unaligned_check(regs->uregs[rd + 1], addr + 4); |
361 | } | 364 | } |
362 | 365 | ||
363 | return TYPE_LDST; | 366 | return TYPE_LDST; |
364 | 367 | bad: | |
368 | return TYPE_ERROR; | ||
365 | fault: | 369 | fault: |
366 | return TYPE_FAULT; | 370 | return TYPE_FAULT; |
367 | } | 371 | } |
@@ -439,7 +443,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg | |||
439 | if (LDST_P_EQ_U(instr)) /* U = P */ | 443 | if (LDST_P_EQ_U(instr)) /* U = P */ |
440 | eaddr += 4; | 444 | eaddr += 4; |
441 | 445 | ||
442 | /* | 446 | /* |
443 | * For alignment faults on the ARM922T/ARM920T the MMU makes | 447 | * For alignment faults on the ARM922T/ARM920T the MMU makes |
444 | * the FSR (and hence addr) equal to the updated base address | 448 | * the FSR (and hence addr) equal to the updated base address |
445 | * of the multiple access rather than the restored value. | 449 | * of the multiple access rather than the restored value. |
@@ -566,7 +570,7 @@ thumb2arm(u16 tinstr) | |||
566 | /* 6.5.1 Format 3: */ | 570 | /* 6.5.1 Format 3: */ |
567 | case 0x4800 >> 11: /* 7.1.28 LDR(3) */ | 571 | case 0x4800 >> 11: /* 7.1.28 LDR(3) */ |
568 | /* NOTE: This case is not technically possible. We're | 572 | /* NOTE: This case is not technically possible. We're |
569 | * loading 32-bit memory data via PC relative | 573 | * loading 32-bit memory data via PC relative |
570 | * addressing mode. So we can and should eliminate | 574 | * addressing mode. So we can and should eliminate |
571 | * this case. But I'll leave it here for now. | 575 | * this case. But I'll leave it here for now. |
572 | */ | 576 | */ |
@@ -638,7 +642,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
638 | 642 | ||
639 | if (fault) { | 643 | if (fault) { |
640 | type = TYPE_FAULT; | 644 | type = TYPE_FAULT; |
641 | goto bad_or_fault; | 645 | goto bad_or_fault; |
642 | } | 646 | } |
643 | 647 | ||
644 | if (user_mode(regs)) | 648 | if (user_mode(regs)) |
@@ -663,6 +667,8 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
663 | else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */ | 667 | else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */ |
664 | (instr & 0x001000f0) == 0x000000f0) /* STRD */ | 668 | (instr & 0x001000f0) == 0x000000f0) /* STRD */ |
665 | handler = do_alignment_ldrdstrd; | 669 | handler = do_alignment_ldrdstrd; |
670 | else if ((instr & 0x01f00ff0) == 0x01000090) /* SWP */ | ||
671 | goto swp; | ||
666 | else | 672 | else |
667 | goto bad; | 673 | goto bad; |
668 | break; | 674 | break; |
@@ -733,6 +739,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
733 | do_bad_area(current, current->mm, addr, fsr, regs); | 739 | do_bad_area(current, current->mm, addr, fsr, regs); |
734 | return 0; | 740 | return 0; |
735 | 741 | ||
742 | swp: | ||
743 | printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); | ||
744 | |||
736 | bad: | 745 | bad: |
737 | /* | 746 | /* |
738 | * Oops, we didn't handle the instruction. | 747 | * Oops, we didn't handle the instruction. |