arch/arm64/kernel/compat_alignment.c

Source file repositories/reference/linux-study-clean/arch/arm64/kernel/compat_alignment.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kernel/compat_alignment.c
Extension
.c
Size
10056 bytes
Lines
386
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (regbits & 1) {
			if (LDST_L_BIT(instr)) {
				if (get_user(val, (u32 __user *)eaddr))
					return TYPE_FAULT;
				if (rd < 15)
					regs->regs[rd] = val;
				else
					regs->pc = val;
			} else {
				/*
				 * The PC register has a bias of +8 in ARM mode
				 * and +4 in Thumb mode. This means that a read
				 * of the value of PC should account for this.
				 * Since Thumb does not permit STM instructions
				 * to refer to PC, just add 8 here.
				 */
				val = (rd < 15) ? regs->regs[rd] : regs->pc + 8;
				if (put_user(val, (u32 __user *)eaddr))
					return TYPE_FAULT;
			}
			eaddr += 4;
		}

	if (LDST_W_BIT(instr))
		regs->regs[rn] = newaddr;

	return TYPE_DONE;
}

/*
 * Convert Thumb multi-word load/store 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.6.1 Format 1: */
	case 0xc000 >> 11:				/* 7.1.51 STMIA */
	case 0xc800 >> 11:				/* 7.1.25 LDMIA */
		{
			u32 Rn = (tinstr & (7<<8)) >> 8;
			u32 W = ((L<<Rn) & (tinstr&255)) ? 0 : 1<<21;

			return 0xe8800000 | W | (L<<20) | (Rn<<16) |
				(tinstr&255);
		}

	/* 6.6.1 Format 2: */
	case 0xb000 >> 11:				/* 7.1.48 PUSH */
	case 0xb800 >> 11:				/* 7.1.47 POP */
		if ((tinstr & (3 << 9)) == 0x0400) {
			static const u32 subset[4] = {
				0xe92d0000,	/* STMDB sp!,{registers} */
				0xe92d4000,	/* STMDB sp!,{registers,lr} */
				0xe8bd0000,	/* LDMIA sp!,{registers} */
				0xe8bd8000	/* LDMIA sp!,{registers,pc} */
			};
			return subset[(L<<1) | ((tinstr & (1<<8)) >> 8)] |
			    (tinstr & 255);		/* register_list */
		}
		fallthrough;	/* for illegal instruction case */

	default:
		return BAD_INSTR;
	}
}

/*
 * Convert Thumb-2 32 bit LDM, STM, LDRD, STRD to equivalent instruction
 * handlable by ARM alignment handler, also find the corresponding handler,
 * so that we can reuse ARM userland alignment fault fixups for Thumb.
 *
 * @pinstr: original Thumb-2 instruction; returns new handlable instruction
 * @regs: register context.
 * @poffset: return offset from faulted addr for later writeback
 *

Annotation

Implementation Notes