xref: /openbmc/linux/arch/arm/probes/decode.c (revision fca08f326ae0423f03b097ff54de432fe77b95d0)
1*fca08f32SWang Nan /*
2*fca08f32SWang Nan  * arch/arm/probes/decode.c
3*fca08f32SWang Nan  *
4*fca08f32SWang Nan  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
5*fca08f32SWang Nan  *
6*fca08f32SWang Nan  * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
7*fca08f32SWang Nan  * Copyright (C) 2006, 2007 Motorola Inc.
8*fca08f32SWang Nan  *
9*fca08f32SWang Nan  * This program is free software; you can redistribute it and/or modify
10*fca08f32SWang Nan  * it under the terms of the GNU General Public License version 2 as
11*fca08f32SWang Nan  * published by the Free Software Foundation.
12*fca08f32SWang Nan  */
13*fca08f32SWang Nan 
14*fca08f32SWang Nan #include <linux/kernel.h>
15*fca08f32SWang Nan #include <linux/types.h>
16*fca08f32SWang Nan #include <asm/system_info.h>
17*fca08f32SWang Nan #include <asm/ptrace.h>
18*fca08f32SWang Nan #include <linux/bug.h>
19*fca08f32SWang Nan 
20*fca08f32SWang Nan #include "decode.h"
21*fca08f32SWang Nan 
22*fca08f32SWang Nan 
23*fca08f32SWang Nan #ifndef find_str_pc_offset
24*fca08f32SWang Nan 
25*fca08f32SWang Nan /*
26*fca08f32SWang Nan  * For STR and STM instructions, an ARM core may choose to use either
27*fca08f32SWang Nan  * a +8 or a +12 displacement from the current instruction's address.
28*fca08f32SWang Nan  * Whichever value is chosen for a given core, it must be the same for
29*fca08f32SWang Nan  * both instructions and may not change.  This function measures it.
30*fca08f32SWang Nan  */
31*fca08f32SWang Nan 
32*fca08f32SWang Nan int str_pc_offset;
33*fca08f32SWang Nan 
34*fca08f32SWang Nan void __init find_str_pc_offset(void)
35*fca08f32SWang Nan {
36*fca08f32SWang Nan 	int addr, scratch, ret;
37*fca08f32SWang Nan 
38*fca08f32SWang Nan 	__asm__ (
39*fca08f32SWang Nan 		"sub	%[ret], pc, #4		\n\t"
40*fca08f32SWang Nan 		"str	pc, %[addr]		\n\t"
41*fca08f32SWang Nan 		"ldr	%[scr], %[addr]		\n\t"
42*fca08f32SWang Nan 		"sub	%[ret], %[scr], %[ret]	\n\t"
43*fca08f32SWang Nan 		: [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr));
44*fca08f32SWang Nan 
45*fca08f32SWang Nan 	str_pc_offset = ret;
46*fca08f32SWang Nan }
47*fca08f32SWang Nan 
48*fca08f32SWang Nan #endif /* !find_str_pc_offset */
49*fca08f32SWang Nan 
50*fca08f32SWang Nan 
51*fca08f32SWang Nan #ifndef test_load_write_pc_interworking
52*fca08f32SWang Nan 
53*fca08f32SWang Nan bool load_write_pc_interworks;
54*fca08f32SWang Nan 
55*fca08f32SWang Nan void __init test_load_write_pc_interworking(void)
56*fca08f32SWang Nan {
57*fca08f32SWang Nan 	int arch = cpu_architecture();
58*fca08f32SWang Nan 	BUG_ON(arch == CPU_ARCH_UNKNOWN);
59*fca08f32SWang Nan 	load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T;
60*fca08f32SWang Nan }
61*fca08f32SWang Nan 
62*fca08f32SWang Nan #endif /* !test_load_write_pc_interworking */
63*fca08f32SWang Nan 
64*fca08f32SWang Nan 
65*fca08f32SWang Nan #ifndef test_alu_write_pc_interworking
66*fca08f32SWang Nan 
67*fca08f32SWang Nan bool alu_write_pc_interworks;
68*fca08f32SWang Nan 
69*fca08f32SWang Nan void __init test_alu_write_pc_interworking(void)
70*fca08f32SWang Nan {
71*fca08f32SWang Nan 	int arch = cpu_architecture();
72*fca08f32SWang Nan 	BUG_ON(arch == CPU_ARCH_UNKNOWN);
73*fca08f32SWang Nan 	alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7;
74*fca08f32SWang Nan }
75*fca08f32SWang Nan 
76*fca08f32SWang Nan #endif /* !test_alu_write_pc_interworking */
77*fca08f32SWang Nan 
78*fca08f32SWang Nan 
79*fca08f32SWang Nan void __init arm_probes_decode_init(void)
80*fca08f32SWang Nan {
81*fca08f32SWang Nan 	find_str_pc_offset();
82*fca08f32SWang Nan 	test_load_write_pc_interworking();
83*fca08f32SWang Nan 	test_alu_write_pc_interworking();
84*fca08f32SWang Nan }
85*fca08f32SWang Nan 
86*fca08f32SWang Nan 
87*fca08f32SWang Nan static unsigned long __kprobes __check_eq(unsigned long cpsr)
88*fca08f32SWang Nan {
89*fca08f32SWang Nan 	return cpsr & PSR_Z_BIT;
90*fca08f32SWang Nan }
91*fca08f32SWang Nan 
92*fca08f32SWang Nan static unsigned long __kprobes __check_ne(unsigned long cpsr)
93*fca08f32SWang Nan {
94*fca08f32SWang Nan 	return (~cpsr) & PSR_Z_BIT;
95*fca08f32SWang Nan }
96*fca08f32SWang Nan 
97*fca08f32SWang Nan static unsigned long __kprobes __check_cs(unsigned long cpsr)
98*fca08f32SWang Nan {
99*fca08f32SWang Nan 	return cpsr & PSR_C_BIT;
100*fca08f32SWang Nan }
101*fca08f32SWang Nan 
102*fca08f32SWang Nan static unsigned long __kprobes __check_cc(unsigned long cpsr)
103*fca08f32SWang Nan {
104*fca08f32SWang Nan 	return (~cpsr) & PSR_C_BIT;
105*fca08f32SWang Nan }
106*fca08f32SWang Nan 
107*fca08f32SWang Nan static unsigned long __kprobes __check_mi(unsigned long cpsr)
108*fca08f32SWang Nan {
109*fca08f32SWang Nan 	return cpsr & PSR_N_BIT;
110*fca08f32SWang Nan }
111*fca08f32SWang Nan 
112*fca08f32SWang Nan static unsigned long __kprobes __check_pl(unsigned long cpsr)
113*fca08f32SWang Nan {
114*fca08f32SWang Nan 	return (~cpsr) & PSR_N_BIT;
115*fca08f32SWang Nan }
116*fca08f32SWang Nan 
117*fca08f32SWang Nan static unsigned long __kprobes __check_vs(unsigned long cpsr)
118*fca08f32SWang Nan {
119*fca08f32SWang Nan 	return cpsr & PSR_V_BIT;
120*fca08f32SWang Nan }
121*fca08f32SWang Nan 
122*fca08f32SWang Nan static unsigned long __kprobes __check_vc(unsigned long cpsr)
123*fca08f32SWang Nan {
124*fca08f32SWang Nan 	return (~cpsr) & PSR_V_BIT;
125*fca08f32SWang Nan }
126*fca08f32SWang Nan 
127*fca08f32SWang Nan static unsigned long __kprobes __check_hi(unsigned long cpsr)
128*fca08f32SWang Nan {
129*fca08f32SWang Nan 	cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
130*fca08f32SWang Nan 	return cpsr & PSR_C_BIT;
131*fca08f32SWang Nan }
132*fca08f32SWang Nan 
133*fca08f32SWang Nan static unsigned long __kprobes __check_ls(unsigned long cpsr)
134*fca08f32SWang Nan {
135*fca08f32SWang Nan 	cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
136*fca08f32SWang Nan 	return (~cpsr) & PSR_C_BIT;
137*fca08f32SWang Nan }
138*fca08f32SWang Nan 
139*fca08f32SWang Nan static unsigned long __kprobes __check_ge(unsigned long cpsr)
140*fca08f32SWang Nan {
141*fca08f32SWang Nan 	cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
142*fca08f32SWang Nan 	return (~cpsr) & PSR_N_BIT;
143*fca08f32SWang Nan }
144*fca08f32SWang Nan 
145*fca08f32SWang Nan static unsigned long __kprobes __check_lt(unsigned long cpsr)
146*fca08f32SWang Nan {
147*fca08f32SWang Nan 	cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
148*fca08f32SWang Nan 	return cpsr & PSR_N_BIT;
149*fca08f32SWang Nan }
150*fca08f32SWang Nan 
151*fca08f32SWang Nan static unsigned long __kprobes __check_gt(unsigned long cpsr)
152*fca08f32SWang Nan {
153*fca08f32SWang Nan 	unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
154*fca08f32SWang Nan 	temp |= (cpsr << 1);			 /* PSR_N_BIT |= PSR_Z_BIT */
155*fca08f32SWang Nan 	return (~temp) & PSR_N_BIT;
156*fca08f32SWang Nan }
157*fca08f32SWang Nan 
158*fca08f32SWang Nan static unsigned long __kprobes __check_le(unsigned long cpsr)
159*fca08f32SWang Nan {
160*fca08f32SWang Nan 	unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
161*fca08f32SWang Nan 	temp |= (cpsr << 1);			 /* PSR_N_BIT |= PSR_Z_BIT */
162*fca08f32SWang Nan 	return temp & PSR_N_BIT;
163*fca08f32SWang Nan }
164*fca08f32SWang Nan 
165*fca08f32SWang Nan static unsigned long __kprobes __check_al(unsigned long cpsr)
166*fca08f32SWang Nan {
167*fca08f32SWang Nan 	return true;
168*fca08f32SWang Nan }
169*fca08f32SWang Nan 
170*fca08f32SWang Nan probes_check_cc * const probes_condition_checks[16] = {
171*fca08f32SWang Nan 	&__check_eq, &__check_ne, &__check_cs, &__check_cc,
172*fca08f32SWang Nan 	&__check_mi, &__check_pl, &__check_vs, &__check_vc,
173*fca08f32SWang Nan 	&__check_hi, &__check_ls, &__check_ge, &__check_lt,
174*fca08f32SWang Nan 	&__check_gt, &__check_le, &__check_al, &__check_al
175*fca08f32SWang Nan };
176*fca08f32SWang Nan 
177*fca08f32SWang Nan 
178*fca08f32SWang Nan void __kprobes probes_simulate_nop(probes_opcode_t opcode,
179*fca08f32SWang Nan 	struct arch_probes_insn *asi,
180*fca08f32SWang Nan 	struct pt_regs *regs)
181*fca08f32SWang Nan {
182*fca08f32SWang Nan }
183*fca08f32SWang Nan 
184*fca08f32SWang Nan void __kprobes probes_emulate_none(probes_opcode_t opcode,
185*fca08f32SWang Nan 	struct arch_probes_insn *asi,
186*fca08f32SWang Nan 	struct pt_regs *regs)
187*fca08f32SWang Nan {
188*fca08f32SWang Nan 	asi->insn_fn();
189*fca08f32SWang Nan }
190*fca08f32SWang Nan 
191*fca08f32SWang Nan /*
192*fca08f32SWang Nan  * Prepare an instruction slot to receive an instruction for emulating.
193*fca08f32SWang Nan  * This is done by placing a subroutine return after the location where the
194*fca08f32SWang Nan  * instruction will be placed. We also modify ARM instructions to be
195*fca08f32SWang Nan  * unconditional as the condition code will already be checked before any
196*fca08f32SWang Nan  * emulation handler is called.
197*fca08f32SWang Nan  */
198*fca08f32SWang Nan static probes_opcode_t __kprobes
199*fca08f32SWang Nan prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
200*fca08f32SWang Nan 		      bool thumb)
201*fca08f32SWang Nan {
202*fca08f32SWang Nan #ifdef CONFIG_THUMB2_KERNEL
203*fca08f32SWang Nan 	if (thumb) {
204*fca08f32SWang Nan 		u16 *thumb_insn = (u16 *)asi->insn;
205*fca08f32SWang Nan 		/* Thumb bx lr */
206*fca08f32SWang Nan 		thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
207*fca08f32SWang Nan 		thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
208*fca08f32SWang Nan 		return insn;
209*fca08f32SWang Nan 	}
210*fca08f32SWang Nan 	asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
211*fca08f32SWang Nan #else
212*fca08f32SWang Nan 	asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
213*fca08f32SWang Nan #endif
214*fca08f32SWang Nan 	/* Make an ARM instruction unconditional */
215*fca08f32SWang Nan 	if (insn < 0xe0000000)
216*fca08f32SWang Nan 		insn = (insn | 0xe0000000) & ~0x10000000;
217*fca08f32SWang Nan 	return insn;
218*fca08f32SWang Nan }
219*fca08f32SWang Nan 
220*fca08f32SWang Nan /*
221*fca08f32SWang Nan  * Write a (probably modified) instruction into the slot previously prepared by
222*fca08f32SWang Nan  * prepare_emulated_insn
223*fca08f32SWang Nan  */
224*fca08f32SWang Nan static void  __kprobes
225*fca08f32SWang Nan set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
226*fca08f32SWang Nan 		  bool thumb)
227*fca08f32SWang Nan {
228*fca08f32SWang Nan #ifdef CONFIG_THUMB2_KERNEL
229*fca08f32SWang Nan 	if (thumb) {
230*fca08f32SWang Nan 		u16 *ip = (u16 *)asi->insn;
231*fca08f32SWang Nan 		if (is_wide_instruction(insn))
232*fca08f32SWang Nan 			*ip++ = __opcode_to_mem_thumb16(insn >> 16);
233*fca08f32SWang Nan 		*ip++ = __opcode_to_mem_thumb16(insn);
234*fca08f32SWang Nan 		return;
235*fca08f32SWang Nan 	}
236*fca08f32SWang Nan #endif
237*fca08f32SWang Nan 	asi->insn[0] = __opcode_to_mem_arm(insn);
238*fca08f32SWang Nan }
239*fca08f32SWang Nan 
240*fca08f32SWang Nan /*
241*fca08f32SWang Nan  * When we modify the register numbers encoded in an instruction to be emulated,
242*fca08f32SWang Nan  * the new values come from this define. For ARM and 32-bit Thumb instructions
243*fca08f32SWang Nan  * this gives...
244*fca08f32SWang Nan  *
245*fca08f32SWang Nan  *	bit position	  16  12   8   4   0
246*fca08f32SWang Nan  *	---------------+---+---+---+---+---+
247*fca08f32SWang Nan  *	register	 r2  r0  r1  --  r3
248*fca08f32SWang Nan  */
249*fca08f32SWang Nan #define INSN_NEW_BITS		0x00020103
250*fca08f32SWang Nan 
251*fca08f32SWang Nan /* Each nibble has same value as that at INSN_NEW_BITS bit 16 */
252*fca08f32SWang Nan #define INSN_SAMEAS16_BITS	0x22222222
253*fca08f32SWang Nan 
254*fca08f32SWang Nan /*
255*fca08f32SWang Nan  * Validate and modify each of the registers encoded in an instruction.
256*fca08f32SWang Nan  *
257*fca08f32SWang Nan  * Each nibble in regs contains a value from enum decode_reg_type. For each
258*fca08f32SWang Nan  * non-zero value, the corresponding nibble in pinsn is validated and modified
259*fca08f32SWang Nan  * according to the type.
260*fca08f32SWang Nan  */
261*fca08f32SWang Nan static bool __kprobes decode_regs(probes_opcode_t *pinsn, u32 regs, bool modify)
262*fca08f32SWang Nan {
263*fca08f32SWang Nan 	probes_opcode_t insn = *pinsn;
264*fca08f32SWang Nan 	probes_opcode_t mask = 0xf; /* Start at least significant nibble */
265*fca08f32SWang Nan 
266*fca08f32SWang Nan 	for (; regs != 0; regs >>= 4, mask <<= 4) {
267*fca08f32SWang Nan 
268*fca08f32SWang Nan 		probes_opcode_t new_bits = INSN_NEW_BITS;
269*fca08f32SWang Nan 
270*fca08f32SWang Nan 		switch (regs & 0xf) {
271*fca08f32SWang Nan 
272*fca08f32SWang Nan 		case REG_TYPE_NONE:
273*fca08f32SWang Nan 			/* Nibble not a register, skip to next */
274*fca08f32SWang Nan 			continue;
275*fca08f32SWang Nan 
276*fca08f32SWang Nan 		case REG_TYPE_ANY:
277*fca08f32SWang Nan 			/* Any register is allowed */
278*fca08f32SWang Nan 			break;
279*fca08f32SWang Nan 
280*fca08f32SWang Nan 		case REG_TYPE_SAMEAS16:
281*fca08f32SWang Nan 			/* Replace register with same as at bit position 16 */
282*fca08f32SWang Nan 			new_bits = INSN_SAMEAS16_BITS;
283*fca08f32SWang Nan 			break;
284*fca08f32SWang Nan 
285*fca08f32SWang Nan 		case REG_TYPE_SP:
286*fca08f32SWang Nan 			/* Only allow SP (R13) */
287*fca08f32SWang Nan 			if ((insn ^ 0xdddddddd) & mask)
288*fca08f32SWang Nan 				goto reject;
289*fca08f32SWang Nan 			break;
290*fca08f32SWang Nan 
291*fca08f32SWang Nan 		case REG_TYPE_PC:
292*fca08f32SWang Nan 			/* Only allow PC (R15) */
293*fca08f32SWang Nan 			if ((insn ^ 0xffffffff) & mask)
294*fca08f32SWang Nan 				goto reject;
295*fca08f32SWang Nan 			break;
296*fca08f32SWang Nan 
297*fca08f32SWang Nan 		case REG_TYPE_NOSP:
298*fca08f32SWang Nan 			/* Reject SP (R13) */
299*fca08f32SWang Nan 			if (((insn ^ 0xdddddddd) & mask) == 0)
300*fca08f32SWang Nan 				goto reject;
301*fca08f32SWang Nan 			break;
302*fca08f32SWang Nan 
303*fca08f32SWang Nan 		case REG_TYPE_NOSPPC:
304*fca08f32SWang Nan 		case REG_TYPE_NOSPPCX:
305*fca08f32SWang Nan 			/* Reject SP and PC (R13 and R15) */
306*fca08f32SWang Nan 			if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0)
307*fca08f32SWang Nan 				goto reject;
308*fca08f32SWang Nan 			break;
309*fca08f32SWang Nan 
310*fca08f32SWang Nan 		case REG_TYPE_NOPCWB:
311*fca08f32SWang Nan 			if (!is_writeback(insn))
312*fca08f32SWang Nan 				break; /* No writeback, so any register is OK */
313*fca08f32SWang Nan 			/* fall through... */
314*fca08f32SWang Nan 		case REG_TYPE_NOPC:
315*fca08f32SWang Nan 		case REG_TYPE_NOPCX:
316*fca08f32SWang Nan 			/* Reject PC (R15) */
317*fca08f32SWang Nan 			if (((insn ^ 0xffffffff) & mask) == 0)
318*fca08f32SWang Nan 				goto reject;
319*fca08f32SWang Nan 			break;
320*fca08f32SWang Nan 		}
321*fca08f32SWang Nan 
322*fca08f32SWang Nan 		/* Replace value of nibble with new register number... */
323*fca08f32SWang Nan 		insn &= ~mask;
324*fca08f32SWang Nan 		insn |= new_bits & mask;
325*fca08f32SWang Nan 	}
326*fca08f32SWang Nan 
327*fca08f32SWang Nan 	if (modify)
328*fca08f32SWang Nan 		*pinsn = insn;
329*fca08f32SWang Nan 
330*fca08f32SWang Nan 	return true;
331*fca08f32SWang Nan 
332*fca08f32SWang Nan reject:
333*fca08f32SWang Nan 	return false;
334*fca08f32SWang Nan }
335*fca08f32SWang Nan 
336*fca08f32SWang Nan static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
337*fca08f32SWang Nan 	[DECODE_TYPE_TABLE]	= sizeof(struct decode_table),
338*fca08f32SWang Nan 	[DECODE_TYPE_CUSTOM]	= sizeof(struct decode_custom),
339*fca08f32SWang Nan 	[DECODE_TYPE_SIMULATE]	= sizeof(struct decode_simulate),
340*fca08f32SWang Nan 	[DECODE_TYPE_EMULATE]	= sizeof(struct decode_emulate),
341*fca08f32SWang Nan 	[DECODE_TYPE_OR]	= sizeof(struct decode_or),
342*fca08f32SWang Nan 	[DECODE_TYPE_REJECT]	= sizeof(struct decode_reject)
343*fca08f32SWang Nan };
344*fca08f32SWang Nan 
345*fca08f32SWang Nan /*
346*fca08f32SWang Nan  * probes_decode_insn operates on data tables in order to decode an ARM
347*fca08f32SWang Nan  * architecture instruction onto which a kprobe has been placed.
348*fca08f32SWang Nan  *
349*fca08f32SWang Nan  * These instruction decoding tables are a concatenation of entries each
350*fca08f32SWang Nan  * of which consist of one of the following structs:
351*fca08f32SWang Nan  *
352*fca08f32SWang Nan  *	decode_table
353*fca08f32SWang Nan  *	decode_custom
354*fca08f32SWang Nan  *	decode_simulate
355*fca08f32SWang Nan  *	decode_emulate
356*fca08f32SWang Nan  *	decode_or
357*fca08f32SWang Nan  *	decode_reject
358*fca08f32SWang Nan  *
359*fca08f32SWang Nan  * Each of these starts with a struct decode_header which has the following
360*fca08f32SWang Nan  * fields:
361*fca08f32SWang Nan  *
362*fca08f32SWang Nan  *	type_regs
363*fca08f32SWang Nan  *	mask
364*fca08f32SWang Nan  *	value
365*fca08f32SWang Nan  *
366*fca08f32SWang Nan  * The least significant DECODE_TYPE_BITS of type_regs contains a value
367*fca08f32SWang Nan  * from enum decode_type, this indicates which of the decode_* structs
368*fca08f32SWang Nan  * the entry contains. The value DECODE_TYPE_END indicates the end of the
369*fca08f32SWang Nan  * table.
370*fca08f32SWang Nan  *
371*fca08f32SWang Nan  * When the table is parsed, each entry is checked in turn to see if it
372*fca08f32SWang Nan  * matches the instruction to be decoded using the test:
373*fca08f32SWang Nan  *
374*fca08f32SWang Nan  *	(insn & mask) == value
375*fca08f32SWang Nan  *
376*fca08f32SWang Nan  * If no match is found before the end of the table is reached then decoding
377*fca08f32SWang Nan  * fails with INSN_REJECTED.
378*fca08f32SWang Nan  *
379*fca08f32SWang Nan  * When a match is found, decode_regs() is called to validate and modify each
380*fca08f32SWang Nan  * of the registers encoded in the instruction; the data it uses to do this
381*fca08f32SWang Nan  * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding
382*fca08f32SWang Nan  * to fail with INSN_REJECTED.
383*fca08f32SWang Nan  *
384*fca08f32SWang Nan  * Once the instruction has passed the above tests, further processing
385*fca08f32SWang Nan  * depends on the type of the table entry's decode struct.
386*fca08f32SWang Nan  *
387*fca08f32SWang Nan  */
388*fca08f32SWang Nan int __kprobes
389*fca08f32SWang Nan probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
390*fca08f32SWang Nan 		   const union decode_item *table, bool thumb,
391*fca08f32SWang Nan 		   bool emulate, const union decode_action *actions)
392*fca08f32SWang Nan {
393*fca08f32SWang Nan 	const struct decode_header *h = (struct decode_header *)table;
394*fca08f32SWang Nan 	const struct decode_header *next;
395*fca08f32SWang Nan 	bool matched = false;
396*fca08f32SWang Nan 
397*fca08f32SWang Nan 	if (emulate)
398*fca08f32SWang Nan 		insn = prepare_emulated_insn(insn, asi, thumb);
399*fca08f32SWang Nan 
400*fca08f32SWang Nan 	for (;; h = next) {
401*fca08f32SWang Nan 		enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
402*fca08f32SWang Nan 		u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS;
403*fca08f32SWang Nan 
404*fca08f32SWang Nan 		if (type == DECODE_TYPE_END)
405*fca08f32SWang Nan 			return INSN_REJECTED;
406*fca08f32SWang Nan 
407*fca08f32SWang Nan 		next = (struct decode_header *)
408*fca08f32SWang Nan 				((uintptr_t)h + decode_struct_sizes[type]);
409*fca08f32SWang Nan 
410*fca08f32SWang Nan 		if (!matched && (insn & h->mask.bits) != h->value.bits)
411*fca08f32SWang Nan 			continue;
412*fca08f32SWang Nan 
413*fca08f32SWang Nan 		if (!decode_regs(&insn, regs, emulate))
414*fca08f32SWang Nan 			return INSN_REJECTED;
415*fca08f32SWang Nan 
416*fca08f32SWang Nan 		switch (type) {
417*fca08f32SWang Nan 
418*fca08f32SWang Nan 		case DECODE_TYPE_TABLE: {
419*fca08f32SWang Nan 			struct decode_table *d = (struct decode_table *)h;
420*fca08f32SWang Nan 			next = (struct decode_header *)d->table.table;
421*fca08f32SWang Nan 			break;
422*fca08f32SWang Nan 		}
423*fca08f32SWang Nan 
424*fca08f32SWang Nan 		case DECODE_TYPE_CUSTOM: {
425*fca08f32SWang Nan 			struct decode_custom *d = (struct decode_custom *)h;
426*fca08f32SWang Nan 			return actions[d->decoder.action].decoder(insn, asi, h);
427*fca08f32SWang Nan 		}
428*fca08f32SWang Nan 
429*fca08f32SWang Nan 		case DECODE_TYPE_SIMULATE: {
430*fca08f32SWang Nan 			struct decode_simulate *d = (struct decode_simulate *)h;
431*fca08f32SWang Nan 			asi->insn_handler = actions[d->handler.action].handler;
432*fca08f32SWang Nan 			return INSN_GOOD_NO_SLOT;
433*fca08f32SWang Nan 		}
434*fca08f32SWang Nan 
435*fca08f32SWang Nan 		case DECODE_TYPE_EMULATE: {
436*fca08f32SWang Nan 			struct decode_emulate *d = (struct decode_emulate *)h;
437*fca08f32SWang Nan 
438*fca08f32SWang Nan 			if (!emulate)
439*fca08f32SWang Nan 				return actions[d->handler.action].decoder(insn,
440*fca08f32SWang Nan 					asi, h);
441*fca08f32SWang Nan 
442*fca08f32SWang Nan 			asi->insn_handler = actions[d->handler.action].handler;
443*fca08f32SWang Nan 			set_emulated_insn(insn, asi, thumb);
444*fca08f32SWang Nan 			return INSN_GOOD;
445*fca08f32SWang Nan 		}
446*fca08f32SWang Nan 
447*fca08f32SWang Nan 		case DECODE_TYPE_OR:
448*fca08f32SWang Nan 			matched = true;
449*fca08f32SWang Nan 			break;
450*fca08f32SWang Nan 
451*fca08f32SWang Nan 		case DECODE_TYPE_REJECT:
452*fca08f32SWang Nan 		default:
453*fca08f32SWang Nan 			return INSN_REJECTED;
454*fca08f32SWang Nan 		}
455*fca08f32SWang Nan 	}
456*fca08f32SWang Nan }
457