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