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. |
