xref: /openbmc/linux/arch/arm/probes/decode.c (revision df561f66)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fca08f32SWang Nan /*
3fca08f32SWang Nan  * arch/arm/probes/decode.c
4fca08f32SWang Nan  *
5fca08f32SWang Nan  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
6fca08f32SWang Nan  *
7fca08f32SWang Nan  * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
8fca08f32SWang Nan  * Copyright (C) 2006, 2007 Motorola Inc.
9fca08f32SWang Nan  */
10fca08f32SWang Nan 
11fca08f32SWang Nan #include <linux/kernel.h>
12fca08f32SWang Nan #include <linux/types.h>
13fca08f32SWang Nan #include <asm/system_info.h>
14fca08f32SWang Nan #include <asm/ptrace.h>
15fca08f32SWang Nan #include <linux/bug.h>
16fca08f32SWang Nan 
17fca08f32SWang Nan #include "decode.h"
18fca08f32SWang Nan 
19fca08f32SWang Nan 
20fca08f32SWang Nan #ifndef find_str_pc_offset
21fca08f32SWang Nan 
22fca08f32SWang Nan /*
23fca08f32SWang Nan  * For STR and STM instructions, an ARM core may choose to use either
24fca08f32SWang Nan  * a +8 or a +12 displacement from the current instruction's address.
25fca08f32SWang Nan  * Whichever value is chosen for a given core, it must be the same for
26fca08f32SWang Nan  * both instructions and may not change.  This function measures it.
27fca08f32SWang Nan  */
28fca08f32SWang Nan 
29fca08f32SWang Nan int str_pc_offset;
30fca08f32SWang Nan 
find_str_pc_offset(void)31fca08f32SWang Nan void __init find_str_pc_offset(void)
32fca08f32SWang Nan {
33fca08f32SWang Nan 	int addr, scratch, ret;
34fca08f32SWang Nan 
35fca08f32SWang Nan 	__asm__ (
36fca08f32SWang Nan 		"sub	%[ret], pc, #4		\n\t"
37fca08f32SWang Nan 		"str	pc, %[addr]		\n\t"
38fca08f32SWang Nan 		"ldr	%[scr], %[addr]		\n\t"
39fca08f32SWang Nan 		"sub	%[ret], %[scr], %[ret]	\n\t"
40fca08f32SWang Nan 		: [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
41fca08f32SWang Nan 
42fca08f32SWang Nan 	str_pc_offset = ret;
43fca08f32SWang Nan }
44fca08f32SWang Nan 
45fca08f32SWang Nan #endif /* !find_str_pc_offset */
46fca08f32SWang Nan 
47fca08f32SWang Nan 
48fca08f32SWang Nan #ifndef test_load_write_pc_interworking
49fca08f32SWang Nan 
50fca08f32SWang Nan bool load_write_pc_interworks;
51fca08f32SWang Nan 
test_load_write_pc_interworking(void)52fca08f32SWang Nan void __init test_load_write_pc_interworking(void)
53fca08f32SWang Nan {
54fca08f32SWang Nan 	int arch = cpu_architecture();
55fca08f32SWang Nan 	BUG_ON(arch == CPU_ARCH_UNKNOWN);
56fca08f32SWang Nan 	load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T;
57fca08f32SWang Nan }
58fca08f32SWang Nan 
59fca08f32SWang Nan #endif /* !test_load_write_pc_interworking */
60fca08f32SWang Nan 
61fca08f32SWang Nan 
62fca08f32SWang Nan #ifndef test_alu_write_pc_interworking
63fca08f32SWang Nan 
64fca08f32SWang Nan bool alu_write_pc_interworks;
65fca08f32SWang Nan 
test_alu_write_pc_interworking(void)66fca08f32SWang Nan void __init test_alu_write_pc_interworking(void)
67fca08f32SWang Nan {
68fca08f32SWang Nan 	int arch = cpu_architecture();
69fca08f32SWang Nan 	BUG_ON(arch == CPU_ARCH_UNKNOWN);
70fca08f32SWang Nan 	alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
71fca08f32SWang Nan }
72fca08f32SWang Nan 
73fca08f32SWang Nan #endif /* !test_alu_write_pc_interworking */
74fca08f32SWang Nan 
75fca08f32SWang Nan 
arm_probes_decode_init(void)76fca08f32SWang Nan void __init arm_probes_decode_init(void)
77fca08f32SWang Nan {
78fca08f32SWang Nan 	find_str_pc_offset();
79fca08f32SWang Nan 	test_load_write_pc_interworking();
80fca08f32SWang Nan 	test_alu_write_pc_interworking();
81fca08f32SWang Nan }
82fca08f32SWang Nan 
83fca08f32SWang Nan 
__check_eq(unsigned long cpsr)84fca08f32SWang Nan static unsigned long __kprobes __check_eq(unsigned long cpsr)
85fca08f32SWang Nan {
86fca08f32SWang Nan 	return cpsr & PSR_Z_BIT;
87fca08f32SWang Nan }
88fca08f32SWang Nan 
__check_ne(unsigned long cpsr)89fca08f32SWang Nan static unsigned long __kprobes __check_ne(unsigned long cpsr)
90fca08f32SWang Nan {
91fca08f32SWang Nan 	return (~cpsr) & PSR_Z_BIT;
92fca08f32SWang Nan }
93fca08f32SWang Nan 
__check_cs(unsigned long cpsr)94fca08f32SWang Nan static unsigned long __kprobes __check_cs(unsigned long cpsr)
95fca08f32SWang Nan {
96fca08f32SWang Nan 	return cpsr & PSR_C_BIT;
97fca08f32SWang Nan }
98fca08f32SWang Nan 
__check_cc(unsigned long cpsr)99fca08f32SWang Nan static unsigned long __kprobes __check_cc(unsigned long cpsr)
100fca08f32SWang Nan {
101fca08f32SWang Nan 	return (~cpsr) & PSR_C_BIT;
102fca08f32SWang Nan }
103fca08f32SWang Nan 
__check_mi(unsigned long cpsr)104fca08f32SWang Nan static unsigned long __kprobes __check_mi(unsigned long cpsr)
105fca08f32SWang Nan {
106fca08f32SWang Nan 	return cpsr & PSR_N_BIT;
107fca08f32SWang Nan }
108fca08f32SWang Nan 
__check_pl(unsigned long cpsr)109fca08f32SWang Nan static unsigned long __kprobes __check_pl(unsigned long cpsr)
110fca08f32SWang Nan {
111fca08f32SWang Nan 	return (~cpsr) & PSR_N_BIT;
112fca08f32SWang Nan }
113fca08f32SWang Nan 
__check_vs(unsigned long cpsr)114fca08f32SWang Nan static unsigned long __kprobes __check_vs(unsigned long cpsr)
115fca08f32SWang Nan {
116fca08f32SWang Nan 	return cpsr & PSR_V_BIT;
117fca08f32SWang Nan }
118fca08f32SWang Nan 
__check_vc(unsigned long cpsr)119fca08f32SWang Nan static unsigned long __kprobes __check_vc(unsigned long cpsr)
120fca08f32SWang Nan {
121fca08f32SWang Nan 	return (~cpsr) & PSR_V_BIT;
122fca08f32SWang Nan }
123fca08f32SWang Nan 
__check_hi(unsigned long cpsr)124fca08f32SWang Nan static unsigned long __kprobes __check_hi(unsigned long cpsr)
125fca08f32SWang Nan {
126fca08f32SWang Nan 	cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
127fca08f32SWang Nan 	return cpsr & PSR_C_BIT;
128fca08f32SWang Nan }
129fca08f32SWang Nan 
__check_ls(unsigned long cpsr)130fca08f32SWang Nan static unsigned long __kprobes __check_ls(unsigned long cpsr)
131fca08f32SWang Nan {
132fca08f32SWang Nan 	cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
133fca08f32SWang Nan 	return (~cpsr) & PSR_C_BIT;
134fca08f32SWang Nan }
135fca08f32SWang Nan 
__check_ge(unsigned long cpsr)136fca08f32SWang Nan static unsigned long __kprobes __check_ge(unsigned long cpsr)
137fca08f32SWang Nan {
138fca08f32SWang Nan 	cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
139fca08f32SWang Nan 	return (~cpsr) & PSR_N_BIT;
140fca08f32SWang Nan }
141fca08f32SWang Nan 
__check_lt(unsigned long cpsr)142fca08f32SWang Nan static unsigned long __kprobes __check_lt(unsigned long cpsr)
143fca08f32SWang Nan {
144fca08f32SWang Nan 	cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
145fca08f32SWang Nan 	return cpsr & PSR_N_BIT;
146fca08f32SWang Nan }
147fca08f32SWang Nan 
__check_gt(unsigned long cpsr)148fca08f32SWang Nan static unsigned long __kprobes __check_gt(unsigned long cpsr)
149fca08f32SWang Nan {
150fca08f32SWang Nan 	unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
151fca08f32SWang Nan 	temp |= (cpsr << 1);			 /* PSR_N_BIT |= PSR_Z_BIT */
152fca08f32SWang Nan 	return (~temp) & PSR_N_BIT;
153fca08f32SWang Nan }
154fca08f32SWang Nan 
__check_le(unsigned long cpsr)155fca08f32SWang Nan static unsigned long __kprobes __check_le(unsigned long cpsr)
156fca08f32SWang Nan {
157fca08f32SWang Nan 	unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
158fca08f32SWang Nan 	temp |= (cpsr << 1);			 /* PSR_N_BIT |= PSR_Z_BIT */
159fca08f32SWang Nan 	return temp & PSR_N_BIT;
160fca08f32SWang Nan }
161fca08f32SWang Nan 
__check_al(unsigned long cpsr)162fca08f32SWang Nan static unsigned long __kprobes __check_al(unsigned long cpsr)
163fca08f32SWang Nan {
164fca08f32SWang Nan 	return true;
165fca08f32SWang Nan }
166fca08f32SWang Nan 
167fca08f32SWang Nan probes_check_cc * const probes_condition_checks[16] = {
168fca08f32SWang Nan 	&__check_eq, &__check_ne, &__check_cs, &__check_cc,
169fca08f32SWang Nan 	&__check_mi, &__check_pl, &__check_vs, &__check_vc,
170fca08f32SWang Nan 	&__check_hi, &__check_ls, &__check_ge, &__check_lt,
171fca08f32SWang Nan 	&__check_gt, &__check_le, &__check_al, &__check_al
172fca08f32SWang Nan };
173fca08f32SWang Nan 
174fca08f32SWang Nan 
probes_simulate_nop(probes_opcode_t opcode,struct arch_probes_insn * asi,struct pt_regs * regs)175fca08f32SWang Nan void __kprobes probes_simulate_nop(probes_opcode_t opcode,
176fca08f32SWang Nan 	struct arch_probes_insn *asi,
177fca08f32SWang Nan 	struct pt_regs *regs)
178fca08f32SWang Nan {
179fca08f32SWang Nan }
180fca08f32SWang Nan 
probes_emulate_none(probes_opcode_t opcode,struct arch_probes_insn * asi,struct pt_regs * regs)181fca08f32SWang Nan void __kprobes probes_emulate_none(probes_opcode_t opcode,
182fca08f32SWang Nan 	struct arch_probes_insn *asi,
183fca08f32SWang Nan 	struct pt_regs *regs)
184fca08f32SWang Nan {
185fca08f32SWang Nan 	asi->insn_fn();
186fca08f32SWang Nan }
187fca08f32SWang Nan 
188fca08f32SWang Nan /*
189fca08f32SWang Nan  * Prepare an instruction slot to receive an instruction for emulating.
190fca08f32SWang Nan  * This is done by placing a subroutine return after the location where the
191fca08f32SWang Nan  * instruction will be placed. We also modify ARM instructions to be
192fca08f32SWang Nan  * unconditional as the condition code will already be checked before any
193fca08f32SWang Nan  * emulation handler is called.
194fca08f32SWang Nan  */
195fca08f32SWang Nan static probes_opcode_t __kprobes
prepare_emulated_insn(probes_opcode_t insn,struct arch_probes_insn * asi,bool thumb)196fca08f32SWang Nan prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
197fca08f32SWang Nan 		      bool thumb)
198fca08f32SWang Nan {
199fca08f32SWang Nan #ifdef CONFIG_THUMB2_KERNEL
200fca08f32SWang Nan 	if (thumb) {
201fca08f32SWang Nan 		u16 *thumb_insn = (u16 *)asi->insn;
202fca08f32SWang Nan 		/* Thumb bx lr */
203fca08f32SWang Nan 		thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
204fca08f32SWang Nan 		thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
205fca08f32SWang Nan 		return insn;
206fca08f32SWang Nan 	}
207fca08f32SWang Nan 	asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
208fca08f32SWang Nan #else
209fca08f32SWang Nan 	asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
210fca08f32SWang Nan #endif
211fca08f32SWang Nan 	/* Make an ARM instruction unconditional */
212fca08f32SWang Nan 	if (insn < 0xe0000000)
213fca08f32SWang Nan 		insn = (insn | 0xe0000000) & ~0x10000000;
214fca08f32SWang Nan 	return insn;
215fca08f32SWang Nan }
216fca08f32SWang Nan 
217fca08f32SWang Nan /*
218fca08f32SWang Nan  * Write a (probably modified) instruction into the slot previously prepared by
219fca08f32SWang Nan  * prepare_emulated_insn
220fca08f32SWang Nan  */
221fca08f32SWang Nan static void  __kprobes
set_emulated_insn(probes_opcode_t insn,struct arch_probes_insn * asi,bool thumb)222fca08f32SWang Nan set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
223fca08f32SWang Nan 		  bool thumb)
224fca08f32SWang Nan {
225fca08f32SWang Nan #ifdef CONFIG_THUMB2_KERNEL
226fca08f32SWang Nan 	if (thumb) {
227fca08f32SWang Nan 		u16 *ip = (u16 *)asi->insn;
228fca08f32SWang Nan 		if (is_wide_instruction(insn))
229fca08f32SWang Nan 			*ip++ = __opcode_to_mem_thumb16(insn >> 16);
230fca08f32SWang Nan 		*ip++ = __opcode_to_mem_thumb16(insn);
231fca08f32SWang Nan 		return;
232fca08f32SWang Nan 	}
233fca08f32SWang Nan #endif
234fca08f32SWang Nan 	asi->insn[0] = __opcode_to_mem_arm(insn);
235fca08f32SWang Nan }
236fca08f32SWang Nan 
237fca08f32SWang Nan /*
238fca08f32SWang Nan  * When we modify the register numbers encoded in an instruction to be emulated,
239fca08f32SWang Nan  * the new values come from this define. For ARM and 32-bit Thumb instructions
240fca08f32SWang Nan  * this gives...
241fca08f32SWang Nan  *
242fca08f32SWang Nan  *	bit position	  16  12   8   4   0
243fca08f32SWang Nan  *	---------------+---+---+---+---+---+
244fca08f32SWang Nan  *	register	 r2  r0  r1  --  r3
245fca08f32SWang Nan  */
246fca08f32SWang Nan #define INSN_NEW_BITS		0x00020103
247fca08f32SWang Nan 
248fca08f32SWang Nan /* Each nibble has same value as that at INSN_NEW_BITS bit 16 */
249fca08f32SWang Nan #define INSN_SAMEAS16_BITS	0x22222222
250fca08f32SWang Nan 
251fca08f32SWang Nan /*
252fca08f32SWang Nan  * Validate and modify each of the registers encoded in an instruction.
253fca08f32SWang Nan  *
254fca08f32SWang Nan  * Each nibble in regs contains a value from enum decode_reg_type. For each
255fca08f32SWang Nan  * non-zero value, the corresponding nibble in pinsn is validated and modified
256fca08f32SWang Nan  * according to the type.
257fca08f32SWang Nan  */
decode_regs(probes_opcode_t * pinsn,u32 regs,bool modify)258fca08f32SWang Nan static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify)
259fca08f32SWang Nan {
260fca08f32SWang Nan 	probes_opcode_t insn = *pinsn;
261fca08f32SWang Nan 	probes_opcode_t mask = 0xf; /* Start at least significant nibble */
262fca08f32SWang Nan 
263fca08f32SWang Nan 	for (; regs != 0; regs >>= 4, mask <<= 4) {
264fca08f32SWang Nan 
265fca08f32SWang Nan 		probes_opcode_t new_bits = INSN_NEW_BITS;
266fca08f32SWang Nan 
267fca08f32SWang Nan 		switch (regs & 0xf) {
268fca08f32SWang Nan 
269fca08f32SWang Nan 		case REG_TYPE_NONE:
270fca08f32SWang Nan 			/* Nibble not a register, skip to next */
271fca08f32SWang Nan 			continue;
272fca08f32SWang Nan 
273fca08f32SWang Nan 		case REG_TYPE_ANY:
274fca08f32SWang Nan 			/* Any register is allowed */
275fca08f32SWang Nan 			break;
276fca08f32SWang Nan 
277fca08f32SWang Nan 		case REG_TYPE_SAMEAS16:
278fca08f32SWang Nan 			/* Replace register with same as at bit position 16 */
279fca08f32SWang Nan 			new_bits = INSN_SAMEAS16_BITS;
280fca08f32SWang Nan 			break;
281fca08f32SWang Nan 
282fca08f32SWang Nan 		case REG_TYPE_SP:
283fca08f32SWang Nan 			/* Only allow SP (R13) */
284fca08f32SWang Nan 			if ((insn ^ 0xdddddddd) & mask)
285fca08f32SWang Nan 				goto reject;
286fca08f32SWang Nan 			break;
287fca08f32SWang Nan 
288fca08f32SWang Nan 		case REG_TYPE_PC:
289fca08f32SWang Nan 			/* Only allow PC (R15) */
290fca08f32SWang Nan 			if ((insn ^ 0xffffffff) & mask)
291fca08f32SWang Nan 				goto reject;
292fca08f32SWang Nan 			break;
293fca08f32SWang Nan 
294fca08f32SWang Nan 		case REG_TYPE_NOSP:
295fca08f32SWang Nan 			/* Reject SP (R13) */
296fca08f32SWang Nan 			if (((insn ^ 0xdddddddd) & mask) == 0)
297fca08f32SWang Nan 				goto reject;
298fca08f32SWang Nan 			break;
299fca08f32SWang Nan 
300fca08f32SWang Nan 		case REG_TYPE_NOSPPC:
301fca08f32SWang Nan 		case REG_TYPE_NOSPPCX:
302fca08f32SWang Nan 			/* Reject SP and PC (R13 and R15) */
303fca08f32SWang Nan 			if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0)
304fca08f32SWang Nan 				goto reject;
305fca08f32SWang Nan 			break;
306fca08f32SWang Nan 
307fca08f32SWang Nan 		case REG_TYPE_NOPCWB:
308fca08f32SWang Nan 			if (!is_writeback(insn))
309fca08f32SWang Nan 				break; /* No writeback, so any register is OK */
310df561f66SGustavo A. R. Silva 			fallthrough;
311fca08f32SWang Nan 		case REG_TYPE_NOPC:
312fca08f32SWang Nan 		case REG_TYPE_NOPCX:
313fca08f32SWang Nan 			/* Reject PC (R15) */
314fca08f32SWang Nan 			if (((insn ^ 0xffffffff) & mask) == 0)
315fca08f32SWang Nan 				goto reject;
316fca08f32SWang Nan 			break;
317fca08f32SWang Nan 		}
318fca08f32SWang Nan 
319fca08f32SWang Nan 		/* Replace value of nibble with new register number... */
320fca08f32SWang Nan 		insn &= ~mask;
321fca08f32SWang Nan 		insn |= new_bits & mask;
322fca08f32SWang Nan 	}
323fca08f32SWang Nan 
324fca08f32SWang Nan 	if (modify)
325fca08f32SWang Nan 		*pinsn = insn;
326fca08f32SWang Nan 
327fca08f32SWang Nan 	return true;
328fca08f32SWang Nan 
329fca08f32SWang Nan reject:
330fca08f32SWang Nan 	return false;
331fca08f32SWang Nan }
332fca08f32SWang Nan 
333fca08f32SWang Nan static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
334fca08f32SWang Nan 	[DECODE_TYPE_TABLE]	= sizeof(struct decode_table),
335fca08f32SWang Nan 	[DECODE_TYPE_CUSTOM]	= sizeof(struct decode_custom),
336fca08f32SWang Nan 	[DECODE_TYPE_SIMULATE]	= sizeof(struct decode_simulate),
337fca08f32SWang Nan 	[DECODE_TYPE_EMULATE]	= sizeof(struct decode_emulate),
338fca08f32SWang Nan 	[DECODE_TYPE_OR]	= sizeof(struct decode_or),
339fca08f32SWang Nan 	[DECODE_TYPE_REJECT]	= sizeof(struct decode_reject)
340fca08f32SWang Nan };
341fca08f32SWang Nan 
run_checkers(const struct decode_checker * checkers[],int action,probes_opcode_t insn,struct arch_probes_insn * asi,const struct decode_header * h)34283803d97SWang Nan static int run_checkers(const struct decode_checker *checkers[],
34383803d97SWang Nan 		int action, probes_opcode_t insn,
34483803d97SWang Nan 		struct arch_probes_insn *asi,
34583803d97SWang Nan 		const struct decode_header *h)
34683803d97SWang Nan {
34783803d97SWang Nan 	const struct decode_checker **p;
34883803d97SWang Nan 
34983803d97SWang Nan 	if (!checkers)
35083803d97SWang Nan 		return INSN_GOOD;
35183803d97SWang Nan 
35283803d97SWang Nan 	p = checkers;
35383803d97SWang Nan 	while (*p != NULL) {
35483803d97SWang Nan 		int retval;
35583803d97SWang Nan 		probes_check_t *checker_func = (*p)[action].checker;
35683803d97SWang Nan 
35783803d97SWang Nan 		retval = INSN_GOOD;
35883803d97SWang Nan 		if (checker_func)
35983803d97SWang Nan 			retval = checker_func(insn, asi, h);
36083803d97SWang Nan 		if (retval == INSN_REJECTED)
36183803d97SWang Nan 			return retval;
36283803d97SWang Nan 		p++;
36383803d97SWang Nan 	}
36483803d97SWang Nan 	return INSN_GOOD;
36583803d97SWang Nan }
36683803d97SWang Nan 
367fca08f32SWang Nan /*
368fca08f32SWang Nan  * probes_decode_insn operates on data tables in order to decode an ARM
369fca08f32SWang Nan  * architecture instruction onto which a kprobe has been placed.
370fca08f32SWang Nan  *
371fca08f32SWang Nan  * These instruction decoding tables are a concatenation of entries each
372fca08f32SWang Nan  * of which consist of one of the following structs:
373fca08f32SWang Nan  *
374fca08f32SWang Nan  *	decode_table
375fca08f32SWang Nan  *	decode_custom
376fca08f32SWang Nan  *	decode_simulate
377fca08f32SWang Nan  *	decode_emulate
378fca08f32SWang Nan  *	decode_or
379fca08f32SWang Nan  *	decode_reject
380fca08f32SWang Nan  *
381fca08f32SWang Nan  * Each of these starts with a struct decode_header which has the following
382fca08f32SWang Nan  * fields:
383fca08f32SWang Nan  *
384fca08f32SWang Nan  *	type_regs
385fca08f32SWang Nan  *	mask
386fca08f32SWang Nan  *	value
387fca08f32SWang Nan  *
388fca08f32SWang Nan  * The least significant DECODE_TYPE_BITS of type_regs contains a value
389fca08f32SWang Nan  * from enum decode_type, this indicates which of the decode_* structs
390fca08f32SWang Nan  * the entry contains. The value DECODE_TYPE_END indicates the end of the
391fca08f32SWang Nan  * table.
392fca08f32SWang Nan  *
393fca08f32SWang Nan  * When the table is parsed, each entry is checked in turn to see if it
394fca08f32SWang Nan  * matches the instruction to be decoded using the test:
395fca08f32SWang Nan  *
396fca08f32SWang Nan  *	(insn & mask) == value
397fca08f32SWang Nan  *
398fca08f32SWang Nan  * If no match is found before the end of the table is reached then decoding
399fca08f32SWang Nan  * fails with INSN_REJECTED.
400fca08f32SWang Nan  *
401fca08f32SWang Nan  * When a match is found, decode_regs() is called to validate and modify each
402fca08f32SWang Nan  * of the registers encoded in the instruction; the data it uses to do this
403fca08f32SWang Nan  * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding
404fca08f32SWang Nan  * to fail with INSN_REJECTED.
405fca08f32SWang Nan  *
406fca08f32SWang Nan  * Once the instruction has passed the above tests, further processing
407fca08f32SWang Nan  * depends on the type of the table entry's decode struct.
408fca08f32SWang Nan  *
409fca08f32SWang Nan  */
410fca08f32SWang Nan int __kprobes
probes_decode_insn(probes_opcode_t insn,struct arch_probes_insn * asi,const union decode_item * table,bool thumb,bool emulate,const union decode_action * actions,const struct decode_checker * checkers[])411fca08f32SWang Nan probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
412fca08f32SWang Nan 		   const union decode_item *table, bool thumb,
41383803d97SWang Nan 		   bool emulate, const union decode_action *actions,
41483803d97SWang Nan 		   const struct decode_checker *checkers[])
415fca08f32SWang Nan {
416fca08f32SWang Nan 	const struct decode_header *h = (struct decode_header *)table;
417fca08f32SWang Nan 	const struct decode_header *next;
418fca08f32SWang Nan 	bool matched = false;
41983803d97SWang Nan 	/*
42083803d97SWang Nan 	 * @insn can be modified by decode_regs. Save its original
42183803d97SWang Nan 	 * value for checkers.
42283803d97SWang Nan 	 */
42383803d97SWang Nan 	probes_opcode_t origin_insn = insn;
424fca08f32SWang Nan 
4256624cf65SWang Nan 	/*
4266624cf65SWang Nan 	 * stack_space is initialized to 0 here. Checker functions
4276624cf65SWang Nan 	 * should update is value if they find this is a stack store
4286624cf65SWang Nan 	 * instruction: positive value means bytes of stack usage,
4296624cf65SWang Nan 	 * negitive value means unable to determine stack usage
4306624cf65SWang Nan 	 * statically. For instruction doesn't store to stack, checker
4316624cf65SWang Nan 	 * do nothing with it.
4326624cf65SWang Nan 	 */
4336624cf65SWang Nan 	asi->stack_space = 0;
4346624cf65SWang Nan 
43528a1899dSWang Nan 	/*
43628a1899dSWang Nan 	 * Similarly to stack_space, register_usage_flags is filled by
43728a1899dSWang Nan 	 * checkers. Its default value is set to ~0, which is 'all
43828a1899dSWang Nan 	 * registers are used', to prevent any potential optimization.
43928a1899dSWang Nan 	 */
44028a1899dSWang Nan 	asi->register_usage_flags = ~0UL;
44128a1899dSWang Nan 
442fca08f32SWang Nan 	if (emulate)
443fca08f32SWang Nan 		insn = prepare_emulated_insn(insn, asi, thumb);
444fca08f32SWang Nan 
445fca08f32SWang Nan 	for (;; h = next) {
446fca08f32SWang Nan 		enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
447fca08f32SWang Nan 		u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
448fca08f32SWang Nan 
449fca08f32SWang Nan 		if (type == DECODE_TYPE_END)
450fca08f32SWang Nan 			return INSN_REJECTED;
451fca08f32SWang Nan 
452fca08f32SWang Nan 		next = (struct decode_header *)
453fca08f32SWang Nan 				((uintptr_t)h + decode_struct_sizes[type]);
454fca08f32SWang Nan 
455fca08f32SWang Nan 		if (!matched && (insn & h->mask.bits) != h->value.bits)
456fca08f32SWang Nan 			continue;
457fca08f32SWang Nan 
458fca08f32SWang Nan 		if (!decode_regs(&insn, regs, emulate))
459fca08f32SWang Nan 			return INSN_REJECTED;
460fca08f32SWang Nan 
461fca08f32SWang Nan 		switch (type) {
462fca08f32SWang Nan 
463fca08f32SWang Nan 		case DECODE_TYPE_TABLE: {
464fca08f32SWang Nan 			struct decode_table *d = (struct decode_table *)h;
465fca08f32SWang Nan 			next = (struct decode_header *)d->table.table;
466fca08f32SWang Nan 			break;
467fca08f32SWang Nan 		}
468fca08f32SWang Nan 
469fca08f32SWang Nan 		case DECODE_TYPE_CUSTOM: {
47083803d97SWang Nan 			int err;
471fca08f32SWang Nan 			struct decode_custom *d = (struct decode_custom *)h;
47283803d97SWang Nan 			int action = d->decoder.action;
47383803d97SWang Nan 
47483803d97SWang Nan 			err = run_checkers(checkers, action, origin_insn, asi, h);
47583803d97SWang Nan 			if (err == INSN_REJECTED)
47683803d97SWang Nan 				return INSN_REJECTED;
47783803d97SWang Nan 			return actions[action].decoder(insn, asi, h);
478fca08f32SWang Nan 		}
479fca08f32SWang Nan 
480fca08f32SWang Nan 		case DECODE_TYPE_SIMULATE: {
48183803d97SWang Nan 			int err;
482fca08f32SWang Nan 			struct decode_simulate *d = (struct decode_simulate *)h;
48383803d97SWang Nan 			int action = d->handler.action;
48483803d97SWang Nan 
48583803d97SWang Nan 			err = run_checkers(checkers, action, origin_insn, asi, h);
48683803d97SWang Nan 			if (err == INSN_REJECTED)
48783803d97SWang Nan 				return INSN_REJECTED;
48883803d97SWang Nan 			asi->insn_handler = actions[action].handler;
489fca08f32SWang Nan 			return INSN_GOOD_NO_SLOT;
490fca08f32SWang Nan 		}
491fca08f32SWang Nan 
492fca08f32SWang Nan 		case DECODE_TYPE_EMULATE: {
49383803d97SWang Nan 			int err;
494fca08f32SWang Nan 			struct decode_emulate *d = (struct decode_emulate *)h;
49583803d97SWang Nan 			int action = d->handler.action;
49683803d97SWang Nan 
49783803d97SWang Nan 			err = run_checkers(checkers, action, origin_insn, asi, h);
49883803d97SWang Nan 			if (err == INSN_REJECTED)
49983803d97SWang Nan 				return INSN_REJECTED;
500fca08f32SWang Nan 
501fca08f32SWang Nan 			if (!emulate)
50283803d97SWang Nan 				return actions[action].decoder(insn, asi, h);
503fca08f32SWang Nan 
50483803d97SWang Nan 			asi->insn_handler = actions[action].handler;
505fca08f32SWang Nan 			set_emulated_insn(insn, asi, thumb);
506fca08f32SWang Nan 			return INSN_GOOD;
507fca08f32SWang Nan 		}
508fca08f32SWang Nan 
509fca08f32SWang Nan 		case DECODE_TYPE_OR:
510fca08f32SWang Nan 			matched = true;
511fca08f32SWang Nan 			break;
512fca08f32SWang Nan 
513fca08f32SWang Nan 		case DECODE_TYPE_REJECT:
514fca08f32SWang Nan 		default:
515fca08f32SWang Nan 			return INSN_REJECTED;
516fca08f32SWang Nan 		}
517fca08f32SWang Nan 	}
518fca08f32SWang Nan }
519