1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   *  linux/arch/arm/kernel/opcodes.c
4   *
5   *  A32 condition code lookup feature moved from nwfpe/fpopcode.c
6   */
7  
8  #include <linux/module.h>
9  #include <asm/opcodes.h>
10  
11  #define ARM_OPCODE_CONDITION_UNCOND 0xf
12  
13  /*
14   * condition code lookup table
15   * index into the table is test code: EQ, NE, ... LT, GT, AL, NV
16   *
17   * bit position in short is condition code: NZCV
18   */
19  static const unsigned short cc_map[16] = {
20  	0xF0F0,			/* EQ == Z set            */
21  	0x0F0F,			/* NE                     */
22  	0xCCCC,			/* CS == C set            */
23  	0x3333,			/* CC                     */
24  	0xFF00,			/* MI == N set            */
25  	0x00FF,			/* PL                     */
26  	0xAAAA,			/* VS == V set            */
27  	0x5555,			/* VC                     */
28  	0x0C0C,			/* HI == C set && Z clear */
29  	0xF3F3,			/* LS == C clear || Z set */
30  	0xAA55,			/* GE == (N==V)           */
31  	0x55AA,			/* LT == (N!=V)           */
32  	0x0A05,			/* GT == (!Z && (N==V))   */
33  	0xF5FA,			/* LE == (Z || (N!=V))    */
34  	0xFFFF,			/* AL always              */
35  	0			/* NV                     */
36  };
37  
38  /*
39   * Returns:
40   * ARM_OPCODE_CONDTEST_FAIL   - if condition fails
41   * ARM_OPCODE_CONDTEST_PASS   - if condition passes (including AL)
42   * ARM_OPCODE_CONDTEST_UNCOND - if NV condition, or separate unconditional
43   *                              opcode space from v5 onwards
44   *
45   * Code that tests whether a conditional instruction would pass its condition
46   * check should check that return value == ARM_OPCODE_CONDTEST_PASS.
47   *
48   * Code that tests if a condition means that the instruction would be executed
49   * (regardless of conditional or unconditional) should instead check that the
50   * return value != ARM_OPCODE_CONDTEST_FAIL.
51   */
arm_check_condition(u32 opcode,u32 psr)52  asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr)
53  {
54  	u32 cc_bits  = opcode >> 28;
55  	u32 psr_cond = psr >> 28;
56  	unsigned int ret;
57  
58  	if (cc_bits != ARM_OPCODE_CONDITION_UNCOND) {
59  		if ((cc_map[cc_bits] >> (psr_cond)) & 1)
60  			ret = ARM_OPCODE_CONDTEST_PASS;
61  		else
62  			ret = ARM_OPCODE_CONDTEST_FAIL;
63  	} else {
64  		ret = ARM_OPCODE_CONDTEST_UNCOND;
65  	}
66  
67  	return ret;
68  }
69  EXPORT_SYMBOL_GPL(arm_check_condition);
70