cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

actions-thumb.c (19454B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * arch/arm/probes/kprobes/actions-thumb.c
      4 *
      5 * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
      6 */
      7
      8#include <linux/types.h>
      9#include <linux/kernel.h>
     10#include <linux/ptrace.h>
     11#include <linux/kprobes.h>
     12
     13#include "../decode-thumb.h"
     14#include "core.h"
     15#include "checkers.h"
     16
     17/* These emulation encodings are functionally equivalent... */
     18#define t32_emulate_rd8rn16rm0ra12_noflags \
     19		t32_emulate_rdlo12rdhi8rn16rm0_noflags
     20
     21/* t32 thumb actions */
     22
     23static void __kprobes
     24t32_simulate_table_branch(probes_opcode_t insn,
     25		struct arch_probes_insn *asi, struct pt_regs *regs)
     26{
     27	unsigned long pc = regs->ARM_pc;
     28	int rn = (insn >> 16) & 0xf;
     29	int rm = insn & 0xf;
     30
     31	unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn];
     32	unsigned long rmv = regs->uregs[rm];
     33	unsigned int halfwords;
     34
     35	if (insn & 0x10) /* TBH */
     36		halfwords = ((u16 *)rnv)[rmv];
     37	else /* TBB */
     38		halfwords = ((u8 *)rnv)[rmv];
     39
     40	regs->ARM_pc = pc + 2 * halfwords;
     41}
     42
     43static void __kprobes
     44t32_simulate_mrs(probes_opcode_t insn,
     45		struct arch_probes_insn *asi, struct pt_regs *regs)
     46{
     47	int rd = (insn >> 8) & 0xf;
     48	unsigned long mask = 0xf8ff03df; /* Mask out execution state */
     49	regs->uregs[rd] = regs->ARM_cpsr & mask;
     50}
     51
     52static void __kprobes
     53t32_simulate_cond_branch(probes_opcode_t insn,
     54		struct arch_probes_insn *asi, struct pt_regs *regs)
     55{
     56	unsigned long pc = regs->ARM_pc;
     57
     58	long offset = insn & 0x7ff;		/* imm11 */
     59	offset += (insn & 0x003f0000) >> 5;	/* imm6 */
     60	offset += (insn & 0x00002000) << 4;	/* J1 */
     61	offset += (insn & 0x00000800) << 7;	/* J2 */
     62	offset -= (insn & 0x04000000) >> 7;	/* Apply sign bit */
     63
     64	regs->ARM_pc = pc + (offset * 2);
     65}
     66
     67static enum probes_insn __kprobes
     68t32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
     69		const struct decode_header *d)
     70{
     71	int cc = (insn >> 22) & 0xf;
     72	asi->insn_check_cc = probes_condition_checks[cc];
     73	asi->insn_handler = t32_simulate_cond_branch;
     74	return INSN_GOOD_NO_SLOT;
     75}
     76
     77static void __kprobes
     78t32_simulate_branch(probes_opcode_t insn,
     79		    struct arch_probes_insn *asi, struct pt_regs *regs)
     80{
     81	unsigned long pc = regs->ARM_pc;
     82
     83	long offset = insn & 0x7ff;		/* imm11 */
     84	offset += (insn & 0x03ff0000) >> 5;	/* imm10 */
     85	offset += (insn & 0x00002000) << 9;	/* J1 */
     86	offset += (insn & 0x00000800) << 10;	/* J2 */
     87	if (insn & 0x04000000)
     88		offset -= 0x00800000; /* Apply sign bit */
     89	else
     90		offset ^= 0x00600000; /* Invert J1 and J2 */
     91
     92	if (insn & (1 << 14)) {
     93		/* BL or BLX */
     94		regs->ARM_lr = regs->ARM_pc | 1;
     95		if (!(insn & (1 << 12))) {
     96			/* BLX so switch to ARM mode */
     97			regs->ARM_cpsr &= ~PSR_T_BIT;
     98			pc &= ~3;
     99		}
    100	}
    101
    102	regs->ARM_pc = pc + (offset * 2);
    103}
    104
    105static void __kprobes
    106t32_simulate_ldr_literal(probes_opcode_t insn,
    107		struct arch_probes_insn *asi, struct pt_regs *regs)
    108{
    109	unsigned long addr = regs->ARM_pc & ~3;
    110	int rt = (insn >> 12) & 0xf;
    111	unsigned long rtv;
    112
    113	long offset = insn & 0xfff;
    114	if (insn & 0x00800000)
    115		addr += offset;
    116	else
    117		addr -= offset;
    118
    119	if (insn & 0x00400000) {
    120		/* LDR */
    121		rtv = *(unsigned long *)addr;
    122		if (rt == 15) {
    123			bx_write_pc(rtv, regs);
    124			return;
    125		}
    126	} else if (insn & 0x00200000) {
    127		/* LDRH */
    128		if (insn & 0x01000000)
    129			rtv = *(s16 *)addr;
    130		else
    131			rtv = *(u16 *)addr;
    132	} else {
    133		/* LDRB */
    134		if (insn & 0x01000000)
    135			rtv = *(s8 *)addr;
    136		else
    137			rtv = *(u8 *)addr;
    138	}
    139
    140	regs->uregs[rt] = rtv;
    141}
    142
    143static enum probes_insn __kprobes
    144t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
    145		const struct decode_header *d)
    146{
    147	enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
    148
    149	/* Fixup modified instruction to have halfwords in correct order...*/
    150	insn = __mem_to_opcode_arm(asi->insn[0]);
    151	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
    152	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
    153
    154	return ret;
    155}
    156
    157static void __kprobes
    158t32_emulate_ldrdstrd(probes_opcode_t insn,
    159		struct arch_probes_insn *asi, struct pt_regs *regs)
    160{
    161	unsigned long pc = regs->ARM_pc & ~3;
    162	int rt1 = (insn >> 12) & 0xf;
    163	int rt2 = (insn >> 8) & 0xf;
    164	int rn = (insn >> 16) & 0xf;
    165
    166	register unsigned long rt1v asm("r0") = regs->uregs[rt1];
    167	register unsigned long rt2v asm("r1") = regs->uregs[rt2];
    168	register unsigned long rnv asm("r2") = (rn == 15) ? pc
    169							  : regs->uregs[rn];
    170
    171	__asm__ __volatile__ (
    172		"blx    %[fn]"
    173		: "=r" (rt1v), "=r" (rt2v), "=r" (rnv)
    174		: "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn)
    175		: "lr", "memory", "cc"
    176	);
    177
    178	if (rn != 15)
    179		regs->uregs[rn] = rnv; /* Writeback base register */
    180	regs->uregs[rt1] = rt1v;
    181	regs->uregs[rt2] = rt2v;
    182}
    183
    184static void __kprobes
    185t32_emulate_ldrstr(probes_opcode_t insn,
    186		struct arch_probes_insn *asi, struct pt_regs *regs)
    187{
    188	int rt = (insn >> 12) & 0xf;
    189	int rn = (insn >> 16) & 0xf;
    190	int rm = insn & 0xf;
    191
    192	register unsigned long rtv asm("r0") = regs->uregs[rt];
    193	register unsigned long rnv asm("r2") = regs->uregs[rn];
    194	register unsigned long rmv asm("r3") = regs->uregs[rm];
    195
    196	__asm__ __volatile__ (
    197		"blx    %[fn]"
    198		: "=r" (rtv), "=r" (rnv)
    199		: "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
    200		: "lr", "memory", "cc"
    201	);
    202
    203	regs->uregs[rn] = rnv; /* Writeback base register */
    204	if (rt == 15) /* Can't be true for a STR as they aren't allowed */
    205		bx_write_pc(rtv, regs);
    206	else
    207		regs->uregs[rt] = rtv;
    208}
    209
    210static void __kprobes
    211t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn,
    212		struct arch_probes_insn *asi, struct pt_regs *regs)
    213{
    214	int rd = (insn >> 8) & 0xf;
    215	int rn = (insn >> 16) & 0xf;
    216	int rm = insn & 0xf;
    217
    218	register unsigned long rdv asm("r1") = regs->uregs[rd];
    219	register unsigned long rnv asm("r2") = regs->uregs[rn];
    220	register unsigned long rmv asm("r3") = regs->uregs[rm];
    221	unsigned long cpsr = regs->ARM_cpsr;
    222
    223	__asm__ __volatile__ (
    224		"msr	cpsr_fs, %[cpsr]	\n\t"
    225		"blx    %[fn]			\n\t"
    226		"mrs	%[cpsr], cpsr		\n\t"
    227		: "=r" (rdv), [cpsr] "=r" (cpsr)
    228		: "0" (rdv), "r" (rnv), "r" (rmv),
    229		  "1" (cpsr), [fn] "r" (asi->insn_fn)
    230		: "lr", "memory", "cc"
    231	);
    232
    233	regs->uregs[rd] = rdv;
    234	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
    235}
    236
    237static void __kprobes
    238t32_emulate_rd8pc16_noflags(probes_opcode_t insn,
    239		struct arch_probes_insn *asi, struct pt_regs *regs)
    240{
    241	unsigned long pc = regs->ARM_pc;
    242	int rd = (insn >> 8) & 0xf;
    243
    244	register unsigned long rdv asm("r1") = regs->uregs[rd];
    245	register unsigned long rnv asm("r2") = pc & ~3;
    246
    247	__asm__ __volatile__ (
    248		"blx    %[fn]"
    249		: "=r" (rdv)
    250		: "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
    251		: "lr", "memory", "cc"
    252	);
    253
    254	regs->uregs[rd] = rdv;
    255}
    256
    257static void __kprobes
    258t32_emulate_rd8rn16_noflags(probes_opcode_t insn,
    259		struct arch_probes_insn *asi, struct pt_regs *regs)
    260{
    261	int rd = (insn >> 8) & 0xf;
    262	int rn = (insn >> 16) & 0xf;
    263
    264	register unsigned long rdv asm("r1") = regs->uregs[rd];
    265	register unsigned long rnv asm("r2") = regs->uregs[rn];
    266
    267	__asm__ __volatile__ (
    268		"blx    %[fn]"
    269		: "=r" (rdv)
    270		: "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
    271		: "lr", "memory", "cc"
    272	);
    273
    274	regs->uregs[rd] = rdv;
    275}
    276
    277static void __kprobes
    278t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn,
    279		struct arch_probes_insn *asi,
    280		struct pt_regs *regs)
    281{
    282	int rdlo = (insn >> 12) & 0xf;
    283	int rdhi = (insn >> 8) & 0xf;
    284	int rn = (insn >> 16) & 0xf;
    285	int rm = insn & 0xf;
    286
    287	register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
    288	register unsigned long rdhiv asm("r1") = regs->uregs[rdhi];
    289	register unsigned long rnv asm("r2") = regs->uregs[rn];
    290	register unsigned long rmv asm("r3") = regs->uregs[rm];
    291
    292	__asm__ __volatile__ (
    293		"blx    %[fn]"
    294		: "=r" (rdlov), "=r" (rdhiv)
    295		: "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
    296		  [fn] "r" (asi->insn_fn)
    297		: "lr", "memory", "cc"
    298	);
    299
    300	regs->uregs[rdlo] = rdlov;
    301	regs->uregs[rdhi] = rdhiv;
    302}
    303/* t16 thumb actions */
    304
    305static void __kprobes
    306t16_simulate_bxblx(probes_opcode_t insn,
    307		struct arch_probes_insn *asi, struct pt_regs *regs)
    308{
    309	unsigned long pc = regs->ARM_pc + 2;
    310	int rm = (insn >> 3) & 0xf;
    311	unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm];
    312
    313	if (insn & (1 << 7)) /* BLX ? */
    314		regs->ARM_lr = regs->ARM_pc | 1;
    315
    316	bx_write_pc(rmv, regs);
    317}
    318
    319static void __kprobes
    320t16_simulate_ldr_literal(probes_opcode_t insn,
    321		struct arch_probes_insn *asi, struct pt_regs *regs)
    322{
    323	unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3);
    324	long index = insn & 0xff;
    325	int rt = (insn >> 8) & 0x7;
    326	regs->uregs[rt] = base[index];
    327}
    328
    329static void __kprobes
    330t16_simulate_ldrstr_sp_relative(probes_opcode_t insn,
    331		struct arch_probes_insn *asi, struct pt_regs *regs)
    332{
    333	unsigned long* base = (unsigned long *)regs->ARM_sp;
    334	long index = insn & 0xff;
    335	int rt = (insn >> 8) & 0x7;
    336	if (insn & 0x800) /* LDR */
    337		regs->uregs[rt] = base[index];
    338	else /* STR */
    339		base[index] = regs->uregs[rt];
    340}
    341
    342static void __kprobes
    343t16_simulate_reladr(probes_opcode_t insn,
    344		struct arch_probes_insn *asi, struct pt_regs *regs)
    345{
    346	unsigned long base = (insn & 0x800) ? regs->ARM_sp
    347					    : ((regs->ARM_pc + 2) & ~3);
    348	long offset = insn & 0xff;
    349	int rt = (insn >> 8) & 0x7;
    350	regs->uregs[rt] = base + offset * 4;
    351}
    352
    353static void __kprobes
    354t16_simulate_add_sp_imm(probes_opcode_t insn,
    355		struct arch_probes_insn *asi, struct pt_regs *regs)
    356{
    357	long imm = insn & 0x7f;
    358	if (insn & 0x80) /* SUB */
    359		regs->ARM_sp -= imm * 4;
    360	else /* ADD */
    361		regs->ARM_sp += imm * 4;
    362}
    363
    364static void __kprobes
    365t16_simulate_cbz(probes_opcode_t insn,
    366		struct arch_probes_insn *asi, struct pt_regs *regs)
    367{
    368	int rn = insn & 0x7;
    369	probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn;
    370	if (nonzero & 0x800) {
    371		long i = insn & 0x200;
    372		long imm5 = insn & 0xf8;
    373		unsigned long pc = regs->ARM_pc + 2;
    374		regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2);
    375	}
    376}
    377
    378static void __kprobes
    379t16_simulate_it(probes_opcode_t insn,
    380		struct arch_probes_insn *asi, struct pt_regs *regs)
    381{
    382	/*
    383	 * The 8 IT state bits are split into two parts in CPSR:
    384	 *	ITSTATE<1:0> are in CPSR<26:25>
    385	 *	ITSTATE<7:2> are in CPSR<15:10>
    386	 * The new IT state is in the lower byte of insn.
    387	 */
    388	unsigned long cpsr = regs->ARM_cpsr;
    389	cpsr &= ~PSR_IT_MASK;
    390	cpsr |= (insn & 0xfc) << 8;
    391	cpsr |= (insn & 0x03) << 25;
    392	regs->ARM_cpsr = cpsr;
    393}
    394
    395static void __kprobes
    396t16_singlestep_it(probes_opcode_t insn,
    397		  struct arch_probes_insn *asi, struct pt_regs *regs)
    398{
    399	regs->ARM_pc += 2;
    400	t16_simulate_it(insn, asi, regs);
    401}
    402
    403static enum probes_insn __kprobes
    404t16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi,
    405		const struct decode_header *d)
    406{
    407	asi->insn_singlestep = t16_singlestep_it;
    408	return INSN_GOOD_NO_SLOT;
    409}
    410
    411static void __kprobes
    412t16_simulate_cond_branch(probes_opcode_t insn,
    413		struct arch_probes_insn *asi, struct pt_regs *regs)
    414{
    415	unsigned long pc = regs->ARM_pc + 2;
    416	long offset = insn & 0x7f;
    417	offset -= insn & 0x80; /* Apply sign bit */
    418	regs->ARM_pc = pc + (offset * 2);
    419}
    420
    421static enum probes_insn __kprobes
    422t16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
    423		const struct decode_header *d)
    424{
    425	int cc = (insn >> 8) & 0xf;
    426	asi->insn_check_cc = probes_condition_checks[cc];
    427	asi->insn_handler = t16_simulate_cond_branch;
    428	return INSN_GOOD_NO_SLOT;
    429}
    430
    431static void __kprobes
    432t16_simulate_branch(probes_opcode_t insn,
    433		   struct arch_probes_insn *asi, struct pt_regs *regs)
    434{
    435	unsigned long pc = regs->ARM_pc + 2;
    436	long offset = insn & 0x3ff;
    437	offset -= insn & 0x400; /* Apply sign bit */
    438	regs->ARM_pc = pc + (offset * 2);
    439}
    440
    441static unsigned long __kprobes
    442t16_emulate_loregs(probes_opcode_t insn,
    443		   struct arch_probes_insn *asi, struct pt_regs *regs)
    444{
    445	unsigned long oldcpsr = regs->ARM_cpsr;
    446	unsigned long newcpsr;
    447
    448	__asm__ __volatile__ (
    449		"msr	cpsr_fs, %[oldcpsr]	\n\t"
    450		"mov	r11, r7			\n\t"
    451		"ldmia	%[regs], {r0-r7}	\n\t"
    452		"blx	%[fn]			\n\t"
    453		"stmia	%[regs], {r0-r7}	\n\t"
    454		"mov	r7, r11			\n\t"
    455		"mrs	%[newcpsr], cpsr	\n\t"
    456		: [newcpsr] "=r" (newcpsr)
    457		: [oldcpsr] "r" (oldcpsr), [regs] "r" (regs),
    458		  [fn] "r" (asi->insn_fn)
    459		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r11",
    460		  "lr", "memory", "cc"
    461		);
    462
    463	return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK);
    464}
    465
    466static void __kprobes
    467t16_emulate_loregs_rwflags(probes_opcode_t insn,
    468		struct arch_probes_insn *asi, struct pt_regs *regs)
    469{
    470	regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs);
    471}
    472
    473static void __kprobes
    474t16_emulate_loregs_noitrwflags(probes_opcode_t insn,
    475		struct arch_probes_insn *asi, struct pt_regs *regs)
    476{
    477	unsigned long cpsr = t16_emulate_loregs(insn, asi, regs);
    478	if (!in_it_block(cpsr))
    479		regs->ARM_cpsr = cpsr;
    480}
    481
    482static void __kprobes
    483t16_emulate_hiregs(probes_opcode_t insn,
    484		struct arch_probes_insn *asi, struct pt_regs *regs)
    485{
    486	unsigned long pc = regs->ARM_pc + 2;
    487	int rdn = (insn & 0x7) | ((insn & 0x80) >> 4);
    488	int rm = (insn >> 3) & 0xf;
    489
    490	register unsigned long rdnv asm("r1");
    491	register unsigned long rmv asm("r0");
    492	unsigned long cpsr = regs->ARM_cpsr;
    493
    494	rdnv = (rdn == 15) ? pc : regs->uregs[rdn];
    495	rmv = (rm == 15) ? pc : regs->uregs[rm];
    496
    497	__asm__ __volatile__ (
    498		"msr	cpsr_fs, %[cpsr]	\n\t"
    499		"blx    %[fn]			\n\t"
    500		"mrs	%[cpsr], cpsr		\n\t"
    501		: "=r" (rdnv), [cpsr] "=r" (cpsr)
    502		: "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn)
    503		: "lr", "memory", "cc"
    504	);
    505
    506	if (rdn == 15)
    507		rdnv &= ~1;
    508
    509	regs->uregs[rdn] = rdnv;
    510	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
    511}
    512
    513static enum probes_insn __kprobes
    514t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
    515		const struct decode_header *d)
    516{
    517	insn &= ~0x00ff;
    518	insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
    519	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
    520	asi->insn_handler = t16_emulate_hiregs;
    521	return INSN_GOOD;
    522}
    523
    524static void __kprobes
    525t16_emulate_push(probes_opcode_t insn,
    526		struct arch_probes_insn *asi, struct pt_regs *regs)
    527{
    528	__asm__ __volatile__ (
    529		"mov	r11, r7			\n\t"
    530		"ldr	r9, [%[regs], #13*4]	\n\t"
    531		"ldr	r8, [%[regs], #14*4]	\n\t"
    532		"ldmia	%[regs], {r0-r7}	\n\t"
    533		"blx	%[fn]			\n\t"
    534		"str	r9, [%[regs], #13*4]	\n\t"
    535		"mov	r7, r11			\n\t"
    536		:
    537		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
    538		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r11",
    539		  "lr", "memory", "cc"
    540		);
    541}
    542
    543static enum probes_insn __kprobes
    544t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
    545		const struct decode_header *d)
    546{
    547	/*
    548	 * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
    549	 * and call it with R9=SP and LR in the register list represented
    550	 * by R8.
    551	 */
    552	/* 1st half STMDB R9!,{} */
    553	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
    554	/* 2nd half (register list) */
    555	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
    556	asi->insn_handler = t16_emulate_push;
    557	return INSN_GOOD;
    558}
    559
    560static void __kprobes
    561t16_emulate_pop_nopc(probes_opcode_t insn,
    562		struct arch_probes_insn *asi, struct pt_regs *regs)
    563{
    564	__asm__ __volatile__ (
    565		"mov	r11, r7			\n\t"
    566		"ldr	r9, [%[regs], #13*4]	\n\t"
    567		"ldmia	%[regs], {r0-r7}	\n\t"
    568		"blx	%[fn]			\n\t"
    569		"stmia	%[regs], {r0-r7}	\n\t"
    570		"str	r9, [%[regs], #13*4]	\n\t"
    571		"mov	r7, r11			\n\t"
    572		:
    573		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
    574		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9", "r11",
    575		  "lr", "memory", "cc"
    576		);
    577}
    578
    579static void __kprobes
    580t16_emulate_pop_pc(probes_opcode_t insn,
    581		struct arch_probes_insn *asi, struct pt_regs *regs)
    582{
    583	register unsigned long pc asm("r8");
    584
    585	__asm__ __volatile__ (
    586		"mov	r11, r7			\n\t"
    587		"ldr	r9, [%[regs], #13*4]	\n\t"
    588		"ldmia	%[regs], {r0-r7}	\n\t"
    589		"blx	%[fn]			\n\t"
    590		"stmia	%[regs], {r0-r7}	\n\t"
    591		"str	r9, [%[regs], #13*4]	\n\t"
    592		"mov	r7, r11			\n\t"
    593		: "=r" (pc)
    594		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
    595		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9", "r11",
    596		  "lr", "memory", "cc"
    597		);
    598
    599	bx_write_pc(pc, regs);
    600}
    601
    602static enum probes_insn __kprobes
    603t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
    604		const struct decode_header *d)
    605{
    606	/*
    607	 * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
    608	 * and call it with R9=SP and PC in the register list represented
    609	 * by R8.
    610	 */
    611	/* 1st half LDMIA R9!,{} */
    612	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
    613	/* 2nd half (register list) */
    614	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
    615	asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
    616					 : t16_emulate_pop_nopc;
    617	return INSN_GOOD;
    618}
    619
    620const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
    621	[PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm},
    622	[PROBES_T16_CBZ] = {.handler = t16_simulate_cbz},
    623	[PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags},
    624	[PROBES_T16_PUSH] = {.decoder = t16_decode_push},
    625	[PROBES_T16_POP] = {.decoder = t16_decode_pop},
    626	[PROBES_T16_SEV] = {.handler = probes_emulate_none},
    627	[PROBES_T16_WFE] = {.handler = probes_simulate_nop},
    628	[PROBES_T16_IT] = {.decoder = t16_decode_it},
    629	[PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags},
    630	[PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags},
    631	[PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags},
    632	[PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal},
    633	[PROBES_T16_BLX] = {.handler = t16_simulate_bxblx},
    634	[PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs},
    635	[PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags},
    636	[PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative},
    637	[PROBES_T16_ADR] = {.handler = t16_simulate_reladr},
    638	[PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags},
    639	[PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch},
    640	[PROBES_T16_BRANCH] = {.handler = t16_simulate_branch},
    641};
    642
    643const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
    644	[PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm},
    645	[PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd},
    646	[PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch},
    647	[PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    648	[PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    649	[PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    650	[PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    651	[PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    652	[PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,},
    653	[PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags},
    654	[PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags},
    655	[PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    656	[PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags},
    657	[PROBES_T32_SEV] = {.handler = probes_emulate_none},
    658	[PROBES_T32_WFE] = {.handler = probes_simulate_nop},
    659	[PROBES_T32_MRS] = {.handler = t32_simulate_mrs},
    660	[PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch},
    661	[PROBES_T32_BRANCH] = {.handler = t32_simulate_branch},
    662	[PROBES_T32_PLDI] = {.handler = probes_simulate_nop},
    663	[PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal},
    664	[PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr},
    665	[PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    666	[PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    667	[PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags},
    668	[PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
    669	[PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags},
    670	[PROBES_T32_MUL_ADD_LONG] = {
    671		.handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
    672};
    673
    674const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL};
    675const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL};