int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs) { union offset_union offset; unsigned long instr, instrptr; int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); unsigned int type; instrptr = instruction_pointer(regs); instr = *(unsigned long *)instrptr; if (user_mode(regs)) goto user; ai_sys += 1; fixup: regs->ARM_pc += 4; switch (CODING_BITS(instr)) { case 0x00000000: /* ldrh or strh */ if (LDSTH_I_BIT(instr)) offset.un = (instr & 0xf00) >> 4 | (instr & 15); else offset.un = regs->uregs[RM_BITS(instr)]; handler = do_alignment_ldrhstrh; break; case 0x04000000: /* ldr or str immediate */ offset.un = OFFSET_BITS(instr); handler = do_alignment_ldrstr; break; case 0x06000000: /* ldr or str register */ offset.un = regs->uregs[RM_BITS(instr)]; if (IS_SHIFT(instr)) { unsigned int shiftval = SHIFT_BITS(instr); switch(SHIFT_TYPE(instr)) { case SHIFT_LSL: offset.un <<= shiftval; break; case SHIFT_LSR: offset.un >>= shiftval; break; case SHIFT_ASR: offset.sn >>= shiftval; break; case SHIFT_RORRRX: if (shiftval == 0) { offset.un >>= 1; if (regs->ARM_cpsr & PSR_C_BIT) offset.un |= 1 << 31; } else offset.un = offset.un >> shiftval | offset.un << (32 - shiftval); break; }
static int do_alignment(unsigned long addr, unsigned int error_code, struct pt_regs *regs) { union offset_union offset; unsigned long instr, instrptr; int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs); unsigned int type; if (user_mode(regs)) ai_user += 1; else ai_sys += 1; instrptr = instruction_pointer(regs); if (instrptr >= SVC_SPACE) instr = *(unsigned long *)instrptr; else { __asm__ __volatile__( "ldw.u %0, [%1]\n" :"=&r"(instr) :"r"(instrptr)); } regs->UCreg_pc += 4; switch (CODING_BITS(instr)) { case 0x40000120: /* ldrh or strh */ if (LDSTH_I_BIT(instr)) offset.un = (instr & 0x3e00) >> 4 | (instr & 31); else offset.un = regs->uregs[RM_BITS(instr)]; handler = do_alignment_ldrhstrh; break; case 0x60000000: /* ldr or str immediate */ case 0x60000100: /* ldr or str immediate */ case 0x60000020: /* ldr or str immediate */ case 0x60000120: /* ldr or str immediate */ offset.un = OFFSET_BITS(instr); handler = do_alignment_ldrstr; break; case 0x40000000: /* ldr or str register */ offset.un = regs->uregs[RM_BITS(instr)]; { unsigned int shiftval = SHIFT_BITS(instr); switch(SHIFT_TYPE(instr)) { case SHIFT_LSL: offset.un <<= shiftval; break; case SHIFT_LSR: offset.un >>= shiftval; break; case SHIFT_ASR: offset.sn >>= shiftval; break; case SHIFT_RORRRX: if (shiftval == 0) { offset.un >>= 1; if (regs->UCreg_csr & PSR_C_BIT) offset.un |= 1 << 31; } else offset.un = offset.un >> shiftval | offset.un << (32 - shiftval); break; }