Commit f21ee2d4 authored by Steve Longerbeam's avatar Steve Longerbeam Committed by Russell King

[ARM] 2867/2: unaligned ldrd/strd fixups

Patch from Steve Longerbeam

Adds an implementation of unaligned LDRD and STRD fixups.
Also fixes a bug where do_alignment() would misinterpret and
fixup an unaligned LDRD/STRD as LDRH/STRH, causing memory
corruption.
This is the same as Patch #2867/1, but with minor whitespace
and comments changes, plus a check for arch-level >= v5TE
before printing ai_dword count in proc_alignment_read().
Signed-off-by: default avatarSteve Longerbeam <stevel@mwwireless.net>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 3618886f
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
#define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0) #define LDST_P_EQ_U(i) ((((i) ^ ((i) >> 1)) & (1 << 23)) == 0)
#define LDSTH_I_BIT(i) (i & (1 << 22)) /* half-word immed */ #define LDSTHD_I_BIT(i) (i & (1 << 22)) /* double/half-word immed */
#define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */ #define LDM_S_BIT(i) (i & (1 << 22)) /* write CPSR from SPSR */
#define RN_BITS(i) ((i >> 16) & 15) /* Rn */ #define RN_BITS(i) ((i >> 16) & 15) /* Rn */
...@@ -68,6 +68,7 @@ static unsigned long ai_sys; ...@@ -68,6 +68,7 @@ static unsigned long ai_sys;
static unsigned long ai_skipped; static unsigned long ai_skipped;
static unsigned long ai_half; static unsigned long ai_half;
static unsigned long ai_word; static unsigned long ai_word;
static unsigned long ai_dword;
static unsigned long ai_multi; static unsigned long ai_multi;
static int ai_usermode; static int ai_usermode;
...@@ -93,6 +94,8 @@ proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, ...@@ -93,6 +94,8 @@ proc_alignment_read(char *page, char **start, off_t off, int count, int *eof,
p += sprintf(p, "Skipped:\t%lu\n", ai_skipped); p += sprintf(p, "Skipped:\t%lu\n", ai_skipped);
p += sprintf(p, "Half:\t\t%lu\n", ai_half); p += sprintf(p, "Half:\t\t%lu\n", ai_half);
p += sprintf(p, "Word:\t\t%lu\n", ai_word); p += sprintf(p, "Word:\t\t%lu\n", ai_word);
if (cpu_architecture() >= CPU_ARCH_ARMv5TE)
p += sprintf(p, "DWord:\t\t%lu\n", ai_dword);
p += sprintf(p, "Multi:\t\t%lu\n", ai_multi); p += sprintf(p, "Multi:\t\t%lu\n", ai_multi);
p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode, p += sprintf(p, "User faults:\t%i (%s)\n", ai_usermode,
usermode_action[ai_usermode]); usermode_action[ai_usermode]);
...@@ -283,12 +286,6 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r ...@@ -283,12 +286,6 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
{ {
unsigned int rd = RD_BITS(instr); unsigned int rd = RD_BITS(instr);
if ((instr & 0x01f00ff0) == 0x01000090)
goto swp;
if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0)
goto bad;
ai_half += 1; ai_half += 1;
if (user_mode(regs)) if (user_mode(regs))
...@@ -323,10 +320,47 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r ...@@ -323,10 +320,47 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r
return TYPE_LDST; return TYPE_LDST;
swp: fault:
printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); return TYPE_FAULT;
bad: }
return TYPE_ERROR;
static int
do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
struct pt_regs *regs)
{
unsigned int rd = RD_BITS(instr);
ai_dword += 1;
if (user_mode(regs))
goto user;
if ((instr & 0xf0) == 0xd0) {
unsigned long val;
get32_unaligned_check(val, addr);
regs->uregs[rd] = val;
get32_unaligned_check(val, addr+4);
regs->uregs[rd+1] = val;
} else {
put32_unaligned_check(regs->uregs[rd], addr);
put32_unaligned_check(regs->uregs[rd+1], addr+4);
}
return TYPE_LDST;
user:
if ((instr & 0xf0) == 0xd0) {
unsigned long val;
get32t_unaligned_check(val, addr);
regs->uregs[rd] = val;
get32t_unaligned_check(val, addr+4);
regs->uregs[rd+1] = val;
} else {
put32t_unaligned_check(regs->uregs[rd], addr);
put32t_unaligned_check(regs->uregs[rd+1], addr+4);
}
return TYPE_LDST;
fault: fault:
return TYPE_FAULT; return TYPE_FAULT;
...@@ -617,12 +651,20 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) ...@@ -617,12 +651,20 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
regs->ARM_pc += thumb_mode(regs) ? 2 : 4; regs->ARM_pc += thumb_mode(regs) ? 2 : 4;
switch (CODING_BITS(instr)) { switch (CODING_BITS(instr)) {
case 0x00000000: /* ldrh or strh */ case 0x00000000: /* 3.13.4 load/store instruction extensions */
if (LDSTH_I_BIT(instr)) if (LDSTHD_I_BIT(instr))
offset.un = (instr & 0xf00) >> 4 | (instr & 15); offset.un = (instr & 0xf00) >> 4 | (instr & 15);
else else
offset.un = regs->uregs[RM_BITS(instr)]; offset.un = regs->uregs[RM_BITS(instr)];
handler = do_alignment_ldrhstrh;
if ((instr & 0x000000f0) == 0x000000b0 || /* LDRH, STRH */
(instr & 0x001000f0) == 0x001000f0) /* LDRSH */
handler = do_alignment_ldrhstrh;
else if ((instr & 0x001000f0) == 0x000000d0 || /* LDRD */
(instr & 0x001000f0) == 0x000000f0) /* STRD */
handler = do_alignment_ldrdstrd;
else
goto bad;
break; break;
case 0x04000000: /* ldr or str immediate */ case 0x04000000: /* ldr or str immediate */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment