162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci#ifndef _ASM_X86_INSN_H 362306a36Sopenharmony_ci#define _ASM_X86_INSN_H 462306a36Sopenharmony_ci/* 562306a36Sopenharmony_ci * x86 instruction analysis 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) IBM Corporation, 2009 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/byteorder.h> 1162306a36Sopenharmony_ci/* insn_attr_t is defined in inat.h */ 1262306a36Sopenharmony_ci#include <asm/inat.h> /* __ignore_sync_check__ */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct insn_field { 1762306a36Sopenharmony_ci union { 1862306a36Sopenharmony_ci insn_value_t value; 1962306a36Sopenharmony_ci insn_byte_t bytes[4]; 2062306a36Sopenharmony_ci }; 2162306a36Sopenharmony_ci /* !0 if we've run insn_get_xxx() for this field */ 2262306a36Sopenharmony_ci unsigned char got; 2362306a36Sopenharmony_ci unsigned char nbytes; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic inline void insn_field_set(struct insn_field *p, insn_value_t v, 2762306a36Sopenharmony_ci unsigned char n) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci p->value = v; 3062306a36Sopenharmony_ci p->nbytes = n; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic inline void insn_set_byte(struct insn_field *p, unsigned char n, 3462306a36Sopenharmony_ci insn_byte_t v) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci p->bytes[n] = v; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#else 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct insn_field { 4262306a36Sopenharmony_ci insn_value_t value; 4362306a36Sopenharmony_ci union { 4462306a36Sopenharmony_ci insn_value_t little; 4562306a36Sopenharmony_ci insn_byte_t bytes[4]; 4662306a36Sopenharmony_ci }; 4762306a36Sopenharmony_ci /* !0 if we've run insn_get_xxx() for this field */ 4862306a36Sopenharmony_ci unsigned char got; 4962306a36Sopenharmony_ci unsigned char nbytes; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic inline void insn_field_set(struct insn_field *p, insn_value_t v, 5362306a36Sopenharmony_ci unsigned char n) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci p->value = v; 5662306a36Sopenharmony_ci p->little = __cpu_to_le32(v); 5762306a36Sopenharmony_ci p->nbytes = n; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic inline void insn_set_byte(struct insn_field *p, unsigned char n, 6162306a36Sopenharmony_ci insn_byte_t v) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci p->bytes[n] = v; 6462306a36Sopenharmony_ci p->value = __le32_to_cpu(p->little); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci#endif 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct insn { 6962306a36Sopenharmony_ci struct insn_field prefixes; /* 7062306a36Sopenharmony_ci * Prefixes 7162306a36Sopenharmony_ci * prefixes.bytes[3]: last prefix 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci struct insn_field rex_prefix; /* REX prefix */ 7462306a36Sopenharmony_ci struct insn_field vex_prefix; /* VEX prefix */ 7562306a36Sopenharmony_ci struct insn_field opcode; /* 7662306a36Sopenharmony_ci * opcode.bytes[0]: opcode1 7762306a36Sopenharmony_ci * opcode.bytes[1]: opcode2 7862306a36Sopenharmony_ci * opcode.bytes[2]: opcode3 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci struct insn_field modrm; 8162306a36Sopenharmony_ci struct insn_field sib; 8262306a36Sopenharmony_ci struct insn_field displacement; 8362306a36Sopenharmony_ci union { 8462306a36Sopenharmony_ci struct insn_field immediate; 8562306a36Sopenharmony_ci struct insn_field moffset1; /* for 64bit MOV */ 8662306a36Sopenharmony_ci struct insn_field immediate1; /* for 64bit imm or off16/32 */ 8762306a36Sopenharmony_ci }; 8862306a36Sopenharmony_ci union { 8962306a36Sopenharmony_ci struct insn_field moffset2; /* for 64bit MOV */ 9062306a36Sopenharmony_ci struct insn_field immediate2; /* for 64bit imm or seg16 */ 9162306a36Sopenharmony_ci }; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci int emulate_prefix_size; 9462306a36Sopenharmony_ci insn_attr_t attr; 9562306a36Sopenharmony_ci unsigned char opnd_bytes; 9662306a36Sopenharmony_ci unsigned char addr_bytes; 9762306a36Sopenharmony_ci unsigned char length; 9862306a36Sopenharmony_ci unsigned char x86_64; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci const insn_byte_t *kaddr; /* kernel address of insn to analyze */ 10162306a36Sopenharmony_ci const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ 10262306a36Sopenharmony_ci const insn_byte_t *next_byte; 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define MAX_INSN_SIZE 15 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) 10862306a36Sopenharmony_ci#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) 10962306a36Sopenharmony_ci#define X86_MODRM_RM(modrm) ((modrm) & 0x07) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) 11262306a36Sopenharmony_ci#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) 11362306a36Sopenharmony_ci#define X86_SIB_BASE(sib) ((sib) & 0x07) 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define X86_REX_W(rex) ((rex) & 8) 11662306a36Sopenharmony_ci#define X86_REX_R(rex) ((rex) & 4) 11762306a36Sopenharmony_ci#define X86_REX_X(rex) ((rex) & 2) 11862306a36Sopenharmony_ci#define X86_REX_B(rex) ((rex) & 1) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* VEX bit flags */ 12162306a36Sopenharmony_ci#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ 12262306a36Sopenharmony_ci#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ 12362306a36Sopenharmony_ci#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ 12462306a36Sopenharmony_ci#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ 12562306a36Sopenharmony_ci#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ 12662306a36Sopenharmony_ci/* VEX bit fields */ 12762306a36Sopenharmony_ci#define X86_EVEX_M(vex) ((vex) & 0x07) /* EVEX Byte1 */ 12862306a36Sopenharmony_ci#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ 12962306a36Sopenharmony_ci#define X86_VEX2_M 1 /* VEX2.M always 1 */ 13062306a36Sopenharmony_ci#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ 13162306a36Sopenharmony_ci#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ 13262306a36Sopenharmony_ci#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciextern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); 13562306a36Sopenharmony_ciextern int insn_get_prefixes(struct insn *insn); 13662306a36Sopenharmony_ciextern int insn_get_opcode(struct insn *insn); 13762306a36Sopenharmony_ciextern int insn_get_modrm(struct insn *insn); 13862306a36Sopenharmony_ciextern int insn_get_sib(struct insn *insn); 13962306a36Sopenharmony_ciextern int insn_get_displacement(struct insn *insn); 14062306a36Sopenharmony_ciextern int insn_get_immediate(struct insn *insn); 14162306a36Sopenharmony_ciextern int insn_get_length(struct insn *insn); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cienum insn_mode { 14462306a36Sopenharmony_ci INSN_MODE_32, 14562306a36Sopenharmony_ci INSN_MODE_64, 14662306a36Sopenharmony_ci /* Mode is determined by the current kernel build. */ 14762306a36Sopenharmony_ci INSN_MODE_KERN, 14862306a36Sopenharmony_ci INSN_NUM_MODES, 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ciextern int insn_decode(struct insn *insn, const void *kaddr, int buf_len, enum insn_mode m); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define insn_decode_kernel(_insn, _ptr) insn_decode((_insn), (_ptr), MAX_INSN_SIZE, INSN_MODE_KERN) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* Attribute will be determined after getting ModRM (for opcode groups) */ 15662306a36Sopenharmony_cistatic inline void insn_get_attribute(struct insn *insn) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci insn_get_modrm(insn); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* Instruction uses RIP-relative addressing */ 16262306a36Sopenharmony_ciextern int insn_rip_relative(struct insn *insn); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic inline int insn_is_avx(struct insn *insn) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci if (!insn->prefixes.got) 16762306a36Sopenharmony_ci insn_get_prefixes(insn); 16862306a36Sopenharmony_ci return (insn->vex_prefix.value != 0); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic inline int insn_is_evex(struct insn *insn) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci if (!insn->prefixes.got) 17462306a36Sopenharmony_ci insn_get_prefixes(insn); 17562306a36Sopenharmony_ci return (insn->vex_prefix.nbytes == 4); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic inline int insn_has_emulate_prefix(struct insn *insn) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci return !!insn->emulate_prefix_size; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic inline insn_byte_t insn_vex_m_bits(struct insn *insn) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 18662306a36Sopenharmony_ci return X86_VEX2_M; 18762306a36Sopenharmony_ci else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ 18862306a36Sopenharmony_ci return X86_VEX3_M(insn->vex_prefix.bytes[1]); 18962306a36Sopenharmony_ci else /* EVEX */ 19062306a36Sopenharmony_ci return X86_EVEX_M(insn->vex_prefix.bytes[1]); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic inline insn_byte_t insn_vex_p_bits(struct insn *insn) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ 19662306a36Sopenharmony_ci return X86_VEX_P(insn->vex_prefix.bytes[1]); 19762306a36Sopenharmony_ci else 19862306a36Sopenharmony_ci return X86_VEX_P(insn->vex_prefix.bytes[2]); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/* Get the last prefix id from last prefix or VEX prefix */ 20262306a36Sopenharmony_cistatic inline int insn_last_prefix_id(struct insn *insn) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci if (insn_is_avx(insn)) 20562306a36Sopenharmony_ci return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (insn->prefixes.bytes[3]) 20862306a36Sopenharmony_ci return inat_get_last_prefix_id(insn->prefixes.bytes[3]); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci return 0; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* Offset of each field from kaddr */ 21462306a36Sopenharmony_cistatic inline int insn_offset_rex_prefix(struct insn *insn) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return insn->prefixes.nbytes; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_cistatic inline int insn_offset_vex_prefix(struct insn *insn) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_cistatic inline int insn_offset_opcode(struct insn *insn) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_cistatic inline int insn_offset_modrm(struct insn *insn) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci return insn_offset_opcode(insn) + insn->opcode.nbytes; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_cistatic inline int insn_offset_sib(struct insn *insn) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return insn_offset_modrm(insn) + insn->modrm.nbytes; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_cistatic inline int insn_offset_displacement(struct insn *insn) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci return insn_offset_sib(insn) + insn->sib.nbytes; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_cistatic inline int insn_offset_immediate(struct insn *insn) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci return insn_offset_displacement(insn) + insn->displacement.nbytes; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/** 24462306a36Sopenharmony_ci * for_each_insn_prefix() -- Iterate prefixes in the instruction 24562306a36Sopenharmony_ci * @insn: Pointer to struct insn. 24662306a36Sopenharmony_ci * @idx: Index storage. 24762306a36Sopenharmony_ci * @prefix: Prefix byte. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * Iterate prefix bytes of given @insn. Each prefix byte is stored in @prefix 25062306a36Sopenharmony_ci * and the index is stored in @idx (note that this @idx is just for a cursor, 25162306a36Sopenharmony_ci * do not change it.) 25262306a36Sopenharmony_ci * Since prefixes.nbytes can be bigger than 4 if some prefixes 25362306a36Sopenharmony_ci * are repeated, it cannot be used for looping over the prefixes. 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci#define for_each_insn_prefix(insn, idx, prefix) \ 25662306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(insn->prefixes.bytes) && (prefix = insn->prefixes.bytes[idx]) != 0; idx++) 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci#define POP_SS_OPCODE 0x1f 25962306a36Sopenharmony_ci#define MOV_SREG_OPCODE 0x8e 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* 26262306a36Sopenharmony_ci * Intel SDM Vol.3A 6.8.3 states; 26362306a36Sopenharmony_ci * "Any single-step trap that would be delivered following the MOV to SS 26462306a36Sopenharmony_ci * instruction or POP to SS instruction (because EFLAGS.TF is 1) is 26562306a36Sopenharmony_ci * suppressed." 26662306a36Sopenharmony_ci * This function returns true if @insn is MOV SS or POP SS. On these 26762306a36Sopenharmony_ci * instructions, single stepping is suppressed. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic inline int insn_masking_exception(struct insn *insn) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci return insn->opcode.bytes[0] == POP_SS_OPCODE || 27262306a36Sopenharmony_ci (insn->opcode.bytes[0] == MOV_SREG_OPCODE && 27362306a36Sopenharmony_ci X86_MODRM_REG(insn->modrm.bytes[0]) == 2); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci#endif /* _ASM_X86_INSN_H */ 277