| 
					
				 | 
			
			
				@@ -531,3 +531,110 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if (regbits & 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				if (LDST_L_BIT(instr)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					unsigned int val; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					get32t_unaligned_check(val, eaddr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					regs->uregs[rd] = val; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					put32t_unaligned_check(regs->uregs[rd], eaddr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				eaddr += 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		for (regbits = REGMASK_BITS(instr), rd = 0; regbits; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		     regbits >>= 1, rd += 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (regbits & 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (LDST_L_BIT(instr)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					unsigned int val; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					get32_unaligned_check(val, eaddr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					regs->uregs[rd] = val; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					put32_unaligned_check(regs->uregs[rd], eaddr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				eaddr += 4; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (LDST_W_BIT(instr)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		regs->uregs[rn] = newaddr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (!LDST_L_BIT(instr) || !(REGMASK_BITS(instr) & (1 << 15))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		regs->ARM_pc -= correction; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return TYPE_DONE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+fault: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	regs->ARM_pc -= correction; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return TYPE_FAULT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+bad: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	printk(KERN_ERR "Alignment trap: not handling ldm with s-bit set\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return TYPE_ERROR; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Convert Thumb ld/st instruction forms to equivalent ARM instructions so 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * we can reuse ARM userland alignment fault fixups for Thumb. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * This implementation was initially based on the algorithm found in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * gdb/sim/arm/thumbemu.c. It is basically just a code reduction of same 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * to convert only Thumb ld/st instruction forms to equivalent ARM forms. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * NOTES: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 1. Comments below refer to ARM ARM DDI0100E Thumb Instruction sections. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 2. If for some reason we're passed an non-ld/st Thumb instruction to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *    decode, we return 0xdeadc0de. This should never happen under normal 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *    circumstances but if it does, we've got other problems to deal with 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *    elsewhere and we obviously can't fix those problems here. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static unsigned long 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+thumb2arm(u16 tinstr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	u32 L = (tinstr & (1<<11)) >> 11; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	switch ((tinstr & 0xf800) >> 11) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 6.5.1 Format 1: */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x6000 >> 11:				/* 7.1.52 STR(1) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x6800 >> 11:				/* 7.1.26 LDR(1) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x7000 >> 11:				/* 7.1.55 STRB(1) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x7800 >> 11:				/* 7.1.30 LDRB(1) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0xe5800000 | 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (1<<12)) << (22-12)) |	/* fixup */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			(L<<20) |				/* L==1? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (7<<0)) << (12-0)) |		/* Rd */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (7<<3)) << (16-3)) |		/* Rn */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (31<<6)) >>			/* immed_5 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				(6 - ((tinstr & (1<<12)) ? 0 : 2))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x8000 >> 11:				/* 7.1.57 STRH(1) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x8800 >> 11:				/* 7.1.32 LDRH(1) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0xe1c000b0 | 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			(L<<20) |				/* L==1? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (7<<0)) << (12-0)) |		/* Rd */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (7<<3)) << (16-3)) |		/* Rn */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (7<<6)) >> (6-1)) |	 /* immed_5[2:0] */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			((tinstr & (3<<9)) >> (9-8));	 /* immed_5[4:3] */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 6.5.1 Format 2: */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x5000 >> 11: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x5800 >> 11: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			static const u32 subset[8] = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe7800000,		/* 7.1.53 STR(2) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe18000b0,		/* 7.1.58 STRH(2) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe7c00000,		/* 7.1.56 STRB(2) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe19000d0,		/* 7.1.34 LDRSB */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe7900000,		/* 7.1.27 LDR(2) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe19000b0,		/* 7.1.33 LDRH(2) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe7d00000,		/* 7.1.31 LDRB(2) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				0xe19000f0		/* 7.1.35 LDRSH */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return subset[(tinstr & (7<<9)) >> 9] | 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			    ((tinstr & (7<<0)) << (12-0)) |	/* Rd */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			    ((tinstr & (7<<3)) << (16-3)) |	/* Rn */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			    ((tinstr & (7<<6)) >> (6-0));	/* Rm */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	/* 6.5.1 Format 3: */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case 0x4800 >> 11:				/* 7.1.28 LDR(3) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		/* NOTE: This case is not technically possible. We're 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 *	 loading 32-bit memory data via PC relative 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 *	 addressing mode. So we can and should eliminate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 *	 this case. But I'll leave it here for now. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0xe59f0000 | 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		    ((tinstr & (7<<8)) << (12-8)) |		/* Rd */ 
			 |