18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_INSN_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_INSN_H 48c2ecf20Sopenharmony_ci/* 58c2ecf20Sopenharmony_ci * x86 instruction analysis 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) IBM Corporation, 2009 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* insn_attr_t is defined in inat.h */ 118c2ecf20Sopenharmony_ci#include "inat.h" /* __ignore_sync_check__ */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistruct insn_field { 148c2ecf20Sopenharmony_ci union { 158c2ecf20Sopenharmony_ci insn_value_t value; 168c2ecf20Sopenharmony_ci insn_byte_t bytes[4]; 178c2ecf20Sopenharmony_ci }; 188c2ecf20Sopenharmony_ci /* !0 if we've run insn_get_xxx() for this field */ 198c2ecf20Sopenharmony_ci unsigned char got; 208c2ecf20Sopenharmony_ci unsigned char nbytes; 218c2ecf20Sopenharmony_ci}; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct insn { 248c2ecf20Sopenharmony_ci struct insn_field prefixes; /* 258c2ecf20Sopenharmony_ci * Prefixes 268c2ecf20Sopenharmony_ci * prefixes.bytes[3]: last prefix 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci struct insn_field rex_prefix; /* REX prefix */ 298c2ecf20Sopenharmony_ci struct insn_field vex_prefix; /* VEX prefix */ 308c2ecf20Sopenharmony_ci struct insn_field opcode; /* 318c2ecf20Sopenharmony_ci * opcode.bytes[0]: opcode1 328c2ecf20Sopenharmony_ci * opcode.bytes[1]: opcode2 338c2ecf20Sopenharmony_ci * opcode.bytes[2]: opcode3 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci struct insn_field modrm; 368c2ecf20Sopenharmony_ci struct insn_field sib; 378c2ecf20Sopenharmony_ci struct insn_field displacement; 388c2ecf20Sopenharmony_ci union { 398c2ecf20Sopenharmony_ci struct insn_field immediate; 408c2ecf20Sopenharmony_ci struct insn_field moffset1; /* for 64bit MOV */ 418c2ecf20Sopenharmony_ci struct insn_field immediate1; /* for 64bit imm or off16/32 */ 428c2ecf20Sopenharmony_ci }; 438c2ecf20Sopenharmony_ci union { 448c2ecf20Sopenharmony_ci struct insn_field moffset2; /* for 64bit MOV */ 458c2ecf20Sopenharmony_ci struct insn_field immediate2; /* for 64bit imm or seg16 */ 468c2ecf20Sopenharmony_ci }; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci int emulate_prefix_size; 498c2ecf20Sopenharmony_ci insn_attr_t attr; 508c2ecf20Sopenharmony_ci unsigned char opnd_bytes; 518c2ecf20Sopenharmony_ci unsigned char addr_bytes; 528c2ecf20Sopenharmony_ci unsigned char length; 538c2ecf20Sopenharmony_ci unsigned char x86_64; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci const insn_byte_t *kaddr; /* kernel address of insn to analyze */ 568c2ecf20Sopenharmony_ci const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ 578c2ecf20Sopenharmony_ci const insn_byte_t *next_byte; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define MAX_INSN_SIZE 15 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) 638c2ecf20Sopenharmony_ci#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) 648c2ecf20Sopenharmony_ci#define X86_MODRM_RM(modrm) ((modrm) & 0x07) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) 678c2ecf20Sopenharmony_ci#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) 688c2ecf20Sopenharmony_ci#define X86_SIB_BASE(sib) ((sib) & 0x07) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define X86_REX_W(rex) ((rex) & 8) 718c2ecf20Sopenharmony_ci#define X86_REX_R(rex) ((rex) & 4) 728c2ecf20Sopenharmony_ci#define X86_REX_X(rex) ((rex) & 2) 738c2ecf20Sopenharmony_ci#define X86_REX_B(rex) ((rex) & 1) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* VEX bit flags */ 768c2ecf20Sopenharmony_ci#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ 778c2ecf20Sopenharmony_ci#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ 788c2ecf20Sopenharmony_ci#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ 798c2ecf20Sopenharmony_ci#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ 808c2ecf20Sopenharmony_ci#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ 818c2ecf20Sopenharmony_ci/* VEX bit fields */ 828c2ecf20Sopenharmony_ci#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ 838c2ecf20Sopenharmony_ci#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ 848c2ecf20Sopenharmony_ci#define X86_VEX2_M 1 /* VEX2.M always 1 */ 858c2ecf20Sopenharmony_ci#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ 868c2ecf20Sopenharmony_ci#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ 878c2ecf20Sopenharmony_ci#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciextern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); 908c2ecf20Sopenharmony_ciextern int insn_get_prefixes(struct insn *insn); 918c2ecf20Sopenharmony_ciextern int insn_get_opcode(struct insn *insn); 928c2ecf20Sopenharmony_ciextern int insn_get_modrm(struct insn *insn); 938c2ecf20Sopenharmony_ciextern int insn_get_sib(struct insn *insn); 948c2ecf20Sopenharmony_ciextern int insn_get_displacement(struct insn *insn); 958c2ecf20Sopenharmony_ciextern int insn_get_immediate(struct insn *insn); 968c2ecf20Sopenharmony_ciextern int insn_get_length(struct insn *insn); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cienum insn_mode { 998c2ecf20Sopenharmony_ci INSN_MODE_32, 1008c2ecf20Sopenharmony_ci INSN_MODE_64, 1018c2ecf20Sopenharmony_ci /* Mode is determined by the current kernel build. */ 1028c2ecf20Sopenharmony_ci INSN_MODE_KERN, 1038c2ecf20Sopenharmony_ci INSN_NUM_MODES, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciextern int insn_decode(struct insn *insn, const void *kaddr, int buf_len, enum insn_mode m); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define insn_decode_kernel(_insn, _ptr) insn_decode((_insn), (_ptr), MAX_INSN_SIZE, INSN_MODE_KERN) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* Attribute will be determined after getting ModRM (for opcode groups) */ 1118c2ecf20Sopenharmony_cistatic inline void insn_get_attribute(struct insn *insn) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci insn_get_modrm(insn); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* Instruction uses RIP-relative addressing */ 1178c2ecf20Sopenharmony_ciextern int insn_rip_relative(struct insn *insn); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* Init insn for kernel text */ 1208c2ecf20Sopenharmony_cistatic inline void kernel_insn_init(struct insn *insn, 1218c2ecf20Sopenharmony_ci const void *kaddr, int buf_len) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 1248c2ecf20Sopenharmony_ci insn_init(insn, kaddr, buf_len, 1); 1258c2ecf20Sopenharmony_ci#else /* CONFIG_X86_32 */ 1268c2ecf20Sopenharmony_ci insn_init(insn, kaddr, buf_len, 0); 1278c2ecf20Sopenharmony_ci#endif 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline int insn_is_avx(struct insn *insn) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci if (!insn->prefixes.got) 1338c2ecf20Sopenharmony_ci insn_get_prefixes(insn); 1348c2ecf20Sopenharmony_ci return (insn->vex_prefix.value != 0); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic inline int insn_is_evex(struct insn *insn) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci if (!insn->prefixes.got) 1408c2ecf20Sopenharmony_ci insn_get_prefixes(insn); 1418c2ecf20Sopenharmony_ci return (insn->vex_prefix.nbytes == 4); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic inline int insn_has_emulate_prefix(struct insn *insn) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci return !!insn->emulate_prefix_size; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/* Ensure this instruction is decoded completely */ 1508c2ecf20Sopenharmony_cistatic inline int insn_complete(struct insn *insn) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return insn->opcode.got && insn->modrm.got && insn->sib.got && 1538c2ecf20Sopenharmony_ci insn->displacement.got && insn->immediate.got; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline insn_byte_t insn_vex_m_bits(struct insn *insn) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 1598c2ecf20Sopenharmony_ci return X86_VEX2_M; 1608c2ecf20Sopenharmony_ci else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ 1618c2ecf20Sopenharmony_ci return X86_VEX3_M(insn->vex_prefix.bytes[1]); 1628c2ecf20Sopenharmony_ci else /* EVEX */ 1638c2ecf20Sopenharmony_ci return X86_EVEX_M(insn->vex_prefix.bytes[1]); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic inline insn_byte_t insn_vex_p_bits(struct insn *insn) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 1698c2ecf20Sopenharmony_ci return X86_VEX_P(insn->vex_prefix.bytes[1]); 1708c2ecf20Sopenharmony_ci else 1718c2ecf20Sopenharmony_ci return X86_VEX_P(insn->vex_prefix.bytes[2]); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* Get the last prefix id from last prefix or VEX prefix */ 1758c2ecf20Sopenharmony_cistatic inline int insn_last_prefix_id(struct insn *insn) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if (insn_is_avx(insn)) 1788c2ecf20Sopenharmony_ci return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (insn->prefixes.bytes[3]) 1818c2ecf20Sopenharmony_ci return inat_get_last_prefix_id(insn->prefixes.bytes[3]); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* Offset of each field from kaddr */ 1878c2ecf20Sopenharmony_cistatic inline int insn_offset_rex_prefix(struct insn *insn) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci return insn->prefixes.nbytes; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_cistatic inline int insn_offset_vex_prefix(struct insn *insn) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_cistatic inline int insn_offset_opcode(struct insn *insn) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_cistatic inline int insn_offset_modrm(struct insn *insn) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci return insn_offset_opcode(insn) + insn->opcode.nbytes; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_cistatic inline int insn_offset_sib(struct insn *insn) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci return insn_offset_modrm(insn) + insn->modrm.nbytes; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_cistatic inline int insn_offset_displacement(struct insn *insn) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci return insn_offset_sib(insn) + insn->sib.nbytes; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_cistatic inline int insn_offset_immediate(struct insn *insn) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci return insn_offset_displacement(insn) + insn->displacement.nbytes; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/** 2178c2ecf20Sopenharmony_ci * for_each_insn_prefix() -- Iterate prefixes in the instruction 2188c2ecf20Sopenharmony_ci * @insn: Pointer to struct insn. 2198c2ecf20Sopenharmony_ci * @idx: Index storage. 2208c2ecf20Sopenharmony_ci * @prefix: Prefix byte. 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * Iterate prefix bytes of given @insn. Each prefix byte is stored in @prefix 2238c2ecf20Sopenharmony_ci * and the index is stored in @idx (note that this @idx is just for a cursor, 2248c2ecf20Sopenharmony_ci * do not change it.) 2258c2ecf20Sopenharmony_ci * Since prefixes.nbytes can be bigger than 4 if some prefixes 2268c2ecf20Sopenharmony_ci * are repeated, it cannot be used for looping over the prefixes. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci#define for_each_insn_prefix(insn, idx, prefix) \ 2298c2ecf20Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(insn->prefixes.bytes) && (prefix = insn->prefixes.bytes[idx]) != 0; idx++) 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci#define POP_SS_OPCODE 0x1f 2328c2ecf20Sopenharmony_ci#define MOV_SREG_OPCODE 0x8e 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* 2358c2ecf20Sopenharmony_ci * Intel SDM Vol.3A 6.8.3 states; 2368c2ecf20Sopenharmony_ci * "Any single-step trap that would be delivered following the MOV to SS 2378c2ecf20Sopenharmony_ci * instruction or POP to SS instruction (because EFLAGS.TF is 1) is 2388c2ecf20Sopenharmony_ci * suppressed." 2398c2ecf20Sopenharmony_ci * This function returns true if @insn is MOV SS or POP SS. On these 2408c2ecf20Sopenharmony_ci * instructions, single stepping is suppressed. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_cistatic inline int insn_masking_exception(struct insn *insn) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci return insn->opcode.bytes[0] == POP_SS_OPCODE || 2458c2ecf20Sopenharmony_ci (insn->opcode.bytes[0] == MOV_SREG_OPCODE && 2468c2ecf20Sopenharmony_ci X86_MODRM_REG(insn->modrm.bytes[0]) == 2); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci#endif /* _ASM_X86_INSN_H */ 250