12437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst/*
22437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst * arch/arm/kernel/kprobes-thumb.c
32437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst *
42437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
52437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst *
62437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst * This program is free software; you can redistribute it and/or modify
72437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst * it under the terms of the GNU General Public License version 2 as
82437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst * published by the Free Software Foundation.
92437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst */
102437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst
1187abef63ead5ac9e2c67f0c07c461eda6be16aebDavid A. Long#include <linux/types.h>
122437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst#include <linux/kernel.h>
1387abef63ead5ac9e2c67f0c07c461eda6be16aebDavid A. Long#include <linux/ptrace.h>
142437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst#include <linux/kprobes.h>
152437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst
162437170710c4a3dee137a65623960aa7ac82a32eJon Medhurst#include "kprobes.h"
1787abef63ead5ac9e2c67f0c07c461eda6be16aebDavid A. Long#include "probes-thumb.h"
18eaf4f33feca2704ad1d06f1ef6b427712c506cc0Jon Medhurst
193e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long/* These emulation encodings are functionally equivalent... */
203e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long#define t32_emulate_rd8rn16rm0ra12_noflags \
213e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		t32_emulate_rdlo12rdhi8rn16rm0_noflags
223e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long
2387abef63ead5ac9e2c67f0c07c461eda6be16aebDavid A. Long/* t32 thumb actions */
2487abef63ead5ac9e2c67f0c07c461eda6be16aebDavid A. Long
253e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
26f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_simulate_table_branch(probes_opcode_t insn,
27b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
28dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst{
297579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc;
30dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst	int rn = (insn >> 16) & 0xf;
31dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst	int rm = insn & 0xf;
32dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst
33dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst	unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn];
34dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst	unsigned long rmv = regs->uregs[rm];
35dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst	unsigned int halfwords;
36dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst
37ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	if (insn & 0x10) /* TBH */
38dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst		halfwords = ((u16 *)rnv)[rmv];
39ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	else /* TBB */
40dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst		halfwords = ((u8 *)rnv)[rmv];
41dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst
42dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst	regs->ARM_pc = pc + 2 * halfwords;
43dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst}
44dd212bd3cbd337f8f3bd6b30929bef5a8c8ba81bJon Medhurst
453e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
46f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_simulate_mrs(probes_opcode_t insn,
47b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
48b06f3ee34d8b817d566d15d25a21f8320b3f7c57Jon Medhurst{
49b06f3ee34d8b817d566d15d25a21f8320b3f7c57Jon Medhurst	int rd = (insn >> 8) & 0xf;
50b06f3ee34d8b817d566d15d25a21f8320b3f7c57Jon Medhurst	unsigned long mask = 0xf8ff03df; /* Mask out execution state */
51b06f3ee34d8b817d566d15d25a21f8320b3f7c57Jon Medhurst	regs->uregs[rd] = regs->ARM_cpsr & mask;
52b06f3ee34d8b817d566d15d25a21f8320b3f7c57Jon Medhurst}
53b06f3ee34d8b817d566d15d25a21f8320b3f7c57Jon Medhurst
543e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
55f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_simulate_cond_branch(probes_opcode_t insn,
56b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
57ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst{
587579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc;
59ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
60ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	long offset = insn & 0x7ff;		/* imm11 */
61ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	offset += (insn & 0x003f0000) >> 5;	/* imm6 */
62ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	offset += (insn & 0x00002000) << 4;	/* J1 */
63ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	offset += (insn & 0x00000800) << 7;	/* J2 */
64ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	offset -= (insn & 0x04000000) >> 7;	/* Apply sign bit */
65ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
66ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	regs->ARM_pc = pc + (offset * 2);
67ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst}
68ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
6944a0a59c535004eac9f18210cb2ce10b23861630David A. Longstatic enum probes_insn __kprobes
70b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Longt32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
713e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		const struct decode_header *d)
72ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst{
73ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	int cc = (insn >> 22) & 0xf;
74f145d664df502585618b12ed68c681f82153e02aDavid A. Long	asi->insn_check_cc = probes_condition_checks[cc];
75ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	asi->insn_handler = t32_simulate_cond_branch;
76ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	return INSN_GOOD_NO_SLOT;
77ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst}
78ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
793e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
80f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_simulate_branch(probes_opcode_t insn,
81b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		    struct arch_probes_insn *asi, struct pt_regs *regs)
82ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst{
837579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc;
84ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
85ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	long offset = insn & 0x7ff;		/* imm11 */
86ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	offset += (insn & 0x03ff0000) >> 5;	/* imm10 */
87ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	offset += (insn & 0x00002000) << 9;	/* J1 */
88ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	offset += (insn & 0x00000800) << 10;	/* J2 */
89ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	if (insn & 0x04000000)
90ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst		offset -= 0x00800000; /* Apply sign bit */
91ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	else
92ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst		offset ^= 0x00600000; /* Invert J1 and J2 */
93ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
94ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	if (insn & (1 << 14)) {
95ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst		/* BL or BLX */
967579f4b3764337b39087d10496af0e741cbfe570David A. Long		regs->ARM_lr = regs->ARM_pc | 1;
97ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst		if (!(insn & (1 << 12))) {
98ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst			/* BLX so switch to ARM mode */
99ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst			regs->ARM_cpsr &= ~PSR_T_BIT;
100ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst			pc &= ~3;
101ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst		}
102ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	}
103ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
104ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst	regs->ARM_pc = pc + (offset * 2);
105ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst}
106ce715c772f0124f9d3f6f5cffcb85688c81d2c07Jon Medhurst
1073e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
108f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_simulate_ldr_literal(probes_opcode_t insn,
109b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
110d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst{
1117579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long addr = regs->ARM_pc & ~3;
112d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	int rt = (insn >> 12) & 0xf;
113d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	unsigned long rtv;
114d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
115d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	long offset = insn & 0xfff;
116d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	if (insn & 0x00800000)
117d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		addr += offset;
118d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	else
119d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		addr -= offset;
120d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
121d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	if (insn & 0x00400000) {
122d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		/* LDR */
123d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		rtv = *(unsigned long *)addr;
124d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		if (rt == 15) {
125d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst			bx_write_pc(rtv, regs);
126d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst			return;
127d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		}
128d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	} else if (insn & 0x00200000) {
129d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		/* LDRH */
130d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		if (insn & 0x01000000)
131d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst			rtv = *(s16 *)addr;
132d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		else
133d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst			rtv = *(u16 *)addr;
134d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	} else {
135d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		/* LDRB */
136d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		if (insn & 0x01000000)
137d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst			rtv = *(s8 *)addr;
138d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		else
139d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst			rtv = *(u8 *)addr;
140d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	}
141d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
142d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	regs->uregs[rt] = rtv;
143d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst}
144d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
14544a0a59c535004eac9f18210cb2ce10b23861630David A. Longstatic enum probes_insn __kprobes
146b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Longt32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
1473e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		const struct decode_header *d)
148eaf1d06500c48109dcd37b7856773fdf608a8d21Jon Medhurst{
14944a0a59c535004eac9f18210cb2ce10b23861630David A. Long	enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
150eaf1d06500c48109dcd37b7856773fdf608a8d21Jon Medhurst
151eaf1d06500c48109dcd37b7856773fdf608a8d21Jon Medhurst	/* Fixup modified instruction to have halfwords in correct order...*/
152888be25402021a425da3e85e2d5a954d7509286eBen Dooks	insn = __mem_to_opcode_arm(asi->insn[0]);
153888be25402021a425da3e85e2d5a954d7509286eBen Dooks	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
154888be25402021a425da3e85e2d5a954d7509286eBen Dooks	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
155eaf1d06500c48109dcd37b7856773fdf608a8d21Jon Medhurst
156eaf1d06500c48109dcd37b7856773fdf608a8d21Jon Medhurst	return ret;
157eaf1d06500c48109dcd37b7856773fdf608a8d21Jon Medhurst}
158eaf1d06500c48109dcd37b7856773fdf608a8d21Jon Medhurst
1593e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
160f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_emulate_ldrdstrd(probes_opcode_t insn,
161b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
162b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst{
1637579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc & ~3;
164b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	int rt1 = (insn >> 12) & 0xf;
165b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	int rt2 = (insn >> 8) & 0xf;
166b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	int rn = (insn >> 16) & 0xf;
167b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst
168b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	register unsigned long rt1v asm("r0") = regs->uregs[rt1];
169b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	register unsigned long rt2v asm("r1") = regs->uregs[rt2];
170b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	register unsigned long rnv asm("r2") = (rn == 15) ? pc
171b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst							  : regs->uregs[rn];
172b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst
173b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	__asm__ __volatile__ (
174b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst		"blx    %[fn]"
175b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst		: "=r" (rt1v), "=r" (rt2v), "=r" (rnv)
1767579f4b3764337b39087d10496af0e741cbfe570David A. Long		: "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn)
177b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst		: "lr", "memory", "cc"
178b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	);
179b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst
180b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	if (rn != 15)
181b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst		regs->uregs[rn] = rnv; /* Writeback base register */
182b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	regs->uregs[rt1] = rt1v;
183b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst	regs->uregs[rt2] = rt2v;
184b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst}
185b48354d3584e93284fba2ee99f6f9f44d18e4f83Jon Medhurst
1863e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
187f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_emulate_ldrstr(probes_opcode_t insn,
188b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
189d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst{
190d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	int rt = (insn >> 12) & 0xf;
191d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	int rn = (insn >> 16) & 0xf;
192d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	int rm = insn & 0xf;
193d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
194d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	register unsigned long rtv asm("r0") = regs->uregs[rt];
195d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	register unsigned long rnv asm("r2") = regs->uregs[rn];
196d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	register unsigned long rmv asm("r3") = regs->uregs[rm];
197d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
198d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	__asm__ __volatile__ (
199d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		"blx    %[fn]"
200d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		: "=r" (rtv), "=r" (rnv)
2017579f4b3764337b39087d10496af0e741cbfe570David A. Long		: "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
202d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		: "lr", "memory", "cc"
203d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	);
204d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
205d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	regs->uregs[rn] = rnv; /* Writeback base register */
206d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	if (rt == 15) /* Can't be true for a STR as they aren't allowed */
207d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		bx_write_pc(rtv, regs);
208d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst	else
209d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst		regs->uregs[rt] = rtv;
210d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst}
211d691023b62bdf33ed84023330f4d2c77d2325b01Jon Medhurst
2123e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
213f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn,
214b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
215080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst{
216080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	int rd = (insn >> 8) & 0xf;
217080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	int rn = (insn >> 16) & 0xf;
218080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	int rm = insn & 0xf;
219080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst
220080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	register unsigned long rdv asm("r1") = regs->uregs[rd];
221080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	register unsigned long rnv asm("r2") = regs->uregs[rn];
222080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	register unsigned long rmv asm("r3") = regs->uregs[rm];
223080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	unsigned long cpsr = regs->ARM_cpsr;
224080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst
225080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	__asm__ __volatile__ (
226080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst		"msr	cpsr_fs, %[cpsr]	\n\t"
227080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst		"blx    %[fn]			\n\t"
228080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst		"mrs	%[cpsr], cpsr		\n\t"
229080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst		: "=r" (rdv), [cpsr] "=r" (cpsr)
230080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst		: "0" (rdv), "r" (rnv), "r" (rmv),
2317579f4b3764337b39087d10496af0e741cbfe570David A. Long		  "1" (cpsr), [fn] "r" (asi->insn_fn)
232080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst		: "lr", "memory", "cc"
233080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	);
234080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst
235080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	regs->uregs[rd] = rdv;
236080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
237080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst}
238080e0013269e9fd428fd834e8a915a80fe6c8ae9Jon Medhurst
2393e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
240f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_emulate_rd8pc16_noflags(probes_opcode_t insn,
241b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
2427848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst{
2437579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc;
2447848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	int rd = (insn >> 8) & 0xf;
2457848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2467848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	register unsigned long rdv asm("r1") = regs->uregs[rd];
2477848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	register unsigned long rnv asm("r2") = pc & ~3;
2487848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2497848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	__asm__ __volatile__ (
2507848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst		"blx    %[fn]"
2517848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst		: "=r" (rdv)
2527579f4b3764337b39087d10496af0e741cbfe570David A. Long		: "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
2537848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst		: "lr", "memory", "cc"
2547848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	);
2557848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2567848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	regs->uregs[rd] = rdv;
2577848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst}
2587848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2593e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
260f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_emulate_rd8rn16_noflags(probes_opcode_t insn,
261b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
2627848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst{
2637848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	int rd = (insn >> 8) & 0xf;
2647848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	int rn = (insn >> 16) & 0xf;
2657848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2667848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	register unsigned long rdv asm("r1") = regs->uregs[rd];
2677848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	register unsigned long rnv asm("r2") = regs->uregs[rn];
2687848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2697848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	__asm__ __volatile__ (
2707848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst		"blx    %[fn]"
2717848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst		: "=r" (rdv)
2727579f4b3764337b39087d10496af0e741cbfe570David A. Long		: "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
2737848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst		: "lr", "memory", "cc"
2747848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	);
2757848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2767848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst	regs->uregs[rd] = rdv;
2777848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst}
2787848786a7a198dd5e097330ad0cbfdf155a25499Jon Medhurst
2793e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
280f145d664df502585618b12ed68c681f82153e02aDavid A. Longt32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn,
281b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi,
2827579f4b3764337b39087d10496af0e741cbfe570David A. Long		struct pt_regs *regs)
283231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst{
284231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	int rdlo = (insn >> 12) & 0xf;
285231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	int rdhi = (insn >> 8) & 0xf;
286231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	int rn = (insn >> 16) & 0xf;
287231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	int rm = insn & 0xf;
288231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst
289231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
290231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	register unsigned long rdhiv asm("r1") = regs->uregs[rdhi];
291231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	register unsigned long rnv asm("r2") = regs->uregs[rn];
292231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	register unsigned long rmv asm("r3") = regs->uregs[rm];
293231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst
294231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	__asm__ __volatile__ (
295231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst		"blx    %[fn]"
296231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst		: "=r" (rdlov), "=r" (rdhiv)
297231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst		: "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
2987579f4b3764337b39087d10496af0e741cbfe570David A. Long		  [fn] "r" (asi->insn_fn)
299231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst		: "lr", "memory", "cc"
300231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	);
301231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst
302231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	regs->uregs[rdlo] = rdlov;
303231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst	regs->uregs[rdhi] = rdhiv;
304231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst}
30587abef63ead5ac9e2c67f0c07c461eda6be16aebDavid A. Long/* t16 thumb actions */
306231fb150c6f8a1f226380affc5498dd9abffc9d7Jon Medhurst
3073e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
308f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_bxblx(probes_opcode_t insn,
309b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
310a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst{
3117579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc + 2;
312a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst	int rm = (insn >> 3) & 0xf;
313a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst	unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm];
314a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst
315a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst	if (insn & (1 << 7)) /* BLX ? */
3167579f4b3764337b39087d10496af0e741cbfe570David A. Long		regs->ARM_lr = regs->ARM_pc | 1;
317a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst
318a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst	bx_write_pc(rmv, regs);
319a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst}
320a9c3c29e72cc459be0ecd597f0af11a67713175bJon Medhurst
3213e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
322f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_ldr_literal(probes_opcode_t insn,
323b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
324f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst{
3257579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3);
326f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	long index = insn & 0xff;
327f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	int rt = (insn >> 8) & 0x7;
328f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	regs->uregs[rt] = base[index];
329f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst}
330f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst
3313e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
332f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_ldrstr_sp_relative(probes_opcode_t insn,
333b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
334f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst{
335f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	unsigned long* base = (unsigned long *)regs->ARM_sp;
336f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	long index = insn & 0xff;
337f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	int rt = (insn >> 8) & 0x7;
338f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	if (insn & 0x800) /* LDR */
339f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst		regs->uregs[rt] = base[index];
340f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst	else /* STR */
341f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst		base[index] = regs->uregs[rt];
342f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst}
343f8695142820f3cb3bc97444a240eec5375a2b107Jon Medhurst
3443e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
345f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_reladr(probes_opcode_t insn,
346b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
3472f335829040cb16d0640e87121bef208894d4934Jon Medhurst{
3482f335829040cb16d0640e87121bef208894d4934Jon Medhurst	unsigned long base = (insn & 0x800) ? regs->ARM_sp
3497579f4b3764337b39087d10496af0e741cbfe570David A. Long					    : ((regs->ARM_pc + 2) & ~3);
3502f335829040cb16d0640e87121bef208894d4934Jon Medhurst	long offset = insn & 0xff;
3512f335829040cb16d0640e87121bef208894d4934Jon Medhurst	int rt = (insn >> 8) & 0x7;
3522f335829040cb16d0640e87121bef208894d4934Jon Medhurst	regs->uregs[rt] = base + offset * 4;
3532f335829040cb16d0640e87121bef208894d4934Jon Medhurst}
3542f335829040cb16d0640e87121bef208894d4934Jon Medhurst
3553e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
356f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_add_sp_imm(probes_opcode_t insn,
357b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
3582f335829040cb16d0640e87121bef208894d4934Jon Medhurst{
3592f335829040cb16d0640e87121bef208894d4934Jon Medhurst	long imm = insn & 0x7f;
3602f335829040cb16d0640e87121bef208894d4934Jon Medhurst	if (insn & 0x80) /* SUB */
3612f335829040cb16d0640e87121bef208894d4934Jon Medhurst		regs->ARM_sp -= imm * 4;
3622f335829040cb16d0640e87121bef208894d4934Jon Medhurst	else /* ADD */
3632f335829040cb16d0640e87121bef208894d4934Jon Medhurst		regs->ARM_sp += imm * 4;
3642f335829040cb16d0640e87121bef208894d4934Jon Medhurst}
3652f335829040cb16d0640e87121bef208894d4934Jon Medhurst
3663e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
367f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_cbz(probes_opcode_t insn,
368b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
36932818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst{
37032818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst	int rn = insn & 0x7;
371f145d664df502585618b12ed68c681f82153e02aDavid A. Long	probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn;
37232818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst	if (nonzero & 0x800) {
37332818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst		long i = insn & 0x200;
37432818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst		long imm5 = insn & 0xf8;
3757579f4b3764337b39087d10496af0e741cbfe570David A. Long		unsigned long pc = regs->ARM_pc + 2;
37632818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst		regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2);
37732818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst	}
37832818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst}
37932818f31f8ed811ea7ef924f24642580a63a7c85Jon Medhurst
3803e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
381f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_it(probes_opcode_t insn,
382b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
3835b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst{
3845b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	/*
3855b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	 * The 8 IT state bits are split into two parts in CPSR:
3865b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	 *	ITSTATE<1:0> are in CPSR<26:25>
3875b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	 *	ITSTATE<7:2> are in CPSR<15:10>
3885b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	 * The new IT state is in the lower byte of insn.
3895b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	 */
3905b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	unsigned long cpsr = regs->ARM_cpsr;
3915b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	cpsr &= ~PSR_IT_MASK;
3925b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	cpsr |= (insn & 0xfc) << 8;
3935b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	cpsr |= (insn & 0x03) << 25;
3945b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	regs->ARM_cpsr = cpsr;
3955b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst}
3965b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst
3973e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
398f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_singlestep_it(probes_opcode_t insn,
399b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		  struct arch_probes_insn *asi, struct pt_regs *regs)
4005b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst{
4015b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	regs->ARM_pc += 2;
4027579f4b3764337b39087d10496af0e741cbfe570David A. Long	t16_simulate_it(insn, asi, regs);
4035b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst}
4045b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst
40544a0a59c535004eac9f18210cb2ce10b23861630David A. Longstatic enum probes_insn __kprobes
406b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Longt16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi,
4073e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		const struct decode_header *d)
4085b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst{
4095b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	asi->insn_singlestep = t16_singlestep_it;
4105b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst	return INSN_GOOD_NO_SLOT;
4115b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst}
4125b94faf8d76be2116223c2591b31ddae5eecac2bJon Medhurst
4133e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
414f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_cond_branch(probes_opcode_t insn,
415b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
416396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst{
4177579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc + 2;
418396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	long offset = insn & 0x7f;
419396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	offset -= insn & 0x80; /* Apply sign bit */
420396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	regs->ARM_pc = pc + (offset * 2);
421396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst}
422396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst
42344a0a59c535004eac9f18210cb2ce10b23861630David A. Longstatic enum probes_insn __kprobes
424b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Longt16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
4253e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		const struct decode_header *d)
426396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst{
427396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	int cc = (insn >> 8) & 0xf;
428f145d664df502585618b12ed68c681f82153e02aDavid A. Long	asi->insn_check_cc = probes_condition_checks[cc];
429396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	asi->insn_handler = t16_simulate_cond_branch;
430396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	return INSN_GOOD_NO_SLOT;
431396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst}
432396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst
4333e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
434f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_simulate_branch(probes_opcode_t insn,
435b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		   struct arch_probes_insn *asi, struct pt_regs *regs)
436396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst{
4377579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc + 2;
438396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	long offset = insn & 0x3ff;
439396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	offset -= insn & 0x400; /* Apply sign bit */
440396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst	regs->ARM_pc = pc + (offset * 2);
441396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst}
442396b41f68d937a0c48ba624186ed06288b35bb4eJon Medhurst
44302d194f64772aee91e7319ca033905b0bafee04cJon Medhurststatic unsigned long __kprobes
444f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_emulate_loregs(probes_opcode_t insn,
445b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		   struct arch_probes_insn *asi, struct pt_regs *regs)
44602d194f64772aee91e7319ca033905b0bafee04cJon Medhurst{
44702d194f64772aee91e7319ca033905b0bafee04cJon Medhurst	unsigned long oldcpsr = regs->ARM_cpsr;
44802d194f64772aee91e7319ca033905b0bafee04cJon Medhurst	unsigned long newcpsr;
44902d194f64772aee91e7319ca033905b0bafee04cJon Medhurst
45002d194f64772aee91e7319ca033905b0bafee04cJon Medhurst	__asm__ __volatile__ (
45102d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		"msr	cpsr_fs, %[oldcpsr]	\n\t"
45202d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		"ldmia	%[regs], {r0-r7}	\n\t"
45302d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		"blx	%[fn]			\n\t"
45402d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		"stmia	%[regs], {r0-r7}	\n\t"
45502d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		"mrs	%[newcpsr], cpsr	\n\t"
45602d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		: [newcpsr] "=r" (newcpsr)
45702d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		: [oldcpsr] "r" (oldcpsr), [regs] "r" (regs),
4587579f4b3764337b39087d10496af0e741cbfe570David A. Long		  [fn] "r" (asi->insn_fn)
45902d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
46002d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		  "lr", "memory", "cc"
46102d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		);
46202d194f64772aee91e7319ca033905b0bafee04cJon Medhurst
46302d194f64772aee91e7319ca033905b0bafee04cJon Medhurst	return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK);
46402d194f64772aee91e7319ca033905b0bafee04cJon Medhurst}
46502d194f64772aee91e7319ca033905b0bafee04cJon Medhurst
4663e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
467f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_emulate_loregs_rwflags(probes_opcode_t insn,
468b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
46902d194f64772aee91e7319ca033905b0bafee04cJon Medhurst{
4707579f4b3764337b39087d10496af0e741cbfe570David A. Long	regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs);
47102d194f64772aee91e7319ca033905b0bafee04cJon Medhurst}
47202d194f64772aee91e7319ca033905b0bafee04cJon Medhurst
4733e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
474f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_emulate_loregs_noitrwflags(probes_opcode_t insn,
475b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
47602d194f64772aee91e7319ca033905b0bafee04cJon Medhurst{
4777579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long cpsr = t16_emulate_loregs(insn, asi, regs);
47802d194f64772aee91e7319ca033905b0bafee04cJon Medhurst	if (!in_it_block(cpsr))
47902d194f64772aee91e7319ca033905b0bafee04cJon Medhurst		regs->ARM_cpsr = cpsr;
48002d194f64772aee91e7319ca033905b0bafee04cJon Medhurst}
48102d194f64772aee91e7319ca033905b0bafee04cJon Medhurst
4823e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
483f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_emulate_hiregs(probes_opcode_t insn,
484b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
4853b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst{
4867579f4b3764337b39087d10496af0e741cbfe570David A. Long	unsigned long pc = regs->ARM_pc + 2;
4873b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	int rdn = (insn & 0x7) | ((insn & 0x80) >> 4);
4883b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	int rm = (insn >> 3) & 0xf;
4893b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst
4903b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	register unsigned long rdnv asm("r1");
4913b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	register unsigned long rmv asm("r0");
4923b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	unsigned long cpsr = regs->ARM_cpsr;
4933b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst
4943b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	rdnv = (rdn == 15) ? pc : regs->uregs[rdn];
4953b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	rmv = (rm == 15) ? pc : regs->uregs[rm];
4963b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst
4973b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	__asm__ __volatile__ (
4983b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst		"msr	cpsr_fs, %[cpsr]	\n\t"
4993b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst		"blx    %[fn]			\n\t"
5003b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst		"mrs	%[cpsr], cpsr		\n\t"
5013b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst		: "=r" (rdnv), [cpsr] "=r" (cpsr)
5027579f4b3764337b39087d10496af0e741cbfe570David A. Long		: "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn)
5033b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst		: "lr", "memory", "cc"
5043b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	);
5053b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst
5063b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	if (rdn == 15)
5073b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst		rdnv &= ~1;
5083b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst
5093b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	regs->uregs[rdn] = rdnv;
5103b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
5113b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst}
5123b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst
51344a0a59c535004eac9f18210cb2ce10b23861630David A. Longstatic enum probes_insn __kprobes
514b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Longt16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
5153e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		const struct decode_header *d)
5163b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst{
5173b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	insn &= ~0x00ff;
5183b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
519888be25402021a425da3e85e2d5a954d7509286eBen Dooks	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
5203b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	asi->insn_handler = t16_emulate_hiregs;
5213b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst	return INSN_GOOD;
5223b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst}
5233b5940e81182ff26d539dcf0ee8b2310f6965833Jon Medhurst
5243e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
525f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_emulate_push(probes_opcode_t insn,
526b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
527fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst{
528fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	__asm__ __volatile__ (
529fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"ldr	r9, [%[regs], #13*4]	\n\t"
530fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"ldr	r8, [%[regs], #14*4]	\n\t"
531fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"ldmia	%[regs], {r0-r7}	\n\t"
532fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"blx	%[fn]			\n\t"
533fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"str	r9, [%[regs], #13*4]	\n\t"
534fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		:
5357579f4b3764337b39087d10496af0e741cbfe570David A. Long		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
536fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
537fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		  "lr", "memory", "cc"
538fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		);
539fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst}
540fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst
54144a0a59c535004eac9f18210cb2ce10b23861630David A. Longstatic enum probes_insn __kprobes
542b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Longt16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
5433e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		const struct decode_header *d)
544fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst{
545fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	/*
546fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
547fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 * and call it with R9=SP and LR in the register list represented
548fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 * by R8.
549fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 */
550888be25402021a425da3e85e2d5a954d7509286eBen Dooks	/* 1st half STMDB R9!,{} */
551888be25402021a425da3e85e2d5a954d7509286eBen Dooks	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
552888be25402021a425da3e85e2d5a954d7509286eBen Dooks	/* 2nd half (register list) */
553888be25402021a425da3e85e2d5a954d7509286eBen Dooks	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
554fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	asi->insn_handler = t16_emulate_push;
555fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	return INSN_GOOD;
556fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst}
557fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst
5583e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
559f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_emulate_pop_nopc(probes_opcode_t insn,
560b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
561fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst{
562fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	__asm__ __volatile__ (
563fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"ldr	r9, [%[regs], #13*4]	\n\t"
564fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"ldmia	%[regs], {r0-r7}	\n\t"
565fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"blx	%[fn]			\n\t"
566fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"stmia	%[regs], {r0-r7}	\n\t"
567fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"str	r9, [%[regs], #13*4]	\n\t"
568fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		:
5697579f4b3764337b39087d10496af0e741cbfe570David A. Long		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
570fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
571fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		  "lr", "memory", "cc"
572fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		);
573fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst}
574fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst
5753e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longstatic void __kprobes
576f145d664df502585618b12ed68c681f82153e02aDavid A. Longt16_emulate_pop_pc(probes_opcode_t insn,
577b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Long		struct arch_probes_insn *asi, struct pt_regs *regs)
578fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst{
579fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	register unsigned long pc asm("r8");
580fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst
581fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	__asm__ __volatile__ (
582fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"ldr	r9, [%[regs], #13*4]	\n\t"
583fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"ldmia	%[regs], {r0-r7}	\n\t"
584fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"blx	%[fn]			\n\t"
585fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"stmia	%[regs], {r0-r7}	\n\t"
586fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		"str	r9, [%[regs], #13*4]	\n\t"
587fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		: "=r" (pc)
5887579f4b3764337b39087d10496af0e741cbfe570David A. Long		: [regs] "r" (regs), [fn] "r" (asi->insn_fn)
589fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9",
590fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		  "lr", "memory", "cc"
591fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst		);
592fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst
593fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	bx_write_pc(pc, regs);
594fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst}
595fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst
59644a0a59c535004eac9f18210cb2ce10b23861630David A. Longstatic enum probes_insn __kprobes
597b4cd605ca92d9a8a2f71355cb45dd943ebcb0c97David A. Longt16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
5983e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		const struct decode_header *d)
599fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst{
600fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	/*
601fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
602fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 * and call it with R9=SP and PC in the register list represented
603fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 * by R8.
604fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	 */
605888be25402021a425da3e85e2d5a954d7509286eBen Dooks	/* 1st half LDMIA R9!,{} */
606888be25402021a425da3e85e2d5a954d7509286eBen Dooks	((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
607888be25402021a425da3e85e2d5a954d7509286eBen Dooks	/* 2nd half (register list) */
608888be25402021a425da3e85e2d5a954d7509286eBen Dooks	((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
609fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
610fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst					 : t16_emulate_pop_nopc;
611fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst	return INSN_GOOD;
612fd0c8d8a48c57cb8a3f1fbbe46a2b208b57ff477Jon Medhurst}
6133e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long
6143e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longconst union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
6153e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm},
6163e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_CBZ] = {.handler = t16_simulate_cbz},
6173e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags},
6183e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_PUSH] = {.decoder = t16_decode_push},
6193e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_POP] = {.decoder = t16_decode_pop},
620eb73ea97e63bb06bf98ff052615ce181bc7f69ecDavid A. Long	[PROBES_T16_SEV] = {.handler = probes_emulate_none},
621eb73ea97e63bb06bf98ff052615ce181bc7f69ecDavid A. Long	[PROBES_T16_WFE] = {.handler = probes_simulate_nop},
6223e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_IT] = {.decoder = t16_decode_it},
6233e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags},
6243e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags},
6253e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags},
6263e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal},
6273e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_BLX] = {.handler = t16_simulate_bxblx},
6283e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs},
6293e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags},
6303e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative},
6313e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_ADR] = {.handler = t16_simulate_reladr},
6323e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags},
6333e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch},
6343e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T16_BRANCH] = {.handler = t16_simulate_branch},
6353e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long};
6363e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long
6373e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Longconst union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
6383e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm},
6393e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd},
6403e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch},
6413e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6423e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6433e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6443e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6453e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6463e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,},
6473e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags},
6483e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags},
6493e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6503e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags},
651eb73ea97e63bb06bf98ff052615ce181bc7f69ecDavid A. Long	[PROBES_T32_SEV] = {.handler = probes_emulate_none},
652eb73ea97e63bb06bf98ff052615ce181bc7f69ecDavid A. Long	[PROBES_T32_WFE] = {.handler = probes_simulate_nop},
6533e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_MRS] = {.handler = t32_simulate_mrs},
6543e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch},
6553e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_BRANCH] = {.handler = t32_simulate_branch},
656eb73ea97e63bb06bf98ff052615ce181bc7f69ecDavid A. Long	[PROBES_T32_PLDI] = {.handler = probes_simulate_nop},
6573e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal},
6583e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr},
6593e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6603e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6613e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags},
6623e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
6633e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags},
6643e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long	[PROBES_T32_MUL_ADD_LONG] = {
6653e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long		.handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
6663e6cd394bb10c2d65322e5f5d2ff0a9074d903a1David A. Long};
667