162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Utility functions for x86 operand and address decoding 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) Intel Corporation 2017 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/string.h> 862306a36Sopenharmony_ci#include <linux/ratelimit.h> 962306a36Sopenharmony_ci#include <linux/mmu_context.h> 1062306a36Sopenharmony_ci#include <asm/desc_defs.h> 1162306a36Sopenharmony_ci#include <asm/desc.h> 1262306a36Sopenharmony_ci#include <asm/inat.h> 1362306a36Sopenharmony_ci#include <asm/insn.h> 1462306a36Sopenharmony_ci#include <asm/insn-eval.h> 1562306a36Sopenharmony_ci#include <asm/ldt.h> 1662306a36Sopenharmony_ci#include <asm/vm86.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#undef pr_fmt 1962306a36Sopenharmony_ci#define pr_fmt(fmt) "insn: " fmt 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cienum reg_type { 2262306a36Sopenharmony_ci REG_TYPE_RM = 0, 2362306a36Sopenharmony_ci REG_TYPE_REG, 2462306a36Sopenharmony_ci REG_TYPE_INDEX, 2562306a36Sopenharmony_ci REG_TYPE_BASE, 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * is_string_insn() - Determine if instruction is a string instruction 3062306a36Sopenharmony_ci * @insn: Instruction containing the opcode to inspect 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * Returns: 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * true if the instruction, determined by the opcode, is any of the 3562306a36Sopenharmony_ci * string instructions as defined in the Intel Software Development manual. 3662306a36Sopenharmony_ci * False otherwise. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_cistatic bool is_string_insn(struct insn *insn) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci /* All string instructions have a 1-byte opcode. */ 4162306a36Sopenharmony_ci if (insn->opcode.nbytes != 1) 4262306a36Sopenharmony_ci return false; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci switch (insn->opcode.bytes[0]) { 4562306a36Sopenharmony_ci case 0x6c ... 0x6f: /* INS, OUTS */ 4662306a36Sopenharmony_ci case 0xa4 ... 0xa7: /* MOVS, CMPS */ 4762306a36Sopenharmony_ci case 0xaa ... 0xaf: /* STOS, LODS, SCAS */ 4862306a36Sopenharmony_ci return true; 4962306a36Sopenharmony_ci default: 5062306a36Sopenharmony_ci return false; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/** 5562306a36Sopenharmony_ci * insn_has_rep_prefix() - Determine if instruction has a REP prefix 5662306a36Sopenharmony_ci * @insn: Instruction containing the prefix to inspect 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Returns: 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * true if the instruction has a REP prefix, false if not. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_cibool insn_has_rep_prefix(struct insn *insn) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci insn_byte_t p; 6562306a36Sopenharmony_ci int i; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci insn_get_prefixes(insn); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci for_each_insn_prefix(insn, i, p) { 7062306a36Sopenharmony_ci if (p == 0xf2 || p == 0xf3) 7162306a36Sopenharmony_ci return true; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return false; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * get_seg_reg_override_idx() - obtain segment register override index 7962306a36Sopenharmony_ci * @insn: Valid instruction with segment override prefixes 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * Inspect the instruction prefixes in @insn and find segment overrides, if any. 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * Returns: 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * A constant identifying the segment register to use, among CS, SS, DS, 8662306a36Sopenharmony_ci * ES, FS, or GS. INAT_SEG_REG_DEFAULT is returned if no segment override 8762306a36Sopenharmony_ci * prefixes were found. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * -EINVAL in case of error. 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic int get_seg_reg_override_idx(struct insn *insn) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci int idx = INAT_SEG_REG_DEFAULT; 9462306a36Sopenharmony_ci int num_overrides = 0, i; 9562306a36Sopenharmony_ci insn_byte_t p; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci insn_get_prefixes(insn); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* Look for any segment override prefixes. */ 10062306a36Sopenharmony_ci for_each_insn_prefix(insn, i, p) { 10162306a36Sopenharmony_ci insn_attr_t attr; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci attr = inat_get_opcode_attribute(p); 10462306a36Sopenharmony_ci switch (attr) { 10562306a36Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_CS): 10662306a36Sopenharmony_ci idx = INAT_SEG_REG_CS; 10762306a36Sopenharmony_ci num_overrides++; 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_SS): 11062306a36Sopenharmony_ci idx = INAT_SEG_REG_SS; 11162306a36Sopenharmony_ci num_overrides++; 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_DS): 11462306a36Sopenharmony_ci idx = INAT_SEG_REG_DS; 11562306a36Sopenharmony_ci num_overrides++; 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_ES): 11862306a36Sopenharmony_ci idx = INAT_SEG_REG_ES; 11962306a36Sopenharmony_ci num_overrides++; 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_FS): 12262306a36Sopenharmony_ci idx = INAT_SEG_REG_FS; 12362306a36Sopenharmony_ci num_overrides++; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_GS): 12662306a36Sopenharmony_ci idx = INAT_SEG_REG_GS; 12762306a36Sopenharmony_ci num_overrides++; 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci /* No default action needed. */ 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* More than one segment override prefix leads to undefined behavior. */ 13462306a36Sopenharmony_ci if (num_overrides > 1) 13562306a36Sopenharmony_ci return -EINVAL; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return idx; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/** 14162306a36Sopenharmony_ci * check_seg_overrides() - check if segment override prefixes are allowed 14262306a36Sopenharmony_ci * @insn: Valid instruction with segment override prefixes 14362306a36Sopenharmony_ci * @regoff: Operand offset, in pt_regs, for which the check is performed 14462306a36Sopenharmony_ci * 14562306a36Sopenharmony_ci * For a particular register used in register-indirect addressing, determine if 14662306a36Sopenharmony_ci * segment override prefixes can be used. Specifically, no overrides are allowed 14762306a36Sopenharmony_ci * for rDI if used with a string instruction. 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * Returns: 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * True if segment override prefixes can be used with the register indicated 15262306a36Sopenharmony_ci * in @regoff. False if otherwise. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_cistatic bool check_seg_overrides(struct insn *insn, int regoff) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci if (regoff == offsetof(struct pt_regs, di) && is_string_insn(insn)) 15762306a36Sopenharmony_ci return false; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return true; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/** 16362306a36Sopenharmony_ci * resolve_default_seg() - resolve default segment register index for an operand 16462306a36Sopenharmony_ci * @insn: Instruction with opcode and address size. Must be valid. 16562306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 16662306a36Sopenharmony_ci * @off: Operand offset, in pt_regs, for which resolution is needed 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * Resolve the default segment register index associated with the instruction 16962306a36Sopenharmony_ci * operand register indicated by @off. Such index is resolved based on defaults 17062306a36Sopenharmony_ci * described in the Intel Software Development Manual. 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * Returns: 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * If in protected mode, a constant identifying the segment register to use, 17562306a36Sopenharmony_ci * among CS, SS, ES or DS. If in long mode, INAT_SEG_REG_IGNORE. 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * -EINVAL in case of error. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistatic int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci if (any_64bit_mode(regs)) 18262306a36Sopenharmony_ci return INAT_SEG_REG_IGNORE; 18362306a36Sopenharmony_ci /* 18462306a36Sopenharmony_ci * Resolve the default segment register as described in Section 3.7.4 18562306a36Sopenharmony_ci * of the Intel Software Development Manual Vol. 1: 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * + DS for all references involving r[ABCD]X, and rSI. 18862306a36Sopenharmony_ci * + If used in a string instruction, ES for rDI. Otherwise, DS. 18962306a36Sopenharmony_ci * + AX, CX and DX are not valid register operands in 16-bit address 19062306a36Sopenharmony_ci * encodings but are valid for 32-bit and 64-bit encodings. 19162306a36Sopenharmony_ci * + -EDOM is reserved to identify for cases in which no register 19262306a36Sopenharmony_ci * is used (i.e., displacement-only addressing). Use DS. 19362306a36Sopenharmony_ci * + SS for rSP or rBP. 19462306a36Sopenharmony_ci * + CS for rIP. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci switch (off) { 19862306a36Sopenharmony_ci case offsetof(struct pt_regs, ax): 19962306a36Sopenharmony_ci case offsetof(struct pt_regs, cx): 20062306a36Sopenharmony_ci case offsetof(struct pt_regs, dx): 20162306a36Sopenharmony_ci /* Need insn to verify address size. */ 20262306a36Sopenharmony_ci if (insn->addr_bytes == 2) 20362306a36Sopenharmony_ci return -EINVAL; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci fallthrough; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci case -EDOM: 20862306a36Sopenharmony_ci case offsetof(struct pt_regs, bx): 20962306a36Sopenharmony_ci case offsetof(struct pt_regs, si): 21062306a36Sopenharmony_ci return INAT_SEG_REG_DS; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci case offsetof(struct pt_regs, di): 21362306a36Sopenharmony_ci if (is_string_insn(insn)) 21462306a36Sopenharmony_ci return INAT_SEG_REG_ES; 21562306a36Sopenharmony_ci return INAT_SEG_REG_DS; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci case offsetof(struct pt_regs, bp): 21862306a36Sopenharmony_ci case offsetof(struct pt_regs, sp): 21962306a36Sopenharmony_ci return INAT_SEG_REG_SS; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci case offsetof(struct pt_regs, ip): 22262306a36Sopenharmony_ci return INAT_SEG_REG_CS; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci default: 22562306a36Sopenharmony_ci return -EINVAL; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/** 23062306a36Sopenharmony_ci * resolve_seg_reg() - obtain segment register index 23162306a36Sopenharmony_ci * @insn: Instruction with operands 23262306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 23362306a36Sopenharmony_ci * @regoff: Operand offset, in pt_regs, used to determine segment register 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * Determine the segment register associated with the operands and, if 23662306a36Sopenharmony_ci * applicable, prefixes and the instruction pointed by @insn. 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci * The segment register associated to an operand used in register-indirect 23962306a36Sopenharmony_ci * addressing depends on: 24062306a36Sopenharmony_ci * 24162306a36Sopenharmony_ci * a) Whether running in long mode (in such a case segments are ignored, except 24262306a36Sopenharmony_ci * if FS or GS are used). 24362306a36Sopenharmony_ci * 24462306a36Sopenharmony_ci * b) Whether segment override prefixes can be used. Certain instructions and 24562306a36Sopenharmony_ci * registers do not allow override prefixes. 24662306a36Sopenharmony_ci * 24762306a36Sopenharmony_ci * c) Whether segment overrides prefixes are found in the instruction prefixes. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * d) If there are not segment override prefixes or they cannot be used, the 25062306a36Sopenharmony_ci * default segment register associated with the operand register is used. 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * The function checks first if segment override prefixes can be used with the 25362306a36Sopenharmony_ci * operand indicated by @regoff. If allowed, obtain such overridden segment 25462306a36Sopenharmony_ci * register index. Lastly, if not prefixes were found or cannot be used, resolve 25562306a36Sopenharmony_ci * the segment register index to use based on the defaults described in the 25662306a36Sopenharmony_ci * Intel documentation. In long mode, all segment register indexes will be 25762306a36Sopenharmony_ci * ignored, except if overrides were found for FS or GS. All these operations 25862306a36Sopenharmony_ci * are done using helper functions. 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * The operand register, @regoff, is represented as the offset from the base of 26162306a36Sopenharmony_ci * pt_regs. 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * As stated, the main use of this function is to determine the segment register 26462306a36Sopenharmony_ci * index based on the instruction, its operands and prefixes. Hence, @insn 26562306a36Sopenharmony_ci * must be valid. However, if @regoff indicates rIP, we don't need to inspect 26662306a36Sopenharmony_ci * @insn at all as in this case CS is used in all cases. This case is checked 26762306a36Sopenharmony_ci * before proceeding further. 26862306a36Sopenharmony_ci * 26962306a36Sopenharmony_ci * Please note that this function does not return the value in the segment 27062306a36Sopenharmony_ci * register (i.e., the segment selector) but our defined index. The segment 27162306a36Sopenharmony_ci * selector needs to be obtained using get_segment_selector() and passing the 27262306a36Sopenharmony_ci * segment register index resolved by this function. 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * Returns: 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * An index identifying the segment register to use, among CS, SS, DS, 27762306a36Sopenharmony_ci * ES, FS, or GS. INAT_SEG_REG_IGNORE is returned if running in long mode. 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * -EINVAL in case of error. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci int idx; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* 28662306a36Sopenharmony_ci * In the unlikely event of having to resolve the segment register 28762306a36Sopenharmony_ci * index for rIP, do it first. Segment override prefixes should not 28862306a36Sopenharmony_ci * be used. Hence, it is not necessary to inspect the instruction, 28962306a36Sopenharmony_ci * which may be invalid at this point. 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci if (regoff == offsetof(struct pt_regs, ip)) { 29262306a36Sopenharmony_ci if (any_64bit_mode(regs)) 29362306a36Sopenharmony_ci return INAT_SEG_REG_IGNORE; 29462306a36Sopenharmony_ci else 29562306a36Sopenharmony_ci return INAT_SEG_REG_CS; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (!insn) 29962306a36Sopenharmony_ci return -EINVAL; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (!check_seg_overrides(insn, regoff)) 30262306a36Sopenharmony_ci return resolve_default_seg(insn, regs, regoff); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci idx = get_seg_reg_override_idx(insn); 30562306a36Sopenharmony_ci if (idx < 0) 30662306a36Sopenharmony_ci return idx; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (idx == INAT_SEG_REG_DEFAULT) 30962306a36Sopenharmony_ci return resolve_default_seg(insn, regs, regoff); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* 31262306a36Sopenharmony_ci * In long mode, segment override prefixes are ignored, except for 31362306a36Sopenharmony_ci * overrides for FS and GS. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci if (any_64bit_mode(regs)) { 31662306a36Sopenharmony_ci if (idx != INAT_SEG_REG_FS && 31762306a36Sopenharmony_ci idx != INAT_SEG_REG_GS) 31862306a36Sopenharmony_ci idx = INAT_SEG_REG_IGNORE; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return idx; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/** 32562306a36Sopenharmony_ci * get_segment_selector() - obtain segment selector 32662306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 32762306a36Sopenharmony_ci * @seg_reg_idx: Segment register index to use 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * Obtain the segment selector from any of the CS, SS, DS, ES, FS, GS segment 33062306a36Sopenharmony_ci * registers. In CONFIG_X86_32, the segment is obtained from either pt_regs or 33162306a36Sopenharmony_ci * kernel_vm86_regs as applicable. In CONFIG_X86_64, CS and SS are obtained 33262306a36Sopenharmony_ci * from pt_regs. DS, ES, FS and GS are obtained by reading the actual CPU 33362306a36Sopenharmony_ci * registers. This done for only for completeness as in CONFIG_X86_64 segment 33462306a36Sopenharmony_ci * registers are ignored. 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * Returns: 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * Value of the segment selector, including null when running in 33962306a36Sopenharmony_ci * long mode. 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * -EINVAL on error. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistatic short get_segment_selector(struct pt_regs *regs, int seg_reg_idx) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci unsigned short sel; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci#ifdef CONFIG_X86_64 34862306a36Sopenharmony_ci switch (seg_reg_idx) { 34962306a36Sopenharmony_ci case INAT_SEG_REG_IGNORE: 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci case INAT_SEG_REG_CS: 35262306a36Sopenharmony_ci return (unsigned short)(regs->cs & 0xffff); 35362306a36Sopenharmony_ci case INAT_SEG_REG_SS: 35462306a36Sopenharmony_ci return (unsigned short)(regs->ss & 0xffff); 35562306a36Sopenharmony_ci case INAT_SEG_REG_DS: 35662306a36Sopenharmony_ci savesegment(ds, sel); 35762306a36Sopenharmony_ci return sel; 35862306a36Sopenharmony_ci case INAT_SEG_REG_ES: 35962306a36Sopenharmony_ci savesegment(es, sel); 36062306a36Sopenharmony_ci return sel; 36162306a36Sopenharmony_ci case INAT_SEG_REG_FS: 36262306a36Sopenharmony_ci savesegment(fs, sel); 36362306a36Sopenharmony_ci return sel; 36462306a36Sopenharmony_ci case INAT_SEG_REG_GS: 36562306a36Sopenharmony_ci savesegment(gs, sel); 36662306a36Sopenharmony_ci return sel; 36762306a36Sopenharmony_ci default: 36862306a36Sopenharmony_ci return -EINVAL; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci#else /* CONFIG_X86_32 */ 37162306a36Sopenharmony_ci struct kernel_vm86_regs *vm86regs = (struct kernel_vm86_regs *)regs; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (v8086_mode(regs)) { 37462306a36Sopenharmony_ci switch (seg_reg_idx) { 37562306a36Sopenharmony_ci case INAT_SEG_REG_CS: 37662306a36Sopenharmony_ci return (unsigned short)(regs->cs & 0xffff); 37762306a36Sopenharmony_ci case INAT_SEG_REG_SS: 37862306a36Sopenharmony_ci return (unsigned short)(regs->ss & 0xffff); 37962306a36Sopenharmony_ci case INAT_SEG_REG_DS: 38062306a36Sopenharmony_ci return vm86regs->ds; 38162306a36Sopenharmony_ci case INAT_SEG_REG_ES: 38262306a36Sopenharmony_ci return vm86regs->es; 38362306a36Sopenharmony_ci case INAT_SEG_REG_FS: 38462306a36Sopenharmony_ci return vm86regs->fs; 38562306a36Sopenharmony_ci case INAT_SEG_REG_GS: 38662306a36Sopenharmony_ci return vm86regs->gs; 38762306a36Sopenharmony_ci case INAT_SEG_REG_IGNORE: 38862306a36Sopenharmony_ci default: 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci switch (seg_reg_idx) { 39462306a36Sopenharmony_ci case INAT_SEG_REG_CS: 39562306a36Sopenharmony_ci return (unsigned short)(regs->cs & 0xffff); 39662306a36Sopenharmony_ci case INAT_SEG_REG_SS: 39762306a36Sopenharmony_ci return (unsigned short)(regs->ss & 0xffff); 39862306a36Sopenharmony_ci case INAT_SEG_REG_DS: 39962306a36Sopenharmony_ci return (unsigned short)(regs->ds & 0xffff); 40062306a36Sopenharmony_ci case INAT_SEG_REG_ES: 40162306a36Sopenharmony_ci return (unsigned short)(regs->es & 0xffff); 40262306a36Sopenharmony_ci case INAT_SEG_REG_FS: 40362306a36Sopenharmony_ci return (unsigned short)(regs->fs & 0xffff); 40462306a36Sopenharmony_ci case INAT_SEG_REG_GS: 40562306a36Sopenharmony_ci savesegment(gs, sel); 40662306a36Sopenharmony_ci return sel; 40762306a36Sopenharmony_ci case INAT_SEG_REG_IGNORE: 40862306a36Sopenharmony_ci default: 40962306a36Sopenharmony_ci return -EINVAL; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci#endif /* CONFIG_X86_64 */ 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic const int pt_regoff[] = { 41562306a36Sopenharmony_ci offsetof(struct pt_regs, ax), 41662306a36Sopenharmony_ci offsetof(struct pt_regs, cx), 41762306a36Sopenharmony_ci offsetof(struct pt_regs, dx), 41862306a36Sopenharmony_ci offsetof(struct pt_regs, bx), 41962306a36Sopenharmony_ci offsetof(struct pt_regs, sp), 42062306a36Sopenharmony_ci offsetof(struct pt_regs, bp), 42162306a36Sopenharmony_ci offsetof(struct pt_regs, si), 42262306a36Sopenharmony_ci offsetof(struct pt_regs, di), 42362306a36Sopenharmony_ci#ifdef CONFIG_X86_64 42462306a36Sopenharmony_ci offsetof(struct pt_regs, r8), 42562306a36Sopenharmony_ci offsetof(struct pt_regs, r9), 42662306a36Sopenharmony_ci offsetof(struct pt_regs, r10), 42762306a36Sopenharmony_ci offsetof(struct pt_regs, r11), 42862306a36Sopenharmony_ci offsetof(struct pt_regs, r12), 42962306a36Sopenharmony_ci offsetof(struct pt_regs, r13), 43062306a36Sopenharmony_ci offsetof(struct pt_regs, r14), 43162306a36Sopenharmony_ci offsetof(struct pt_regs, r15), 43262306a36Sopenharmony_ci#else 43362306a36Sopenharmony_ci offsetof(struct pt_regs, ds), 43462306a36Sopenharmony_ci offsetof(struct pt_regs, es), 43562306a36Sopenharmony_ci offsetof(struct pt_regs, fs), 43662306a36Sopenharmony_ci offsetof(struct pt_regs, gs), 43762306a36Sopenharmony_ci#endif 43862306a36Sopenharmony_ci}; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ciint pt_regs_offset(struct pt_regs *regs, int regno) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci if ((unsigned)regno < ARRAY_SIZE(pt_regoff)) 44362306a36Sopenharmony_ci return pt_regoff[regno]; 44462306a36Sopenharmony_ci return -EDOM; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic int get_regno(struct insn *insn, enum reg_type type) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci int nr_registers = ARRAY_SIZE(pt_regoff); 45062306a36Sopenharmony_ci int regno = 0; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* 45362306a36Sopenharmony_ci * Don't possibly decode a 32-bit instructions as 45462306a36Sopenharmony_ci * reading a 64-bit-only register. 45562306a36Sopenharmony_ci */ 45662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64) 45762306a36Sopenharmony_ci nr_registers -= 8; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci switch (type) { 46062306a36Sopenharmony_ci case REG_TYPE_RM: 46162306a36Sopenharmony_ci regno = X86_MODRM_RM(insn->modrm.value); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* 46462306a36Sopenharmony_ci * ModRM.mod == 0 and ModRM.rm == 5 means a 32-bit displacement 46562306a36Sopenharmony_ci * follows the ModRM byte. 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ci if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5) 46862306a36Sopenharmony_ci return -EDOM; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (X86_REX_B(insn->rex_prefix.value)) 47162306a36Sopenharmony_ci regno += 8; 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci case REG_TYPE_REG: 47562306a36Sopenharmony_ci regno = X86_MODRM_REG(insn->modrm.value); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci if (X86_REX_R(insn->rex_prefix.value)) 47862306a36Sopenharmony_ci regno += 8; 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci case REG_TYPE_INDEX: 48262306a36Sopenharmony_ci regno = X86_SIB_INDEX(insn->sib.value); 48362306a36Sopenharmony_ci if (X86_REX_X(insn->rex_prefix.value)) 48462306a36Sopenharmony_ci regno += 8; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci /* 48762306a36Sopenharmony_ci * If ModRM.mod != 3 and SIB.index = 4 the scale*index 48862306a36Sopenharmony_ci * portion of the address computation is null. This is 48962306a36Sopenharmony_ci * true only if REX.X is 0. In such a case, the SIB index 49062306a36Sopenharmony_ci * is used in the address computation. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) != 3 && regno == 4) 49362306a36Sopenharmony_ci return -EDOM; 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci case REG_TYPE_BASE: 49762306a36Sopenharmony_ci regno = X86_SIB_BASE(insn->sib.value); 49862306a36Sopenharmony_ci /* 49962306a36Sopenharmony_ci * If ModRM.mod is 0 and SIB.base == 5, the base of the 50062306a36Sopenharmony_ci * register-indirect addressing is 0. In this case, a 50162306a36Sopenharmony_ci * 32-bit displacement follows the SIB byte. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ci if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5) 50462306a36Sopenharmony_ci return -EDOM; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (X86_REX_B(insn->rex_prefix.value)) 50762306a36Sopenharmony_ci regno += 8; 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci default: 51162306a36Sopenharmony_ci pr_err_ratelimited("invalid register type: %d\n", type); 51262306a36Sopenharmony_ci return -EINVAL; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (regno >= nr_registers) { 51662306a36Sopenharmony_ci WARN_ONCE(1, "decoded an instruction with an invalid register"); 51762306a36Sopenharmony_ci return -EINVAL; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci return regno; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic int get_reg_offset(struct insn *insn, struct pt_regs *regs, 52362306a36Sopenharmony_ci enum reg_type type) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci int regno = get_regno(insn, type); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (regno < 0) 52862306a36Sopenharmony_ci return regno; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return pt_regs_offset(regs, regno); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/** 53462306a36Sopenharmony_ci * get_reg_offset_16() - Obtain offset of register indicated by instruction 53562306a36Sopenharmony_ci * @insn: Instruction containing ModRM byte 53662306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 53762306a36Sopenharmony_ci * @offs1: Offset of the first operand register 53862306a36Sopenharmony_ci * @offs2: Offset of the second operand register, if applicable 53962306a36Sopenharmony_ci * 54062306a36Sopenharmony_ci * Obtain the offset, in pt_regs, of the registers indicated by the ModRM byte 54162306a36Sopenharmony_ci * in @insn. This function is to be used with 16-bit address encodings. The 54262306a36Sopenharmony_ci * @offs1 and @offs2 will be written with the offset of the two registers 54362306a36Sopenharmony_ci * indicated by the instruction. In cases where any of the registers is not 54462306a36Sopenharmony_ci * referenced by the instruction, the value will be set to -EDOM. 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * Returns: 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * 0 on success, -EINVAL on error. 54962306a36Sopenharmony_ci */ 55062306a36Sopenharmony_cistatic int get_reg_offset_16(struct insn *insn, struct pt_regs *regs, 55162306a36Sopenharmony_ci int *offs1, int *offs2) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci /* 55462306a36Sopenharmony_ci * 16-bit addressing can use one or two registers. Specifics of 55562306a36Sopenharmony_ci * encodings are given in Table 2-1. "16-Bit Addressing Forms with the 55662306a36Sopenharmony_ci * ModR/M Byte" of the Intel Software Development Manual. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci static const int regoff1[] = { 55962306a36Sopenharmony_ci offsetof(struct pt_regs, bx), 56062306a36Sopenharmony_ci offsetof(struct pt_regs, bx), 56162306a36Sopenharmony_ci offsetof(struct pt_regs, bp), 56262306a36Sopenharmony_ci offsetof(struct pt_regs, bp), 56362306a36Sopenharmony_ci offsetof(struct pt_regs, si), 56462306a36Sopenharmony_ci offsetof(struct pt_regs, di), 56562306a36Sopenharmony_ci offsetof(struct pt_regs, bp), 56662306a36Sopenharmony_ci offsetof(struct pt_regs, bx), 56762306a36Sopenharmony_ci }; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci static const int regoff2[] = { 57062306a36Sopenharmony_ci offsetof(struct pt_regs, si), 57162306a36Sopenharmony_ci offsetof(struct pt_regs, di), 57262306a36Sopenharmony_ci offsetof(struct pt_regs, si), 57362306a36Sopenharmony_ci offsetof(struct pt_regs, di), 57462306a36Sopenharmony_ci -EDOM, 57562306a36Sopenharmony_ci -EDOM, 57662306a36Sopenharmony_ci -EDOM, 57762306a36Sopenharmony_ci -EDOM, 57862306a36Sopenharmony_ci }; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (!offs1 || !offs2) 58162306a36Sopenharmony_ci return -EINVAL; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* Operand is a register, use the generic function. */ 58462306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 58562306a36Sopenharmony_ci *offs1 = insn_get_modrm_rm_off(insn, regs); 58662306a36Sopenharmony_ci *offs2 = -EDOM; 58762306a36Sopenharmony_ci return 0; 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci *offs1 = regoff1[X86_MODRM_RM(insn->modrm.value)]; 59162306a36Sopenharmony_ci *offs2 = regoff2[X86_MODRM_RM(insn->modrm.value)]; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* 59462306a36Sopenharmony_ci * If ModRM.mod is 0 and ModRM.rm is 110b, then we use displacement- 59562306a36Sopenharmony_ci * only addressing. This means that no registers are involved in 59662306a36Sopenharmony_ci * computing the effective address. Thus, ensure that the first 59762306a36Sopenharmony_ci * register offset is invalid. The second register offset is already 59862306a36Sopenharmony_ci * invalid under the aforementioned conditions. 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci if ((X86_MODRM_MOD(insn->modrm.value) == 0) && 60162306a36Sopenharmony_ci (X86_MODRM_RM(insn->modrm.value) == 6)) 60262306a36Sopenharmony_ci *offs1 = -EDOM; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return 0; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci/** 60862306a36Sopenharmony_ci * get_desc() - Obtain contents of a segment descriptor 60962306a36Sopenharmony_ci * @out: Segment descriptor contents on success 61062306a36Sopenharmony_ci * @sel: Segment selector 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci * Given a segment selector, obtain a pointer to the segment descriptor. 61362306a36Sopenharmony_ci * Both global and local descriptor tables are supported. 61462306a36Sopenharmony_ci * 61562306a36Sopenharmony_ci * Returns: 61662306a36Sopenharmony_ci * 61762306a36Sopenharmony_ci * True on success, false on failure. 61862306a36Sopenharmony_ci * 61962306a36Sopenharmony_ci * NULL on error. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_cistatic bool get_desc(struct desc_struct *out, unsigned short sel) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct desc_ptr gdt_desc = {0, 0}; 62462306a36Sopenharmony_ci unsigned long desc_base; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 62762306a36Sopenharmony_ci if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) { 62862306a36Sopenharmony_ci bool success = false; 62962306a36Sopenharmony_ci struct ldt_struct *ldt; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* Bits [15:3] contain the index of the desired entry. */ 63262306a36Sopenharmony_ci sel >>= 3; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci mutex_lock(¤t->active_mm->context.lock); 63562306a36Sopenharmony_ci ldt = current->active_mm->context.ldt; 63662306a36Sopenharmony_ci if (ldt && sel < ldt->nr_entries) { 63762306a36Sopenharmony_ci *out = ldt->entries[sel]; 63862306a36Sopenharmony_ci success = true; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci mutex_unlock(¤t->active_mm->context.lock); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return success; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci#endif 64662306a36Sopenharmony_ci native_store_gdt(&gdt_desc); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci * Segment descriptors have a size of 8 bytes. Thus, the index is 65062306a36Sopenharmony_ci * multiplied by 8 to obtain the memory offset of the desired descriptor 65162306a36Sopenharmony_ci * from the base of the GDT. As bits [15:3] of the segment selector 65262306a36Sopenharmony_ci * contain the index, it can be regarded as multiplied by 8 already. 65362306a36Sopenharmony_ci * All that remains is to clear bits [2:0]. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_ci desc_base = sel & ~(SEGMENT_RPL_MASK | SEGMENT_TI_MASK); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci if (desc_base > gdt_desc.size) 65862306a36Sopenharmony_ci return false; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci *out = *(struct desc_struct *)(gdt_desc.address + desc_base); 66162306a36Sopenharmony_ci return true; 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci/** 66562306a36Sopenharmony_ci * insn_get_seg_base() - Obtain base address of segment descriptor. 66662306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 66762306a36Sopenharmony_ci * @seg_reg_idx: Index of the segment register pointing to seg descriptor 66862306a36Sopenharmony_ci * 66962306a36Sopenharmony_ci * Obtain the base address of the segment as indicated by the segment descriptor 67062306a36Sopenharmony_ci * pointed by the segment selector. The segment selector is obtained from the 67162306a36Sopenharmony_ci * input segment register index @seg_reg_idx. 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * Returns: 67462306a36Sopenharmony_ci * 67562306a36Sopenharmony_ci * In protected mode, base address of the segment. Zero in long mode, 67662306a36Sopenharmony_ci * except when FS or GS are used. In virtual-8086 mode, the segment 67762306a36Sopenharmony_ci * selector shifted 4 bits to the right. 67862306a36Sopenharmony_ci * 67962306a36Sopenharmony_ci * -1L in case of error. 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_ciunsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct desc_struct desc; 68462306a36Sopenharmony_ci short sel; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci sel = get_segment_selector(regs, seg_reg_idx); 68762306a36Sopenharmony_ci if (sel < 0) 68862306a36Sopenharmony_ci return -1L; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (v8086_mode(regs)) 69162306a36Sopenharmony_ci /* 69262306a36Sopenharmony_ci * Base is simply the segment selector shifted 4 69362306a36Sopenharmony_ci * bits to the right. 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_ci return (unsigned long)(sel << 4); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (any_64bit_mode(regs)) { 69862306a36Sopenharmony_ci /* 69962306a36Sopenharmony_ci * Only FS or GS will have a base address, the rest of 70062306a36Sopenharmony_ci * the segments' bases are forced to 0. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_ci unsigned long base; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (seg_reg_idx == INAT_SEG_REG_FS) { 70562306a36Sopenharmony_ci rdmsrl(MSR_FS_BASE, base); 70662306a36Sopenharmony_ci } else if (seg_reg_idx == INAT_SEG_REG_GS) { 70762306a36Sopenharmony_ci /* 70862306a36Sopenharmony_ci * swapgs was called at the kernel entry point. Thus, 70962306a36Sopenharmony_ci * MSR_KERNEL_GS_BASE will have the user-space GS base. 71062306a36Sopenharmony_ci */ 71162306a36Sopenharmony_ci if (user_mode(regs)) 71262306a36Sopenharmony_ci rdmsrl(MSR_KERNEL_GS_BASE, base); 71362306a36Sopenharmony_ci else 71462306a36Sopenharmony_ci rdmsrl(MSR_GS_BASE, base); 71562306a36Sopenharmony_ci } else { 71662306a36Sopenharmony_ci base = 0; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci return base; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* In protected mode the segment selector cannot be null. */ 72262306a36Sopenharmony_ci if (!sel) 72362306a36Sopenharmony_ci return -1L; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (!get_desc(&desc, sel)) 72662306a36Sopenharmony_ci return -1L; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci return get_desc_base(&desc); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci/** 73262306a36Sopenharmony_ci * get_seg_limit() - Obtain the limit of a segment descriptor 73362306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 73462306a36Sopenharmony_ci * @seg_reg_idx: Index of the segment register pointing to seg descriptor 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * Obtain the limit of the segment as indicated by the segment descriptor 73762306a36Sopenharmony_ci * pointed by the segment selector. The segment selector is obtained from the 73862306a36Sopenharmony_ci * input segment register index @seg_reg_idx. 73962306a36Sopenharmony_ci * 74062306a36Sopenharmony_ci * Returns: 74162306a36Sopenharmony_ci * 74262306a36Sopenharmony_ci * In protected mode, the limit of the segment descriptor in bytes. 74362306a36Sopenharmony_ci * In long mode and virtual-8086 mode, segment limits are not enforced. Thus, 74462306a36Sopenharmony_ci * limit is returned as -1L to imply a limit-less segment. 74562306a36Sopenharmony_ci * 74662306a36Sopenharmony_ci * Zero is returned on error. 74762306a36Sopenharmony_ci */ 74862306a36Sopenharmony_cistatic unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct desc_struct desc; 75162306a36Sopenharmony_ci unsigned long limit; 75262306a36Sopenharmony_ci short sel; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci sel = get_segment_selector(regs, seg_reg_idx); 75562306a36Sopenharmony_ci if (sel < 0) 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (any_64bit_mode(regs) || v8086_mode(regs)) 75962306a36Sopenharmony_ci return -1L; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (!sel) 76262306a36Sopenharmony_ci return 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (!get_desc(&desc, sel)) 76562306a36Sopenharmony_ci return 0; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci /* 76862306a36Sopenharmony_ci * If the granularity bit is set, the limit is given in multiples 76962306a36Sopenharmony_ci * of 4096. This also means that the 12 least significant bits are 77062306a36Sopenharmony_ci * not tested when checking the segment limits. In practice, 77162306a36Sopenharmony_ci * this means that the segment ends in (limit << 12) + 0xfff. 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_ci limit = get_desc_limit(&desc); 77462306a36Sopenharmony_ci if (desc.g) 77562306a36Sopenharmony_ci limit = (limit << 12) + 0xfff; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return limit; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci/** 78162306a36Sopenharmony_ci * insn_get_code_seg_params() - Obtain code segment parameters 78262306a36Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 78362306a36Sopenharmony_ci * 78462306a36Sopenharmony_ci * Obtain address and operand sizes of the code segment. It is obtained from the 78562306a36Sopenharmony_ci * selector contained in the CS register in regs. In protected mode, the default 78662306a36Sopenharmony_ci * address is determined by inspecting the L and D bits of the segment 78762306a36Sopenharmony_ci * descriptor. In virtual-8086 mode, the default is always two bytes for both 78862306a36Sopenharmony_ci * address and operand sizes. 78962306a36Sopenharmony_ci * 79062306a36Sopenharmony_ci * Returns: 79162306a36Sopenharmony_ci * 79262306a36Sopenharmony_ci * An int containing ORed-in default parameters on success. 79362306a36Sopenharmony_ci * 79462306a36Sopenharmony_ci * -EINVAL on error. 79562306a36Sopenharmony_ci */ 79662306a36Sopenharmony_ciint insn_get_code_seg_params(struct pt_regs *regs) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct desc_struct desc; 79962306a36Sopenharmony_ci short sel; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (v8086_mode(regs)) 80262306a36Sopenharmony_ci /* Address and operand size are both 16-bit. */ 80362306a36Sopenharmony_ci return INSN_CODE_SEG_PARAMS(2, 2); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci sel = get_segment_selector(regs, INAT_SEG_REG_CS); 80662306a36Sopenharmony_ci if (sel < 0) 80762306a36Sopenharmony_ci return sel; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (!get_desc(&desc, sel)) 81062306a36Sopenharmony_ci return -EINVAL; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci /* 81362306a36Sopenharmony_ci * The most significant byte of the Type field of the segment descriptor 81462306a36Sopenharmony_ci * determines whether a segment contains data or code. If this is a data 81562306a36Sopenharmony_ci * segment, return error. 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci if (!(desc.type & BIT(3))) 81862306a36Sopenharmony_ci return -EINVAL; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci switch ((desc.l << 1) | desc.d) { 82162306a36Sopenharmony_ci case 0: /* 82262306a36Sopenharmony_ci * Legacy mode. CS.L=0, CS.D=0. Address and operand size are 82362306a36Sopenharmony_ci * both 16-bit. 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci return INSN_CODE_SEG_PARAMS(2, 2); 82662306a36Sopenharmony_ci case 1: /* 82762306a36Sopenharmony_ci * Legacy mode. CS.L=0, CS.D=1. Address and operand size are 82862306a36Sopenharmony_ci * both 32-bit. 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_ci return INSN_CODE_SEG_PARAMS(4, 4); 83162306a36Sopenharmony_ci case 2: /* 83262306a36Sopenharmony_ci * IA-32e 64-bit mode. CS.L=1, CS.D=0. Address size is 64-bit; 83362306a36Sopenharmony_ci * operand size is 32-bit. 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_ci return INSN_CODE_SEG_PARAMS(4, 8); 83662306a36Sopenharmony_ci case 3: /* Invalid setting. CS.L=1, CS.D=1 */ 83762306a36Sopenharmony_ci fallthrough; 83862306a36Sopenharmony_ci default: 83962306a36Sopenharmony_ci return -EINVAL; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci/** 84462306a36Sopenharmony_ci * insn_get_modrm_rm_off() - Obtain register in r/m part of the ModRM byte 84562306a36Sopenharmony_ci * @insn: Instruction containing the ModRM byte 84662306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 84762306a36Sopenharmony_ci * 84862306a36Sopenharmony_ci * Returns: 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * The register indicated by the r/m part of the ModRM byte. The 85162306a36Sopenharmony_ci * register is obtained as an offset from the base of pt_regs. In specific 85262306a36Sopenharmony_ci * cases, the returned value can be -EDOM to indicate that the particular value 85362306a36Sopenharmony_ci * of ModRM does not refer to a register and shall be ignored. 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_ciint insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci return get_reg_offset(insn, regs, REG_TYPE_RM); 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci/** 86162306a36Sopenharmony_ci * insn_get_modrm_reg_off() - Obtain register in reg part of the ModRM byte 86262306a36Sopenharmony_ci * @insn: Instruction containing the ModRM byte 86362306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 86462306a36Sopenharmony_ci * 86562306a36Sopenharmony_ci * Returns: 86662306a36Sopenharmony_ci * 86762306a36Sopenharmony_ci * The register indicated by the reg part of the ModRM byte. The 86862306a36Sopenharmony_ci * register is obtained as an offset from the base of pt_regs. 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ciint insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci return get_reg_offset(insn, regs, REG_TYPE_REG); 87362306a36Sopenharmony_ci} 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci/** 87662306a36Sopenharmony_ci * insn_get_modrm_reg_ptr() - Obtain register pointer based on ModRM byte 87762306a36Sopenharmony_ci * @insn: Instruction containing the ModRM byte 87862306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 87962306a36Sopenharmony_ci * 88062306a36Sopenharmony_ci * Returns: 88162306a36Sopenharmony_ci * 88262306a36Sopenharmony_ci * The register indicated by the reg part of the ModRM byte. 88362306a36Sopenharmony_ci * The register is obtained as a pointer within pt_regs. 88462306a36Sopenharmony_ci */ 88562306a36Sopenharmony_ciunsigned long *insn_get_modrm_reg_ptr(struct insn *insn, struct pt_regs *regs) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci int offset; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci offset = insn_get_modrm_reg_off(insn, regs); 89062306a36Sopenharmony_ci if (offset < 0) 89162306a36Sopenharmony_ci return NULL; 89262306a36Sopenharmony_ci return (void *)regs + offset; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci/** 89662306a36Sopenharmony_ci * get_seg_base_limit() - obtain base address and limit of a segment 89762306a36Sopenharmony_ci * @insn: Instruction. Must be valid. 89862306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 89962306a36Sopenharmony_ci * @regoff: Operand offset, in pt_regs, used to resolve segment descriptor 90062306a36Sopenharmony_ci * @base: Obtained segment base 90162306a36Sopenharmony_ci * @limit: Obtained segment limit 90262306a36Sopenharmony_ci * 90362306a36Sopenharmony_ci * Obtain the base address and limit of the segment associated with the operand 90462306a36Sopenharmony_ci * @regoff and, if any or allowed, override prefixes in @insn. This function is 90562306a36Sopenharmony_ci * different from insn_get_seg_base() as the latter does not resolve the segment 90662306a36Sopenharmony_ci * associated with the instruction operand. If a limit is not needed (e.g., 90762306a36Sopenharmony_ci * when running in long mode), @limit can be NULL. 90862306a36Sopenharmony_ci * 90962306a36Sopenharmony_ci * Returns: 91062306a36Sopenharmony_ci * 91162306a36Sopenharmony_ci * 0 on success. @base and @limit will contain the base address and of the 91262306a36Sopenharmony_ci * resolved segment, respectively. 91362306a36Sopenharmony_ci * 91462306a36Sopenharmony_ci * -EINVAL on error. 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_cistatic int get_seg_base_limit(struct insn *insn, struct pt_regs *regs, 91762306a36Sopenharmony_ci int regoff, unsigned long *base, 91862306a36Sopenharmony_ci unsigned long *limit) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci int seg_reg_idx; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (!base) 92362306a36Sopenharmony_ci return -EINVAL; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci seg_reg_idx = resolve_seg_reg(insn, regs, regoff); 92662306a36Sopenharmony_ci if (seg_reg_idx < 0) 92762306a36Sopenharmony_ci return seg_reg_idx; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci *base = insn_get_seg_base(regs, seg_reg_idx); 93062306a36Sopenharmony_ci if (*base == -1L) 93162306a36Sopenharmony_ci return -EINVAL; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (!limit) 93462306a36Sopenharmony_ci return 0; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci *limit = get_seg_limit(regs, seg_reg_idx); 93762306a36Sopenharmony_ci if (!(*limit)) 93862306a36Sopenharmony_ci return -EINVAL; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci return 0; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci/** 94462306a36Sopenharmony_ci * get_eff_addr_reg() - Obtain effective address from register operand 94562306a36Sopenharmony_ci * @insn: Instruction. Must be valid. 94662306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 94762306a36Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, with the effective address 94862306a36Sopenharmony_ci * @eff_addr: Obtained effective address 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * Obtain the effective address stored in the register operand as indicated by 95162306a36Sopenharmony_ci * the ModRM byte. This function is to be used only with register addressing 95262306a36Sopenharmony_ci * (i.e., ModRM.mod is 3). The effective address is saved in @eff_addr. The 95362306a36Sopenharmony_ci * register operand, as an offset from the base of pt_regs, is saved in @regoff; 95462306a36Sopenharmony_ci * such offset can then be used to resolve the segment associated with the 95562306a36Sopenharmony_ci * operand. This function can be used with any of the supported address sizes 95662306a36Sopenharmony_ci * in x86. 95762306a36Sopenharmony_ci * 95862306a36Sopenharmony_ci * Returns: 95962306a36Sopenharmony_ci * 96062306a36Sopenharmony_ci * 0 on success. @eff_addr will have the effective address stored in the 96162306a36Sopenharmony_ci * operand indicated by ModRM. @regoff will have such operand as an offset from 96262306a36Sopenharmony_ci * the base of pt_regs. 96362306a36Sopenharmony_ci * 96462306a36Sopenharmony_ci * -EINVAL on error. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_cistatic int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs, 96762306a36Sopenharmony_ci int *regoff, long *eff_addr) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci int ret; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci ret = insn_get_modrm(insn); 97262306a36Sopenharmony_ci if (ret) 97362306a36Sopenharmony_ci return ret; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) != 3) 97662306a36Sopenharmony_ci return -EINVAL; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci *regoff = get_reg_offset(insn, regs, REG_TYPE_RM); 97962306a36Sopenharmony_ci if (*regoff < 0) 98062306a36Sopenharmony_ci return -EINVAL; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* Ignore bytes that are outside the address size. */ 98362306a36Sopenharmony_ci if (insn->addr_bytes == 2) 98462306a36Sopenharmony_ci *eff_addr = regs_get_register(regs, *regoff) & 0xffff; 98562306a36Sopenharmony_ci else if (insn->addr_bytes == 4) 98662306a36Sopenharmony_ci *eff_addr = regs_get_register(regs, *regoff) & 0xffffffff; 98762306a36Sopenharmony_ci else /* 64-bit address */ 98862306a36Sopenharmony_ci *eff_addr = regs_get_register(regs, *regoff); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci return 0; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci/** 99462306a36Sopenharmony_ci * get_eff_addr_modrm() - Obtain referenced effective address via ModRM 99562306a36Sopenharmony_ci * @insn: Instruction. Must be valid. 99662306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 99762306a36Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, associated with segment 99862306a36Sopenharmony_ci * @eff_addr: Obtained effective address 99962306a36Sopenharmony_ci * 100062306a36Sopenharmony_ci * Obtain the effective address referenced by the ModRM byte of @insn. After 100162306a36Sopenharmony_ci * identifying the registers involved in the register-indirect memory reference, 100262306a36Sopenharmony_ci * its value is obtained from the operands in @regs. The computed address is 100362306a36Sopenharmony_ci * stored @eff_addr. Also, the register operand that indicates the associated 100462306a36Sopenharmony_ci * segment is stored in @regoff, this parameter can later be used to determine 100562306a36Sopenharmony_ci * such segment. 100662306a36Sopenharmony_ci * 100762306a36Sopenharmony_ci * Returns: 100862306a36Sopenharmony_ci * 100962306a36Sopenharmony_ci * 0 on success. @eff_addr will have the referenced effective address. @regoff 101062306a36Sopenharmony_ci * will have a register, as an offset from the base of pt_regs, that can be used 101162306a36Sopenharmony_ci * to resolve the associated segment. 101262306a36Sopenharmony_ci * 101362306a36Sopenharmony_ci * -EINVAL on error. 101462306a36Sopenharmony_ci */ 101562306a36Sopenharmony_cistatic int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs, 101662306a36Sopenharmony_ci int *regoff, long *eff_addr) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci long tmp; 101962306a36Sopenharmony_ci int ret; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (insn->addr_bytes != 8 && insn->addr_bytes != 4) 102262306a36Sopenharmony_ci return -EINVAL; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci ret = insn_get_modrm(insn); 102562306a36Sopenharmony_ci if (ret) 102662306a36Sopenharmony_ci return ret; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) > 2) 102962306a36Sopenharmony_ci return -EINVAL; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci *regoff = get_reg_offset(insn, regs, REG_TYPE_RM); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* 103462306a36Sopenharmony_ci * -EDOM means that we must ignore the address_offset. In such a case, 103562306a36Sopenharmony_ci * in 64-bit mode the effective address relative to the rIP of the 103662306a36Sopenharmony_ci * following instruction. 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_ci if (*regoff == -EDOM) { 103962306a36Sopenharmony_ci if (any_64bit_mode(regs)) 104062306a36Sopenharmony_ci tmp = regs->ip + insn->length; 104162306a36Sopenharmony_ci else 104262306a36Sopenharmony_ci tmp = 0; 104362306a36Sopenharmony_ci } else if (*regoff < 0) { 104462306a36Sopenharmony_ci return -EINVAL; 104562306a36Sopenharmony_ci } else { 104662306a36Sopenharmony_ci tmp = regs_get_register(regs, *regoff); 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci if (insn->addr_bytes == 4) { 105062306a36Sopenharmony_ci int addr32 = (int)(tmp & 0xffffffff) + insn->displacement.value; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci *eff_addr = addr32 & 0xffffffff; 105362306a36Sopenharmony_ci } else { 105462306a36Sopenharmony_ci *eff_addr = tmp + insn->displacement.value; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci return 0; 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci/** 106162306a36Sopenharmony_ci * get_eff_addr_modrm_16() - Obtain referenced effective address via ModRM 106262306a36Sopenharmony_ci * @insn: Instruction. Must be valid. 106362306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 106462306a36Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, associated with segment 106562306a36Sopenharmony_ci * @eff_addr: Obtained effective address 106662306a36Sopenharmony_ci * 106762306a36Sopenharmony_ci * Obtain the 16-bit effective address referenced by the ModRM byte of @insn. 106862306a36Sopenharmony_ci * After identifying the registers involved in the register-indirect memory 106962306a36Sopenharmony_ci * reference, its value is obtained from the operands in @regs. The computed 107062306a36Sopenharmony_ci * address is stored @eff_addr. Also, the register operand that indicates 107162306a36Sopenharmony_ci * the associated segment is stored in @regoff, this parameter can later be used 107262306a36Sopenharmony_ci * to determine such segment. 107362306a36Sopenharmony_ci * 107462306a36Sopenharmony_ci * Returns: 107562306a36Sopenharmony_ci * 107662306a36Sopenharmony_ci * 0 on success. @eff_addr will have the referenced effective address. @regoff 107762306a36Sopenharmony_ci * will have a register, as an offset from the base of pt_regs, that can be used 107862306a36Sopenharmony_ci * to resolve the associated segment. 107962306a36Sopenharmony_ci * 108062306a36Sopenharmony_ci * -EINVAL on error. 108162306a36Sopenharmony_ci */ 108262306a36Sopenharmony_cistatic int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs, 108362306a36Sopenharmony_ci int *regoff, short *eff_addr) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci int addr_offset1, addr_offset2, ret; 108662306a36Sopenharmony_ci short addr1 = 0, addr2 = 0, displacement; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (insn->addr_bytes != 2) 108962306a36Sopenharmony_ci return -EINVAL; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci insn_get_modrm(insn); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (!insn->modrm.nbytes) 109462306a36Sopenharmony_ci return -EINVAL; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) > 2) 109762306a36Sopenharmony_ci return -EINVAL; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci ret = get_reg_offset_16(insn, regs, &addr_offset1, &addr_offset2); 110062306a36Sopenharmony_ci if (ret < 0) 110162306a36Sopenharmony_ci return -EINVAL; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* 110462306a36Sopenharmony_ci * Don't fail on invalid offset values. They might be invalid because 110562306a36Sopenharmony_ci * they cannot be used for this particular value of ModRM. Instead, use 110662306a36Sopenharmony_ci * them in the computation only if they contain a valid value. 110762306a36Sopenharmony_ci */ 110862306a36Sopenharmony_ci if (addr_offset1 != -EDOM) 110962306a36Sopenharmony_ci addr1 = regs_get_register(regs, addr_offset1) & 0xffff; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (addr_offset2 != -EDOM) 111262306a36Sopenharmony_ci addr2 = regs_get_register(regs, addr_offset2) & 0xffff; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci displacement = insn->displacement.value & 0xffff; 111562306a36Sopenharmony_ci *eff_addr = addr1 + addr2 + displacement; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* 111862306a36Sopenharmony_ci * The first operand register could indicate to use of either SS or DS 111962306a36Sopenharmony_ci * registers to obtain the segment selector. The second operand 112062306a36Sopenharmony_ci * register can only indicate the use of DS. Thus, the first operand 112162306a36Sopenharmony_ci * will be used to obtain the segment selector. 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_ci *regoff = addr_offset1; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci return 0; 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci/** 112962306a36Sopenharmony_ci * get_eff_addr_sib() - Obtain referenced effective address via SIB 113062306a36Sopenharmony_ci * @insn: Instruction. Must be valid. 113162306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 113262306a36Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, associated with segment 113362306a36Sopenharmony_ci * @eff_addr: Obtained effective address 113462306a36Sopenharmony_ci * 113562306a36Sopenharmony_ci * Obtain the effective address referenced by the SIB byte of @insn. After 113662306a36Sopenharmony_ci * identifying the registers involved in the indexed, register-indirect memory 113762306a36Sopenharmony_ci * reference, its value is obtained from the operands in @regs. The computed 113862306a36Sopenharmony_ci * address is stored @eff_addr. Also, the register operand that indicates the 113962306a36Sopenharmony_ci * associated segment is stored in @regoff, this parameter can later be used to 114062306a36Sopenharmony_ci * determine such segment. 114162306a36Sopenharmony_ci * 114262306a36Sopenharmony_ci * Returns: 114362306a36Sopenharmony_ci * 114462306a36Sopenharmony_ci * 0 on success. @eff_addr will have the referenced effective address. 114562306a36Sopenharmony_ci * @base_offset will have a register, as an offset from the base of pt_regs, 114662306a36Sopenharmony_ci * that can be used to resolve the associated segment. 114762306a36Sopenharmony_ci * 114862306a36Sopenharmony_ci * Negative value on error. 114962306a36Sopenharmony_ci */ 115062306a36Sopenharmony_cistatic int get_eff_addr_sib(struct insn *insn, struct pt_regs *regs, 115162306a36Sopenharmony_ci int *base_offset, long *eff_addr) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci long base, indx; 115462306a36Sopenharmony_ci int indx_offset; 115562306a36Sopenharmony_ci int ret; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (insn->addr_bytes != 8 && insn->addr_bytes != 4) 115862306a36Sopenharmony_ci return -EINVAL; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci ret = insn_get_modrm(insn); 116162306a36Sopenharmony_ci if (ret) 116262306a36Sopenharmony_ci return ret; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (!insn->modrm.nbytes) 116562306a36Sopenharmony_ci return -EINVAL; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) > 2) 116862306a36Sopenharmony_ci return -EINVAL; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ret = insn_get_sib(insn); 117162306a36Sopenharmony_ci if (ret) 117262306a36Sopenharmony_ci return ret; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (!insn->sib.nbytes) 117562306a36Sopenharmony_ci return -EINVAL; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci *base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE); 117862306a36Sopenharmony_ci indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* 118162306a36Sopenharmony_ci * Negative values in the base and index offset means an error when 118262306a36Sopenharmony_ci * decoding the SIB byte. Except -EDOM, which means that the registers 118362306a36Sopenharmony_ci * should not be used in the address computation. 118462306a36Sopenharmony_ci */ 118562306a36Sopenharmony_ci if (*base_offset == -EDOM) 118662306a36Sopenharmony_ci base = 0; 118762306a36Sopenharmony_ci else if (*base_offset < 0) 118862306a36Sopenharmony_ci return -EINVAL; 118962306a36Sopenharmony_ci else 119062306a36Sopenharmony_ci base = regs_get_register(regs, *base_offset); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (indx_offset == -EDOM) 119362306a36Sopenharmony_ci indx = 0; 119462306a36Sopenharmony_ci else if (indx_offset < 0) 119562306a36Sopenharmony_ci return -EINVAL; 119662306a36Sopenharmony_ci else 119762306a36Sopenharmony_ci indx = regs_get_register(regs, indx_offset); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (insn->addr_bytes == 4) { 120062306a36Sopenharmony_ci int addr32, base32, idx32; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci base32 = base & 0xffffffff; 120362306a36Sopenharmony_ci idx32 = indx & 0xffffffff; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci addr32 = base32 + idx32 * (1 << X86_SIB_SCALE(insn->sib.value)); 120662306a36Sopenharmony_ci addr32 += insn->displacement.value; 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci *eff_addr = addr32 & 0xffffffff; 120962306a36Sopenharmony_ci } else { 121062306a36Sopenharmony_ci *eff_addr = base + indx * (1 << X86_SIB_SCALE(insn->sib.value)); 121162306a36Sopenharmony_ci *eff_addr += insn->displacement.value; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci return 0; 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci/** 121862306a36Sopenharmony_ci * get_addr_ref_16() - Obtain the 16-bit address referred by instruction 121962306a36Sopenharmony_ci * @insn: Instruction containing ModRM byte and displacement 122062306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 122162306a36Sopenharmony_ci * 122262306a36Sopenharmony_ci * This function is to be used with 16-bit address encodings. Obtain the memory 122362306a36Sopenharmony_ci * address referred by the instruction's ModRM and displacement bytes. Also, the 122462306a36Sopenharmony_ci * segment used as base is determined by either any segment override prefixes in 122562306a36Sopenharmony_ci * @insn or the default segment of the registers involved in the address 122662306a36Sopenharmony_ci * computation. In protected mode, segment limits are enforced. 122762306a36Sopenharmony_ci * 122862306a36Sopenharmony_ci * Returns: 122962306a36Sopenharmony_ci * 123062306a36Sopenharmony_ci * Linear address referenced by the instruction operands on success. 123162306a36Sopenharmony_ci * 123262306a36Sopenharmony_ci * -1L on error. 123362306a36Sopenharmony_ci */ 123462306a36Sopenharmony_cistatic void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci unsigned long linear_addr = -1L, seg_base, seg_limit; 123762306a36Sopenharmony_ci int ret, regoff; 123862306a36Sopenharmony_ci short eff_addr; 123962306a36Sopenharmony_ci long tmp; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci if (insn_get_displacement(insn)) 124262306a36Sopenharmony_ci goto out; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if (insn->addr_bytes != 2) 124562306a36Sopenharmony_ci goto out; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 124862306a36Sopenharmony_ci ret = get_eff_addr_reg(insn, regs, ®off, &tmp); 124962306a36Sopenharmony_ci if (ret) 125062306a36Sopenharmony_ci goto out; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci eff_addr = tmp; 125362306a36Sopenharmony_ci } else { 125462306a36Sopenharmony_ci ret = get_eff_addr_modrm_16(insn, regs, ®off, &eff_addr); 125562306a36Sopenharmony_ci if (ret) 125662306a36Sopenharmony_ci goto out; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit); 126062306a36Sopenharmony_ci if (ret) 126162306a36Sopenharmony_ci goto out; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* 126462306a36Sopenharmony_ci * Before computing the linear address, make sure the effective address 126562306a36Sopenharmony_ci * is within the limits of the segment. In virtual-8086 mode, segment 126662306a36Sopenharmony_ci * limits are not enforced. In such a case, the segment limit is -1L to 126762306a36Sopenharmony_ci * reflect this fact. 126862306a36Sopenharmony_ci */ 126962306a36Sopenharmony_ci if ((unsigned long)(eff_addr & 0xffff) > seg_limit) 127062306a36Sopenharmony_ci goto out; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci linear_addr = (unsigned long)(eff_addr & 0xffff) + seg_base; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* Limit linear address to 20 bits */ 127562306a36Sopenharmony_ci if (v8086_mode(regs)) 127662306a36Sopenharmony_ci linear_addr &= 0xfffff; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ciout: 127962306a36Sopenharmony_ci return (void __user *)linear_addr; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci/** 128362306a36Sopenharmony_ci * get_addr_ref_32() - Obtain a 32-bit linear address 128462306a36Sopenharmony_ci * @insn: Instruction with ModRM, SIB bytes and displacement 128562306a36Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 128662306a36Sopenharmony_ci * 128762306a36Sopenharmony_ci * This function is to be used with 32-bit address encodings to obtain the 128862306a36Sopenharmony_ci * linear memory address referred by the instruction's ModRM, SIB, 128962306a36Sopenharmony_ci * displacement bytes and segment base address, as applicable. If in protected 129062306a36Sopenharmony_ci * mode, segment limits are enforced. 129162306a36Sopenharmony_ci * 129262306a36Sopenharmony_ci * Returns: 129362306a36Sopenharmony_ci * 129462306a36Sopenharmony_ci * Linear address referenced by instruction and registers on success. 129562306a36Sopenharmony_ci * 129662306a36Sopenharmony_ci * -1L on error. 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_cistatic void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci unsigned long linear_addr = -1L, seg_base, seg_limit; 130162306a36Sopenharmony_ci int eff_addr, regoff; 130262306a36Sopenharmony_ci long tmp; 130362306a36Sopenharmony_ci int ret; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (insn->addr_bytes != 4) 130662306a36Sopenharmony_ci goto out; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 130962306a36Sopenharmony_ci ret = get_eff_addr_reg(insn, regs, ®off, &tmp); 131062306a36Sopenharmony_ci if (ret) 131162306a36Sopenharmony_ci goto out; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci eff_addr = tmp; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci } else { 131662306a36Sopenharmony_ci if (insn->sib.nbytes) { 131762306a36Sopenharmony_ci ret = get_eff_addr_sib(insn, regs, ®off, &tmp); 131862306a36Sopenharmony_ci if (ret) 131962306a36Sopenharmony_ci goto out; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci eff_addr = tmp; 132262306a36Sopenharmony_ci } else { 132362306a36Sopenharmony_ci ret = get_eff_addr_modrm(insn, regs, ®off, &tmp); 132462306a36Sopenharmony_ci if (ret) 132562306a36Sopenharmony_ci goto out; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci eff_addr = tmp; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit); 133262306a36Sopenharmony_ci if (ret) 133362306a36Sopenharmony_ci goto out; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* 133662306a36Sopenharmony_ci * In protected mode, before computing the linear address, make sure 133762306a36Sopenharmony_ci * the effective address is within the limits of the segment. 133862306a36Sopenharmony_ci * 32-bit addresses can be used in long and virtual-8086 modes if an 133962306a36Sopenharmony_ci * address override prefix is used. In such cases, segment limits are 134062306a36Sopenharmony_ci * not enforced. When in virtual-8086 mode, the segment limit is -1L 134162306a36Sopenharmony_ci * to reflect this situation. 134262306a36Sopenharmony_ci * 134362306a36Sopenharmony_ci * After computed, the effective address is treated as an unsigned 134462306a36Sopenharmony_ci * quantity. 134562306a36Sopenharmony_ci */ 134662306a36Sopenharmony_ci if (!any_64bit_mode(regs) && ((unsigned int)eff_addr > seg_limit)) 134762306a36Sopenharmony_ci goto out; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci /* 135062306a36Sopenharmony_ci * Even though 32-bit address encodings are allowed in virtual-8086 135162306a36Sopenharmony_ci * mode, the address range is still limited to [0x-0xffff]. 135262306a36Sopenharmony_ci */ 135362306a36Sopenharmony_ci if (v8086_mode(regs) && (eff_addr & ~0xffff)) 135462306a36Sopenharmony_ci goto out; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci /* 135762306a36Sopenharmony_ci * Data type long could be 64 bits in size. Ensure that our 32-bit 135862306a36Sopenharmony_ci * effective address is not sign-extended when computing the linear 135962306a36Sopenharmony_ci * address. 136062306a36Sopenharmony_ci */ 136162306a36Sopenharmony_ci linear_addr = (unsigned long)(eff_addr & 0xffffffff) + seg_base; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci /* Limit linear address to 20 bits */ 136462306a36Sopenharmony_ci if (v8086_mode(regs)) 136562306a36Sopenharmony_ci linear_addr &= 0xfffff; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ciout: 136862306a36Sopenharmony_ci return (void __user *)linear_addr; 136962306a36Sopenharmony_ci} 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci/** 137262306a36Sopenharmony_ci * get_addr_ref_64() - Obtain a 64-bit linear address 137362306a36Sopenharmony_ci * @insn: Instruction struct with ModRM and SIB bytes and displacement 137462306a36Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 137562306a36Sopenharmony_ci * 137662306a36Sopenharmony_ci * This function is to be used with 64-bit address encodings to obtain the 137762306a36Sopenharmony_ci * linear memory address referred by the instruction's ModRM, SIB, 137862306a36Sopenharmony_ci * displacement bytes and segment base address, as applicable. 137962306a36Sopenharmony_ci * 138062306a36Sopenharmony_ci * Returns: 138162306a36Sopenharmony_ci * 138262306a36Sopenharmony_ci * Linear address referenced by instruction and registers on success. 138362306a36Sopenharmony_ci * 138462306a36Sopenharmony_ci * -1L on error. 138562306a36Sopenharmony_ci */ 138662306a36Sopenharmony_ci#ifndef CONFIG_X86_64 138762306a36Sopenharmony_cistatic void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci return (void __user *)-1L; 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci#else 139262306a36Sopenharmony_cistatic void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci unsigned long linear_addr = -1L, seg_base; 139562306a36Sopenharmony_ci int regoff, ret; 139662306a36Sopenharmony_ci long eff_addr; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci if (insn->addr_bytes != 8) 139962306a36Sopenharmony_ci goto out; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 140262306a36Sopenharmony_ci ret = get_eff_addr_reg(insn, regs, ®off, &eff_addr); 140362306a36Sopenharmony_ci if (ret) 140462306a36Sopenharmony_ci goto out; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci } else { 140762306a36Sopenharmony_ci if (insn->sib.nbytes) { 140862306a36Sopenharmony_ci ret = get_eff_addr_sib(insn, regs, ®off, &eff_addr); 140962306a36Sopenharmony_ci if (ret) 141062306a36Sopenharmony_ci goto out; 141162306a36Sopenharmony_ci } else { 141262306a36Sopenharmony_ci ret = get_eff_addr_modrm(insn, regs, ®off, &eff_addr); 141362306a36Sopenharmony_ci if (ret) 141462306a36Sopenharmony_ci goto out; 141562306a36Sopenharmony_ci } 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci ret = get_seg_base_limit(insn, regs, regoff, &seg_base, NULL); 142062306a36Sopenharmony_ci if (ret) 142162306a36Sopenharmony_ci goto out; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci linear_addr = (unsigned long)eff_addr + seg_base; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ciout: 142662306a36Sopenharmony_ci return (void __user *)linear_addr; 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci#endif /* CONFIG_X86_64 */ 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci/** 143162306a36Sopenharmony_ci * insn_get_addr_ref() - Obtain the linear address referred by instruction 143262306a36Sopenharmony_ci * @insn: Instruction structure containing ModRM byte and displacement 143362306a36Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 143462306a36Sopenharmony_ci * 143562306a36Sopenharmony_ci * Obtain the linear address referred by the instruction's ModRM, SIB and 143662306a36Sopenharmony_ci * displacement bytes, and segment base, as applicable. In protected mode, 143762306a36Sopenharmony_ci * segment limits are enforced. 143862306a36Sopenharmony_ci * 143962306a36Sopenharmony_ci * Returns: 144062306a36Sopenharmony_ci * 144162306a36Sopenharmony_ci * Linear address referenced by instruction and registers on success. 144262306a36Sopenharmony_ci * 144362306a36Sopenharmony_ci * -1L on error. 144462306a36Sopenharmony_ci */ 144562306a36Sopenharmony_civoid __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci if (!insn || !regs) 144862306a36Sopenharmony_ci return (void __user *)-1L; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (insn_get_opcode(insn)) 145162306a36Sopenharmony_ci return (void __user *)-1L; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci switch (insn->addr_bytes) { 145462306a36Sopenharmony_ci case 2: 145562306a36Sopenharmony_ci return get_addr_ref_16(insn, regs); 145662306a36Sopenharmony_ci case 4: 145762306a36Sopenharmony_ci return get_addr_ref_32(insn, regs); 145862306a36Sopenharmony_ci case 8: 145962306a36Sopenharmony_ci return get_addr_ref_64(insn, regs); 146062306a36Sopenharmony_ci default: 146162306a36Sopenharmony_ci return (void __user *)-1L; 146262306a36Sopenharmony_ci } 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ciint insn_get_effective_ip(struct pt_regs *regs, unsigned long *ip) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci unsigned long seg_base = 0; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* 147062306a36Sopenharmony_ci * If not in user-space long mode, a custom code segment could be in 147162306a36Sopenharmony_ci * use. This is true in protected mode (if the process defined a local 147262306a36Sopenharmony_ci * descriptor table), or virtual-8086 mode. In most of the cases 147362306a36Sopenharmony_ci * seg_base will be zero as in USER_CS. 147462306a36Sopenharmony_ci */ 147562306a36Sopenharmony_ci if (!user_64bit_mode(regs)) { 147662306a36Sopenharmony_ci seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS); 147762306a36Sopenharmony_ci if (seg_base == -1L) 147862306a36Sopenharmony_ci return -EINVAL; 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci *ip = seg_base + regs->ip; 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci return 0; 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci/** 148762306a36Sopenharmony_ci * insn_fetch_from_user() - Copy instruction bytes from user-space memory 148862306a36Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 148962306a36Sopenharmony_ci * @buf: Array to store the fetched instruction 149062306a36Sopenharmony_ci * 149162306a36Sopenharmony_ci * Gets the linear address of the instruction and copies the instruction bytes 149262306a36Sopenharmony_ci * to the buf. 149362306a36Sopenharmony_ci * 149462306a36Sopenharmony_ci * Returns: 149562306a36Sopenharmony_ci * 149662306a36Sopenharmony_ci * - number of instruction bytes copied. 149762306a36Sopenharmony_ci * - 0 if nothing was copied. 149862306a36Sopenharmony_ci * - -EINVAL if the linear address of the instruction could not be calculated 149962306a36Sopenharmony_ci */ 150062306a36Sopenharmony_ciint insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) 150162306a36Sopenharmony_ci{ 150262306a36Sopenharmony_ci unsigned long ip; 150362306a36Sopenharmony_ci int not_copied; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci if (insn_get_effective_ip(regs, &ip)) 150662306a36Sopenharmony_ci return -EINVAL; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci not_copied = copy_from_user(buf, (void __user *)ip, MAX_INSN_SIZE); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci return MAX_INSN_SIZE - not_copied; 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci/** 151462306a36Sopenharmony_ci * insn_fetch_from_user_inatomic() - Copy instruction bytes from user-space memory 151562306a36Sopenharmony_ci * while in atomic code 151662306a36Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 151762306a36Sopenharmony_ci * @buf: Array to store the fetched instruction 151862306a36Sopenharmony_ci * 151962306a36Sopenharmony_ci * Gets the linear address of the instruction and copies the instruction bytes 152062306a36Sopenharmony_ci * to the buf. This function must be used in atomic context. 152162306a36Sopenharmony_ci * 152262306a36Sopenharmony_ci * Returns: 152362306a36Sopenharmony_ci * 152462306a36Sopenharmony_ci * - number of instruction bytes copied. 152562306a36Sopenharmony_ci * - 0 if nothing was copied. 152662306a36Sopenharmony_ci * - -EINVAL if the linear address of the instruction could not be calculated. 152762306a36Sopenharmony_ci */ 152862306a36Sopenharmony_ciint insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci unsigned long ip; 153162306a36Sopenharmony_ci int not_copied; 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (insn_get_effective_ip(regs, &ip)) 153462306a36Sopenharmony_ci return -EINVAL; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci not_copied = __copy_from_user_inatomic(buf, (void __user *)ip, MAX_INSN_SIZE); 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci return MAX_INSN_SIZE - not_copied; 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci/** 154262306a36Sopenharmony_ci * insn_decode_from_regs() - Decode an instruction 154362306a36Sopenharmony_ci * @insn: Structure to store decoded instruction 154462306a36Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 154562306a36Sopenharmony_ci * @buf: Buffer containing the instruction bytes 154662306a36Sopenharmony_ci * @buf_size: Number of instruction bytes available in buf 154762306a36Sopenharmony_ci * 154862306a36Sopenharmony_ci * Decodes the instruction provided in buf and stores the decoding results in 154962306a36Sopenharmony_ci * insn. Also determines the correct address and operand sizes. 155062306a36Sopenharmony_ci * 155162306a36Sopenharmony_ci * Returns: 155262306a36Sopenharmony_ci * 155362306a36Sopenharmony_ci * True if instruction was decoded, False otherwise. 155462306a36Sopenharmony_ci */ 155562306a36Sopenharmony_cibool insn_decode_from_regs(struct insn *insn, struct pt_regs *regs, 155662306a36Sopenharmony_ci unsigned char buf[MAX_INSN_SIZE], int buf_size) 155762306a36Sopenharmony_ci{ 155862306a36Sopenharmony_ci int seg_defs; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci insn_init(insn, buf, buf_size, user_64bit_mode(regs)); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* 156362306a36Sopenharmony_ci * Override the default operand and address sizes with what is specified 156462306a36Sopenharmony_ci * in the code segment descriptor. The instruction decoder only sets 156562306a36Sopenharmony_ci * the address size it to either 4 or 8 address bytes and does nothing 156662306a36Sopenharmony_ci * for the operand bytes. This OK for most of the cases, but we could 156762306a36Sopenharmony_ci * have special cases where, for instance, a 16-bit code segment 156862306a36Sopenharmony_ci * descriptor is used. 156962306a36Sopenharmony_ci * If there is an address override prefix, the instruction decoder 157062306a36Sopenharmony_ci * correctly updates these values, even for 16-bit defaults. 157162306a36Sopenharmony_ci */ 157262306a36Sopenharmony_ci seg_defs = insn_get_code_seg_params(regs); 157362306a36Sopenharmony_ci if (seg_defs == -EINVAL) 157462306a36Sopenharmony_ci return false; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci insn->addr_bytes = INSN_CODE_SEG_ADDR_SZ(seg_defs); 157762306a36Sopenharmony_ci insn->opnd_bytes = INSN_CODE_SEG_OPND_SZ(seg_defs); 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci if (insn_get_length(insn)) 158062306a36Sopenharmony_ci return false; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci if (buf_size < insn->length) 158362306a36Sopenharmony_ci return false; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci return true; 158662306a36Sopenharmony_ci} 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci/** 158962306a36Sopenharmony_ci * insn_decode_mmio() - Decode a MMIO instruction 159062306a36Sopenharmony_ci * @insn: Structure to store decoded instruction 159162306a36Sopenharmony_ci * @bytes: Returns size of memory operand 159262306a36Sopenharmony_ci * 159362306a36Sopenharmony_ci * Decodes instruction that used for Memory-mapped I/O. 159462306a36Sopenharmony_ci * 159562306a36Sopenharmony_ci * Returns: 159662306a36Sopenharmony_ci * 159762306a36Sopenharmony_ci * Type of the instruction. Size of the memory operand is stored in 159862306a36Sopenharmony_ci * @bytes. If decode failed, INSN_MMIO_DECODE_FAILED returned. 159962306a36Sopenharmony_ci */ 160062306a36Sopenharmony_cienum insn_mmio_type insn_decode_mmio(struct insn *insn, int *bytes) 160162306a36Sopenharmony_ci{ 160262306a36Sopenharmony_ci enum insn_mmio_type type = INSN_MMIO_DECODE_FAILED; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci *bytes = 0; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci if (insn_get_opcode(insn)) 160762306a36Sopenharmony_ci return INSN_MMIO_DECODE_FAILED; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci switch (insn->opcode.bytes[0]) { 161062306a36Sopenharmony_ci case 0x88: /* MOV m8,r8 */ 161162306a36Sopenharmony_ci *bytes = 1; 161262306a36Sopenharmony_ci fallthrough; 161362306a36Sopenharmony_ci case 0x89: /* MOV m16/m32/m64, r16/m32/m64 */ 161462306a36Sopenharmony_ci if (!*bytes) 161562306a36Sopenharmony_ci *bytes = insn->opnd_bytes; 161662306a36Sopenharmony_ci type = INSN_MMIO_WRITE; 161762306a36Sopenharmony_ci break; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci case 0xc6: /* MOV m8, imm8 */ 162062306a36Sopenharmony_ci *bytes = 1; 162162306a36Sopenharmony_ci fallthrough; 162262306a36Sopenharmony_ci case 0xc7: /* MOV m16/m32/m64, imm16/imm32/imm64 */ 162362306a36Sopenharmony_ci if (!*bytes) 162462306a36Sopenharmony_ci *bytes = insn->opnd_bytes; 162562306a36Sopenharmony_ci type = INSN_MMIO_WRITE_IMM; 162662306a36Sopenharmony_ci break; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci case 0x8a: /* MOV r8, m8 */ 162962306a36Sopenharmony_ci *bytes = 1; 163062306a36Sopenharmony_ci fallthrough; 163162306a36Sopenharmony_ci case 0x8b: /* MOV r16/r32/r64, m16/m32/m64 */ 163262306a36Sopenharmony_ci if (!*bytes) 163362306a36Sopenharmony_ci *bytes = insn->opnd_bytes; 163462306a36Sopenharmony_ci type = INSN_MMIO_READ; 163562306a36Sopenharmony_ci break; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci case 0xa4: /* MOVS m8, m8 */ 163862306a36Sopenharmony_ci *bytes = 1; 163962306a36Sopenharmony_ci fallthrough; 164062306a36Sopenharmony_ci case 0xa5: /* MOVS m16/m32/m64, m16/m32/m64 */ 164162306a36Sopenharmony_ci if (!*bytes) 164262306a36Sopenharmony_ci *bytes = insn->opnd_bytes; 164362306a36Sopenharmony_ci type = INSN_MMIO_MOVS; 164462306a36Sopenharmony_ci break; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci case 0x0f: /* Two-byte instruction */ 164762306a36Sopenharmony_ci switch (insn->opcode.bytes[1]) { 164862306a36Sopenharmony_ci case 0xb6: /* MOVZX r16/r32/r64, m8 */ 164962306a36Sopenharmony_ci *bytes = 1; 165062306a36Sopenharmony_ci fallthrough; 165162306a36Sopenharmony_ci case 0xb7: /* MOVZX r32/r64, m16 */ 165262306a36Sopenharmony_ci if (!*bytes) 165362306a36Sopenharmony_ci *bytes = 2; 165462306a36Sopenharmony_ci type = INSN_MMIO_READ_ZERO_EXTEND; 165562306a36Sopenharmony_ci break; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci case 0xbe: /* MOVSX r16/r32/r64, m8 */ 165862306a36Sopenharmony_ci *bytes = 1; 165962306a36Sopenharmony_ci fallthrough; 166062306a36Sopenharmony_ci case 0xbf: /* MOVSX r32/r64, m16 */ 166162306a36Sopenharmony_ci if (!*bytes) 166262306a36Sopenharmony_ci *bytes = 2; 166362306a36Sopenharmony_ci type = INSN_MMIO_READ_SIGN_EXTEND; 166462306a36Sopenharmony_ci break; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci break; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci return type; 167062306a36Sopenharmony_ci} 1671