Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 : : #ifndef _ASM_X86_INSN_H 3 : : #define _ASM_X86_INSN_H 4 : : /* 5 : : * x86 instruction analysis 6 : : * 7 : : * Copyright (C) IBM Corporation, 2009 8 : : */ 9 : : 10 : : /* insn_attr_t is defined in inat.h */ 11 : : #include <asm/inat.h> 12 : : 13 : : struct insn_field { 14 : : union { 15 : : insn_value_t value; 16 : : insn_byte_t bytes[4]; 17 : : }; 18 : : /* !0 if we've run insn_get_xxx() for this field */ 19 : : unsigned char got; 20 : : unsigned char nbytes; 21 : : }; 22 : : 23 : : struct insn { 24 : : struct insn_field prefixes; /* 25 : : * Prefixes 26 : : * prefixes.bytes[3]: last prefix 27 : : */ 28 : : struct insn_field rex_prefix; /* REX prefix */ 29 : : struct insn_field vex_prefix; /* VEX prefix */ 30 : : struct insn_field opcode; /* 31 : : * opcode.bytes[0]: opcode1 32 : : * opcode.bytes[1]: opcode2 33 : : * opcode.bytes[2]: opcode3 34 : : */ 35 : : struct insn_field modrm; 36 : : struct insn_field sib; 37 : : struct insn_field displacement; 38 : : union { 39 : : struct insn_field immediate; 40 : : struct insn_field moffset1; /* for 64bit MOV */ 41 : : struct insn_field immediate1; /* for 64bit imm or off16/32 */ 42 : : }; 43 : : union { 44 : : struct insn_field moffset2; /* for 64bit MOV */ 45 : : struct insn_field immediate2; /* for 64bit imm or seg16 */ 46 : : }; 47 : : 48 : : int emulate_prefix_size; 49 : : insn_attr_t attr; 50 : : unsigned char opnd_bytes; 51 : : unsigned char addr_bytes; 52 : : unsigned char length; 53 : : unsigned char x86_64; 54 : : 55 : : const insn_byte_t *kaddr; /* kernel address of insn to analyze */ 56 : : const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ 57 : : const insn_byte_t *next_byte; 58 : : }; 59 : : 60 : : #define MAX_INSN_SIZE 15 61 : : 62 : : #define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) 63 : : #define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) 64 : : #define X86_MODRM_RM(modrm) ((modrm) & 0x07) 65 : : 66 : : #define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) 67 : : #define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) 68 : : #define X86_SIB_BASE(sib) ((sib) & 0x07) 69 : : 70 : : #define X86_REX_W(rex) ((rex) & 8) 71 : : #define X86_REX_R(rex) ((rex) & 4) 72 : : #define X86_REX_X(rex) ((rex) & 2) 73 : : #define X86_REX_B(rex) ((rex) & 1) 74 : : 75 : : /* VEX bit flags */ 76 : : #define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ 77 : : #define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ 78 : : #define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ 79 : : #define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ 80 : : #define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ 81 : : /* VEX bit fields */ 82 : : #define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ 83 : : #define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ 84 : : #define X86_VEX2_M 1 /* VEX2.M always 1 */ 85 : : #define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ 86 : : #define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ 87 : : #define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ 88 : : 89 : : extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); 90 : : extern void insn_get_prefixes(struct insn *insn); 91 : : extern void insn_get_opcode(struct insn *insn); 92 : : extern void insn_get_modrm(struct insn *insn); 93 : : extern void insn_get_sib(struct insn *insn); 94 : : extern void insn_get_displacement(struct insn *insn); 95 : : extern void insn_get_immediate(struct insn *insn); 96 : : extern void insn_get_length(struct insn *insn); 97 : : 98 : : /* Attribute will be determined after getting ModRM (for opcode groups) */ 99 : : static inline void insn_get_attribute(struct insn *insn) 100 : : { 101 : : insn_get_modrm(insn); 102 : : } 103 : : 104 : : /* Instruction uses RIP-relative addressing */ 105 : : extern int insn_rip_relative(struct insn *insn); 106 : : 107 : : /* Init insn for kernel text */ 108 : 1650 : static inline void kernel_insn_init(struct insn *insn, 109 : : const void *kaddr, int buf_len) 110 : : { 111 : : #ifdef CONFIG_X86_64 112 : 1650 : insn_init(insn, kaddr, buf_len, 1); 113 : : #else /* CONFIG_X86_32 */ 114 : : insn_init(insn, kaddr, buf_len, 0); 115 : : #endif 116 : : } 117 : : 118 : 1650 : static inline int insn_is_avx(struct insn *insn) 119 : : { 120 [ - - - + ]: 1650 : if (!insn->prefixes.got) 121 : 0 : insn_get_prefixes(insn); 122 [ - - - + ]: 1650 : return (insn->vex_prefix.value != 0); 123 : : } 124 : : 125 : 0 : static inline int insn_is_evex(struct insn *insn) 126 : : { 127 [ # # ]: 0 : if (!insn->prefixes.got) 128 : 0 : insn_get_prefixes(insn); 129 [ # # ]: 0 : return (insn->vex_prefix.nbytes == 4); 130 : : } 131 : : 132 : 0 : static inline int insn_has_emulate_prefix(struct insn *insn) 133 : : { 134 [ # # ]: 0 : return !!insn->emulate_prefix_size; 135 : : } 136 : : 137 : : /* Ensure this instruction is decoded completely */ 138 : 1650 : static inline int insn_complete(struct insn *insn) 139 : : { 140 [ + - + - ]: 1650 : return insn->opcode.got && insn->modrm.got && insn->sib.got && 141 [ + - + - : 3300 : insn->displacement.got && insn->immediate.got; - + ] 142 : : } 143 : : 144 : 0 : static inline insn_byte_t insn_vex_m_bits(struct insn *insn) 145 : : { 146 [ # # ]: 0 : if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 147 : : return X86_VEX2_M; 148 [ # # ]: 0 : else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ 149 : 0 : return X86_VEX3_M(insn->vex_prefix.bytes[1]); 150 : : else /* EVEX */ 151 : 0 : return X86_EVEX_M(insn->vex_prefix.bytes[1]); 152 : : } 153 : : 154 : 0 : static inline insn_byte_t insn_vex_p_bits(struct insn *insn) 155 : : { 156 [ # # ]: 0 : if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 157 : 0 : return X86_VEX_P(insn->vex_prefix.bytes[1]); 158 : : else 159 : 0 : return X86_VEX_P(insn->vex_prefix.bytes[2]); 160 : : } 161 : : 162 : : /* Get the last prefix id from last prefix or VEX prefix */ 163 : 0 : static inline int insn_last_prefix_id(struct insn *insn) 164 : : { 165 [ # # # # ]: 0 : if (insn_is_avx(insn)) 166 [ # # ]: 0 : return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ 167 : : 168 [ # # ]: 0 : if (insn->prefixes.bytes[3]) 169 : 0 : return inat_get_last_prefix_id(insn->prefixes.bytes[3]); 170 : : 171 : : return 0; 172 : : } 173 : : 174 : : /* Offset of each field from kaddr */ 175 : 0 : static inline int insn_offset_rex_prefix(struct insn *insn) 176 : : { 177 : 0 : return insn->prefixes.nbytes; 178 : : } 179 : 0 : static inline int insn_offset_vex_prefix(struct insn *insn) 180 : : { 181 : 0 : return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; 182 : : } 183 : 0 : static inline int insn_offset_opcode(struct insn *insn) 184 : : { 185 : 0 : return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; 186 : : } 187 : 0 : static inline int insn_offset_modrm(struct insn *insn) 188 : : { 189 : 0 : return insn_offset_opcode(insn) + insn->opcode.nbytes; 190 : : } 191 : 0 : static inline int insn_offset_sib(struct insn *insn) 192 : : { 193 : 0 : return insn_offset_modrm(insn) + insn->modrm.nbytes; 194 : : } 195 : 0 : static inline int insn_offset_displacement(struct insn *insn) 196 : : { 197 : 0 : return insn_offset_sib(insn) + insn->sib.nbytes; 198 : : } 199 : 0 : static inline int insn_offset_immediate(struct insn *insn) 200 : : { 201 : 0 : return insn_offset_displacement(insn) + insn->displacement.nbytes; 202 : : } 203 : : 204 : : #define POP_SS_OPCODE 0x1f 205 : : #define MOV_SREG_OPCODE 0x8e 206 : : 207 : : /* 208 : : * Intel SDM Vol.3A 6.8.3 states; 209 : : * "Any single-step trap that would be delivered following the MOV to SS 210 : : * instruction or POP to SS instruction (because EFLAGS.TF is 1) is 211 : : * suppressed." 212 : : * This function returns true if @insn is MOV SS or POP SS. On these 213 : : * instructions, single stepping is suppressed. 214 : : */ 215 : 0 : static inline int insn_masking_exception(struct insn *insn) 216 : : { 217 [ # # # # ]: 0 : return insn->opcode.bytes[0] == POP_SS_OPCODE || 218 : 0 : (insn->opcode.bytes[0] == MOV_SREG_OPCODE && 219 [ # # ]: 0 : X86_MODRM_REG(insn->modrm.bytes[0]) == 2); 220 : : } 221 : : 222 : : #endif /* _ASM_X86_INSN_H */