18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Utility functions for x86 operand and address decoding 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) Intel Corporation 2017 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/string.h> 88c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 98c2ecf20Sopenharmony_ci#include <linux/mmu_context.h> 108c2ecf20Sopenharmony_ci#include <asm/desc_defs.h> 118c2ecf20Sopenharmony_ci#include <asm/desc.h> 128c2ecf20Sopenharmony_ci#include <asm/inat.h> 138c2ecf20Sopenharmony_ci#include <asm/insn.h> 148c2ecf20Sopenharmony_ci#include <asm/insn-eval.h> 158c2ecf20Sopenharmony_ci#include <asm/ldt.h> 168c2ecf20Sopenharmony_ci#include <asm/vm86.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#undef pr_fmt 198c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "insn: " fmt 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cienum reg_type { 228c2ecf20Sopenharmony_ci REG_TYPE_RM = 0, 238c2ecf20Sopenharmony_ci REG_TYPE_REG, 248c2ecf20Sopenharmony_ci REG_TYPE_INDEX, 258c2ecf20Sopenharmony_ci REG_TYPE_BASE, 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * is_string_insn() - Determine if instruction is a string instruction 308c2ecf20Sopenharmony_ci * @insn: Instruction containing the opcode to inspect 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Returns: 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * true if the instruction, determined by the opcode, is any of the 358c2ecf20Sopenharmony_ci * string instructions as defined in the Intel Software Development manual. 368c2ecf20Sopenharmony_ci * False otherwise. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_cistatic bool is_string_insn(struct insn *insn) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci insn_get_opcode(insn); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* All string instructions have a 1-byte opcode. */ 438c2ecf20Sopenharmony_ci if (insn->opcode.nbytes != 1) 448c2ecf20Sopenharmony_ci return false; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci switch (insn->opcode.bytes[0]) { 478c2ecf20Sopenharmony_ci case 0x6c ... 0x6f: /* INS, OUTS */ 488c2ecf20Sopenharmony_ci case 0xa4 ... 0xa7: /* MOVS, CMPS */ 498c2ecf20Sopenharmony_ci case 0xaa ... 0xaf: /* STOS, LODS, SCAS */ 508c2ecf20Sopenharmony_ci return true; 518c2ecf20Sopenharmony_ci default: 528c2ecf20Sopenharmony_ci return false; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/** 578c2ecf20Sopenharmony_ci * insn_has_rep_prefix() - Determine if instruction has a REP prefix 588c2ecf20Sopenharmony_ci * @insn: Instruction containing the prefix to inspect 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * Returns: 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * true if the instruction has a REP prefix, false if not. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cibool insn_has_rep_prefix(struct insn *insn) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci insn_byte_t p; 678c2ecf20Sopenharmony_ci int i; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci insn_get_prefixes(insn); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci for_each_insn_prefix(insn, i, p) { 728c2ecf20Sopenharmony_ci if (p == 0xf2 || p == 0xf3) 738c2ecf20Sopenharmony_ci return true; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return false; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/** 808c2ecf20Sopenharmony_ci * get_seg_reg_override_idx() - obtain segment register override index 818c2ecf20Sopenharmony_ci * @insn: Valid instruction with segment override prefixes 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * Inspect the instruction prefixes in @insn and find segment overrides, if any. 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * Returns: 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * A constant identifying the segment register to use, among CS, SS, DS, 888c2ecf20Sopenharmony_ci * ES, FS, or GS. INAT_SEG_REG_DEFAULT is returned if no segment override 898c2ecf20Sopenharmony_ci * prefixes were found. 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * -EINVAL in case of error. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cistatic int get_seg_reg_override_idx(struct insn *insn) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci int idx = INAT_SEG_REG_DEFAULT; 968c2ecf20Sopenharmony_ci int num_overrides = 0, i; 978c2ecf20Sopenharmony_ci insn_byte_t p; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci insn_get_prefixes(insn); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Look for any segment override prefixes. */ 1028c2ecf20Sopenharmony_ci for_each_insn_prefix(insn, i, p) { 1038c2ecf20Sopenharmony_ci insn_attr_t attr; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci attr = inat_get_opcode_attribute(p); 1068c2ecf20Sopenharmony_ci switch (attr) { 1078c2ecf20Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_CS): 1088c2ecf20Sopenharmony_ci idx = INAT_SEG_REG_CS; 1098c2ecf20Sopenharmony_ci num_overrides++; 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_SS): 1128c2ecf20Sopenharmony_ci idx = INAT_SEG_REG_SS; 1138c2ecf20Sopenharmony_ci num_overrides++; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_DS): 1168c2ecf20Sopenharmony_ci idx = INAT_SEG_REG_DS; 1178c2ecf20Sopenharmony_ci num_overrides++; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_ES): 1208c2ecf20Sopenharmony_ci idx = INAT_SEG_REG_ES; 1218c2ecf20Sopenharmony_ci num_overrides++; 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_FS): 1248c2ecf20Sopenharmony_ci idx = INAT_SEG_REG_FS; 1258c2ecf20Sopenharmony_ci num_overrides++; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case INAT_MAKE_PREFIX(INAT_PFX_GS): 1288c2ecf20Sopenharmony_ci idx = INAT_SEG_REG_GS; 1298c2ecf20Sopenharmony_ci num_overrides++; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci /* No default action needed. */ 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* More than one segment override prefix leads to undefined behavior. */ 1368c2ecf20Sopenharmony_ci if (num_overrides > 1) 1378c2ecf20Sopenharmony_ci return -EINVAL; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return idx; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/** 1438c2ecf20Sopenharmony_ci * check_seg_overrides() - check if segment override prefixes are allowed 1448c2ecf20Sopenharmony_ci * @insn: Valid instruction with segment override prefixes 1458c2ecf20Sopenharmony_ci * @regoff: Operand offset, in pt_regs, for which the check is performed 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * For a particular register used in register-indirect addressing, determine if 1488c2ecf20Sopenharmony_ci * segment override prefixes can be used. Specifically, no overrides are allowed 1498c2ecf20Sopenharmony_ci * for rDI if used with a string instruction. 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * Returns: 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci * True if segment override prefixes can be used with the register indicated 1548c2ecf20Sopenharmony_ci * in @regoff. False if otherwise. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_cistatic bool check_seg_overrides(struct insn *insn, int regoff) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci if (regoff == offsetof(struct pt_regs, di) && is_string_insn(insn)) 1598c2ecf20Sopenharmony_ci return false; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return true; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/** 1658c2ecf20Sopenharmony_ci * resolve_default_seg() - resolve default segment register index for an operand 1668c2ecf20Sopenharmony_ci * @insn: Instruction with opcode and address size. Must be valid. 1678c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 1688c2ecf20Sopenharmony_ci * @off: Operand offset, in pt_regs, for which resolution is needed 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Resolve the default segment register index associated with the instruction 1718c2ecf20Sopenharmony_ci * operand register indicated by @off. Such index is resolved based on defaults 1728c2ecf20Sopenharmony_ci * described in the Intel Software Development Manual. 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Returns: 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * If in protected mode, a constant identifying the segment register to use, 1778c2ecf20Sopenharmony_ci * among CS, SS, ES or DS. If in long mode, INAT_SEG_REG_IGNORE. 1788c2ecf20Sopenharmony_ci * 1798c2ecf20Sopenharmony_ci * -EINVAL in case of error. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic int resolve_default_seg(struct insn *insn, struct pt_regs *regs, int off) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci if (any_64bit_mode(regs)) 1848c2ecf20Sopenharmony_ci return INAT_SEG_REG_IGNORE; 1858c2ecf20Sopenharmony_ci /* 1868c2ecf20Sopenharmony_ci * Resolve the default segment register as described in Section 3.7.4 1878c2ecf20Sopenharmony_ci * of the Intel Software Development Manual Vol. 1: 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * + DS for all references involving r[ABCD]X, and rSI. 1908c2ecf20Sopenharmony_ci * + If used in a string instruction, ES for rDI. Otherwise, DS. 1918c2ecf20Sopenharmony_ci * + AX, CX and DX are not valid register operands in 16-bit address 1928c2ecf20Sopenharmony_ci * encodings but are valid for 32-bit and 64-bit encodings. 1938c2ecf20Sopenharmony_ci * + -EDOM is reserved to identify for cases in which no register 1948c2ecf20Sopenharmony_ci * is used (i.e., displacement-only addressing). Use DS. 1958c2ecf20Sopenharmony_ci * + SS for rSP or rBP. 1968c2ecf20Sopenharmony_ci * + CS for rIP. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci switch (off) { 2008c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, ax): 2018c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, cx): 2028c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, dx): 2038c2ecf20Sopenharmony_ci /* Need insn to verify address size. */ 2048c2ecf20Sopenharmony_ci if (insn->addr_bytes == 2) 2058c2ecf20Sopenharmony_ci return -EINVAL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci fallthrough; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci case -EDOM: 2108c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, bx): 2118c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, si): 2128c2ecf20Sopenharmony_ci return INAT_SEG_REG_DS; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, di): 2158c2ecf20Sopenharmony_ci if (is_string_insn(insn)) 2168c2ecf20Sopenharmony_ci return INAT_SEG_REG_ES; 2178c2ecf20Sopenharmony_ci return INAT_SEG_REG_DS; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, bp): 2208c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, sp): 2218c2ecf20Sopenharmony_ci return INAT_SEG_REG_SS; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci case offsetof(struct pt_regs, ip): 2248c2ecf20Sopenharmony_ci return INAT_SEG_REG_CS; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci default: 2278c2ecf20Sopenharmony_ci return -EINVAL; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/** 2328c2ecf20Sopenharmony_ci * resolve_seg_reg() - obtain segment register index 2338c2ecf20Sopenharmony_ci * @insn: Instruction with operands 2348c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 2358c2ecf20Sopenharmony_ci * @regoff: Operand offset, in pt_regs, used to deterimine segment register 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Determine the segment register associated with the operands and, if 2388c2ecf20Sopenharmony_ci * applicable, prefixes and the instruction pointed by @insn. 2398c2ecf20Sopenharmony_ci * 2408c2ecf20Sopenharmony_ci * The segment register associated to an operand used in register-indirect 2418c2ecf20Sopenharmony_ci * addressing depends on: 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * a) Whether running in long mode (in such a case segments are ignored, except 2448c2ecf20Sopenharmony_ci * if FS or GS are used). 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci * b) Whether segment override prefixes can be used. Certain instructions and 2478c2ecf20Sopenharmony_ci * registers do not allow override prefixes. 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * c) Whether segment overrides prefixes are found in the instruction prefixes. 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * d) If there are not segment override prefixes or they cannot be used, the 2528c2ecf20Sopenharmony_ci * default segment register associated with the operand register is used. 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * The function checks first if segment override prefixes can be used with the 2558c2ecf20Sopenharmony_ci * operand indicated by @regoff. If allowed, obtain such overridden segment 2568c2ecf20Sopenharmony_ci * register index. Lastly, if not prefixes were found or cannot be used, resolve 2578c2ecf20Sopenharmony_ci * the segment register index to use based on the defaults described in the 2588c2ecf20Sopenharmony_ci * Intel documentation. In long mode, all segment register indexes will be 2598c2ecf20Sopenharmony_ci * ignored, except if overrides were found for FS or GS. All these operations 2608c2ecf20Sopenharmony_ci * are done using helper functions. 2618c2ecf20Sopenharmony_ci * 2628c2ecf20Sopenharmony_ci * The operand register, @regoff, is represented as the offset from the base of 2638c2ecf20Sopenharmony_ci * pt_regs. 2648c2ecf20Sopenharmony_ci * 2658c2ecf20Sopenharmony_ci * As stated, the main use of this function is to determine the segment register 2668c2ecf20Sopenharmony_ci * index based on the instruction, its operands and prefixes. Hence, @insn 2678c2ecf20Sopenharmony_ci * must be valid. However, if @regoff indicates rIP, we don't need to inspect 2688c2ecf20Sopenharmony_ci * @insn at all as in this case CS is used in all cases. This case is checked 2698c2ecf20Sopenharmony_ci * before proceeding further. 2708c2ecf20Sopenharmony_ci * 2718c2ecf20Sopenharmony_ci * Please note that this function does not return the value in the segment 2728c2ecf20Sopenharmony_ci * register (i.e., the segment selector) but our defined index. The segment 2738c2ecf20Sopenharmony_ci * selector needs to be obtained using get_segment_selector() and passing the 2748c2ecf20Sopenharmony_ci * segment register index resolved by this function. 2758c2ecf20Sopenharmony_ci * 2768c2ecf20Sopenharmony_ci * Returns: 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci * An index identifying the segment register to use, among CS, SS, DS, 2798c2ecf20Sopenharmony_ci * ES, FS, or GS. INAT_SEG_REG_IGNORE is returned if running in long mode. 2808c2ecf20Sopenharmony_ci * 2818c2ecf20Sopenharmony_ci * -EINVAL in case of error. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_cistatic int resolve_seg_reg(struct insn *insn, struct pt_regs *regs, int regoff) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int idx; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* 2888c2ecf20Sopenharmony_ci * In the unlikely event of having to resolve the segment register 2898c2ecf20Sopenharmony_ci * index for rIP, do it first. Segment override prefixes should not 2908c2ecf20Sopenharmony_ci * be used. Hence, it is not necessary to inspect the instruction, 2918c2ecf20Sopenharmony_ci * which may be invalid at this point. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_ci if (regoff == offsetof(struct pt_regs, ip)) { 2948c2ecf20Sopenharmony_ci if (any_64bit_mode(regs)) 2958c2ecf20Sopenharmony_ci return INAT_SEG_REG_IGNORE; 2968c2ecf20Sopenharmony_ci else 2978c2ecf20Sopenharmony_ci return INAT_SEG_REG_CS; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (!insn) 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (!check_seg_overrides(insn, regoff)) 3048c2ecf20Sopenharmony_ci return resolve_default_seg(insn, regs, regoff); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci idx = get_seg_reg_override_idx(insn); 3078c2ecf20Sopenharmony_ci if (idx < 0) 3088c2ecf20Sopenharmony_ci return idx; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (idx == INAT_SEG_REG_DEFAULT) 3118c2ecf20Sopenharmony_ci return resolve_default_seg(insn, regs, regoff); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * In long mode, segment override prefixes are ignored, except for 3158c2ecf20Sopenharmony_ci * overrides for FS and GS. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci if (any_64bit_mode(regs)) { 3188c2ecf20Sopenharmony_ci if (idx != INAT_SEG_REG_FS && 3198c2ecf20Sopenharmony_ci idx != INAT_SEG_REG_GS) 3208c2ecf20Sopenharmony_ci idx = INAT_SEG_REG_IGNORE; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci return idx; 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci/** 3278c2ecf20Sopenharmony_ci * get_segment_selector() - obtain segment selector 3288c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 3298c2ecf20Sopenharmony_ci * @seg_reg_idx: Segment register index to use 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * Obtain the segment selector from any of the CS, SS, DS, ES, FS, GS segment 3328c2ecf20Sopenharmony_ci * registers. In CONFIG_X86_32, the segment is obtained from either pt_regs or 3338c2ecf20Sopenharmony_ci * kernel_vm86_regs as applicable. In CONFIG_X86_64, CS and SS are obtained 3348c2ecf20Sopenharmony_ci * from pt_regs. DS, ES, FS and GS are obtained by reading the actual CPU 3358c2ecf20Sopenharmony_ci * registers. This done for only for completeness as in CONFIG_X86_64 segment 3368c2ecf20Sopenharmony_ci * registers are ignored. 3378c2ecf20Sopenharmony_ci * 3388c2ecf20Sopenharmony_ci * Returns: 3398c2ecf20Sopenharmony_ci * 3408c2ecf20Sopenharmony_ci * Value of the segment selector, including null when running in 3418c2ecf20Sopenharmony_ci * long mode. 3428c2ecf20Sopenharmony_ci * 3438c2ecf20Sopenharmony_ci * -EINVAL on error. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_cistatic short get_segment_selector(struct pt_regs *regs, int seg_reg_idx) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 3488c2ecf20Sopenharmony_ci unsigned short sel; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci switch (seg_reg_idx) { 3518c2ecf20Sopenharmony_ci case INAT_SEG_REG_IGNORE: 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci case INAT_SEG_REG_CS: 3548c2ecf20Sopenharmony_ci return (unsigned short)(regs->cs & 0xffff); 3558c2ecf20Sopenharmony_ci case INAT_SEG_REG_SS: 3568c2ecf20Sopenharmony_ci return (unsigned short)(regs->ss & 0xffff); 3578c2ecf20Sopenharmony_ci case INAT_SEG_REG_DS: 3588c2ecf20Sopenharmony_ci savesegment(ds, sel); 3598c2ecf20Sopenharmony_ci return sel; 3608c2ecf20Sopenharmony_ci case INAT_SEG_REG_ES: 3618c2ecf20Sopenharmony_ci savesegment(es, sel); 3628c2ecf20Sopenharmony_ci return sel; 3638c2ecf20Sopenharmony_ci case INAT_SEG_REG_FS: 3648c2ecf20Sopenharmony_ci savesegment(fs, sel); 3658c2ecf20Sopenharmony_ci return sel; 3668c2ecf20Sopenharmony_ci case INAT_SEG_REG_GS: 3678c2ecf20Sopenharmony_ci savesegment(gs, sel); 3688c2ecf20Sopenharmony_ci return sel; 3698c2ecf20Sopenharmony_ci default: 3708c2ecf20Sopenharmony_ci return -EINVAL; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci#else /* CONFIG_X86_32 */ 3738c2ecf20Sopenharmony_ci struct kernel_vm86_regs *vm86regs = (struct kernel_vm86_regs *)regs; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (v8086_mode(regs)) { 3768c2ecf20Sopenharmony_ci switch (seg_reg_idx) { 3778c2ecf20Sopenharmony_ci case INAT_SEG_REG_CS: 3788c2ecf20Sopenharmony_ci return (unsigned short)(regs->cs & 0xffff); 3798c2ecf20Sopenharmony_ci case INAT_SEG_REG_SS: 3808c2ecf20Sopenharmony_ci return (unsigned short)(regs->ss & 0xffff); 3818c2ecf20Sopenharmony_ci case INAT_SEG_REG_DS: 3828c2ecf20Sopenharmony_ci return vm86regs->ds; 3838c2ecf20Sopenharmony_ci case INAT_SEG_REG_ES: 3848c2ecf20Sopenharmony_ci return vm86regs->es; 3858c2ecf20Sopenharmony_ci case INAT_SEG_REG_FS: 3868c2ecf20Sopenharmony_ci return vm86regs->fs; 3878c2ecf20Sopenharmony_ci case INAT_SEG_REG_GS: 3888c2ecf20Sopenharmony_ci return vm86regs->gs; 3898c2ecf20Sopenharmony_ci case INAT_SEG_REG_IGNORE: 3908c2ecf20Sopenharmony_ci default: 3918c2ecf20Sopenharmony_ci return -EINVAL; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci switch (seg_reg_idx) { 3968c2ecf20Sopenharmony_ci case INAT_SEG_REG_CS: 3978c2ecf20Sopenharmony_ci return (unsigned short)(regs->cs & 0xffff); 3988c2ecf20Sopenharmony_ci case INAT_SEG_REG_SS: 3998c2ecf20Sopenharmony_ci return (unsigned short)(regs->ss & 0xffff); 4008c2ecf20Sopenharmony_ci case INAT_SEG_REG_DS: 4018c2ecf20Sopenharmony_ci return (unsigned short)(regs->ds & 0xffff); 4028c2ecf20Sopenharmony_ci case INAT_SEG_REG_ES: 4038c2ecf20Sopenharmony_ci return (unsigned short)(regs->es & 0xffff); 4048c2ecf20Sopenharmony_ci case INAT_SEG_REG_FS: 4058c2ecf20Sopenharmony_ci return (unsigned short)(regs->fs & 0xffff); 4068c2ecf20Sopenharmony_ci case INAT_SEG_REG_GS: 4078c2ecf20Sopenharmony_ci /* 4088c2ecf20Sopenharmony_ci * GS may or may not be in regs as per CONFIG_X86_32_LAZY_GS. 4098c2ecf20Sopenharmony_ci * The macro below takes care of both cases. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_ci return get_user_gs(regs); 4128c2ecf20Sopenharmony_ci case INAT_SEG_REG_IGNORE: 4138c2ecf20Sopenharmony_ci default: 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_64 */ 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int get_reg_offset(struct insn *insn, struct pt_regs *regs, 4208c2ecf20Sopenharmony_ci enum reg_type type) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci int regno = 0; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci static const int regoff[] = { 4258c2ecf20Sopenharmony_ci offsetof(struct pt_regs, ax), 4268c2ecf20Sopenharmony_ci offsetof(struct pt_regs, cx), 4278c2ecf20Sopenharmony_ci offsetof(struct pt_regs, dx), 4288c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bx), 4298c2ecf20Sopenharmony_ci offsetof(struct pt_regs, sp), 4308c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bp), 4318c2ecf20Sopenharmony_ci offsetof(struct pt_regs, si), 4328c2ecf20Sopenharmony_ci offsetof(struct pt_regs, di), 4338c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 4348c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r8), 4358c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r9), 4368c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r10), 4378c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r11), 4388c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r12), 4398c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r13), 4408c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r14), 4418c2ecf20Sopenharmony_ci offsetof(struct pt_regs, r15), 4428c2ecf20Sopenharmony_ci#endif 4438c2ecf20Sopenharmony_ci }; 4448c2ecf20Sopenharmony_ci int nr_registers = ARRAY_SIZE(regoff); 4458c2ecf20Sopenharmony_ci /* 4468c2ecf20Sopenharmony_ci * Don't possibly decode a 32-bit instructions as 4478c2ecf20Sopenharmony_ci * reading a 64-bit-only register. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64) 4508c2ecf20Sopenharmony_ci nr_registers -= 8; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci switch (type) { 4538c2ecf20Sopenharmony_ci case REG_TYPE_RM: 4548c2ecf20Sopenharmony_ci regno = X86_MODRM_RM(insn->modrm.value); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* 4578c2ecf20Sopenharmony_ci * ModRM.mod == 0 and ModRM.rm == 5 means a 32-bit displacement 4588c2ecf20Sopenharmony_ci * follows the ModRM byte. 4598c2ecf20Sopenharmony_ci */ 4608c2ecf20Sopenharmony_ci if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5) 4618c2ecf20Sopenharmony_ci return -EDOM; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (X86_REX_B(insn->rex_prefix.value)) 4648c2ecf20Sopenharmony_ci regno += 8; 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci case REG_TYPE_REG: 4688c2ecf20Sopenharmony_ci regno = X86_MODRM_REG(insn->modrm.value); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (X86_REX_R(insn->rex_prefix.value)) 4718c2ecf20Sopenharmony_ci regno += 8; 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci case REG_TYPE_INDEX: 4758c2ecf20Sopenharmony_ci regno = X86_SIB_INDEX(insn->sib.value); 4768c2ecf20Sopenharmony_ci if (X86_REX_X(insn->rex_prefix.value)) 4778c2ecf20Sopenharmony_ci regno += 8; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* 4808c2ecf20Sopenharmony_ci * If ModRM.mod != 3 and SIB.index = 4 the scale*index 4818c2ecf20Sopenharmony_ci * portion of the address computation is null. This is 4828c2ecf20Sopenharmony_ci * true only if REX.X is 0. In such a case, the SIB index 4838c2ecf20Sopenharmony_ci * is used in the address computation. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) != 3 && regno == 4) 4868c2ecf20Sopenharmony_ci return -EDOM; 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci case REG_TYPE_BASE: 4908c2ecf20Sopenharmony_ci regno = X86_SIB_BASE(insn->sib.value); 4918c2ecf20Sopenharmony_ci /* 4928c2ecf20Sopenharmony_ci * If ModRM.mod is 0 and SIB.base == 5, the base of the 4938c2ecf20Sopenharmony_ci * register-indirect addressing is 0. In this case, a 4948c2ecf20Sopenharmony_ci * 32-bit displacement follows the SIB byte. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5) 4978c2ecf20Sopenharmony_ci return -EDOM; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (X86_REX_B(insn->rex_prefix.value)) 5008c2ecf20Sopenharmony_ci regno += 8; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci default: 5048c2ecf20Sopenharmony_ci pr_err_ratelimited("invalid register type: %d\n", type); 5058c2ecf20Sopenharmony_ci return -EINVAL; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (regno >= nr_registers) { 5098c2ecf20Sopenharmony_ci WARN_ONCE(1, "decoded an instruction with an invalid register"); 5108c2ecf20Sopenharmony_ci return -EINVAL; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci return regoff[regno]; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/** 5168c2ecf20Sopenharmony_ci * get_reg_offset_16() - Obtain offset of register indicated by instruction 5178c2ecf20Sopenharmony_ci * @insn: Instruction containing ModRM byte 5188c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 5198c2ecf20Sopenharmony_ci * @offs1: Offset of the first operand register 5208c2ecf20Sopenharmony_ci * @offs2: Offset of the second opeand register, if applicable 5218c2ecf20Sopenharmony_ci * 5228c2ecf20Sopenharmony_ci * Obtain the offset, in pt_regs, of the registers indicated by the ModRM byte 5238c2ecf20Sopenharmony_ci * in @insn. This function is to be used with 16-bit address encodings. The 5248c2ecf20Sopenharmony_ci * @offs1 and @offs2 will be written with the offset of the two registers 5258c2ecf20Sopenharmony_ci * indicated by the instruction. In cases where any of the registers is not 5268c2ecf20Sopenharmony_ci * referenced by the instruction, the value will be set to -EDOM. 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * Returns: 5298c2ecf20Sopenharmony_ci * 5308c2ecf20Sopenharmony_ci * 0 on success, -EINVAL on error. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_cistatic int get_reg_offset_16(struct insn *insn, struct pt_regs *regs, 5338c2ecf20Sopenharmony_ci int *offs1, int *offs2) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci /* 5368c2ecf20Sopenharmony_ci * 16-bit addressing can use one or two registers. Specifics of 5378c2ecf20Sopenharmony_ci * encodings are given in Table 2-1. "16-Bit Addressing Forms with the 5388c2ecf20Sopenharmony_ci * ModR/M Byte" of the Intel Software Development Manual. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_ci static const int regoff1[] = { 5418c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bx), 5428c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bx), 5438c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bp), 5448c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bp), 5458c2ecf20Sopenharmony_ci offsetof(struct pt_regs, si), 5468c2ecf20Sopenharmony_ci offsetof(struct pt_regs, di), 5478c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bp), 5488c2ecf20Sopenharmony_ci offsetof(struct pt_regs, bx), 5498c2ecf20Sopenharmony_ci }; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci static const int regoff2[] = { 5528c2ecf20Sopenharmony_ci offsetof(struct pt_regs, si), 5538c2ecf20Sopenharmony_ci offsetof(struct pt_regs, di), 5548c2ecf20Sopenharmony_ci offsetof(struct pt_regs, si), 5558c2ecf20Sopenharmony_ci offsetof(struct pt_regs, di), 5568c2ecf20Sopenharmony_ci -EDOM, 5578c2ecf20Sopenharmony_ci -EDOM, 5588c2ecf20Sopenharmony_ci -EDOM, 5598c2ecf20Sopenharmony_ci -EDOM, 5608c2ecf20Sopenharmony_ci }; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (!offs1 || !offs2) 5638c2ecf20Sopenharmony_ci return -EINVAL; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Operand is a register, use the generic function. */ 5668c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 5678c2ecf20Sopenharmony_ci *offs1 = insn_get_modrm_rm_off(insn, regs); 5688c2ecf20Sopenharmony_ci *offs2 = -EDOM; 5698c2ecf20Sopenharmony_ci return 0; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci *offs1 = regoff1[X86_MODRM_RM(insn->modrm.value)]; 5738c2ecf20Sopenharmony_ci *offs2 = regoff2[X86_MODRM_RM(insn->modrm.value)]; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * If ModRM.mod is 0 and ModRM.rm is 110b, then we use displacement- 5778c2ecf20Sopenharmony_ci * only addressing. This means that no registers are involved in 5788c2ecf20Sopenharmony_ci * computing the effective address. Thus, ensure that the first 5798c2ecf20Sopenharmony_ci * register offset is invalild. The second register offset is already 5808c2ecf20Sopenharmony_ci * invalid under the aforementioned conditions. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci if ((X86_MODRM_MOD(insn->modrm.value) == 0) && 5838c2ecf20Sopenharmony_ci (X86_MODRM_RM(insn->modrm.value) == 6)) 5848c2ecf20Sopenharmony_ci *offs1 = -EDOM; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci/** 5908c2ecf20Sopenharmony_ci * get_desc() - Obtain contents of a segment descriptor 5918c2ecf20Sopenharmony_ci * @out: Segment descriptor contents on success 5928c2ecf20Sopenharmony_ci * @sel: Segment selector 5938c2ecf20Sopenharmony_ci * 5948c2ecf20Sopenharmony_ci * Given a segment selector, obtain a pointer to the segment descriptor. 5958c2ecf20Sopenharmony_ci * Both global and local descriptor tables are supported. 5968c2ecf20Sopenharmony_ci * 5978c2ecf20Sopenharmony_ci * Returns: 5988c2ecf20Sopenharmony_ci * 5998c2ecf20Sopenharmony_ci * True on success, false on failure. 6008c2ecf20Sopenharmony_ci * 6018c2ecf20Sopenharmony_ci * NULL on error. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_cistatic bool get_desc(struct desc_struct *out, unsigned short sel) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct desc_ptr gdt_desc = {0, 0}; 6068c2ecf20Sopenharmony_ci unsigned long desc_base; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 6098c2ecf20Sopenharmony_ci if ((sel & SEGMENT_TI_MASK) == SEGMENT_LDT) { 6108c2ecf20Sopenharmony_ci bool success = false; 6118c2ecf20Sopenharmony_ci struct ldt_struct *ldt; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Bits [15:3] contain the index of the desired entry. */ 6148c2ecf20Sopenharmony_ci sel >>= 3; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci mutex_lock(¤t->active_mm->context.lock); 6178c2ecf20Sopenharmony_ci ldt = current->active_mm->context.ldt; 6188c2ecf20Sopenharmony_ci if (ldt && sel < ldt->nr_entries) { 6198c2ecf20Sopenharmony_ci *out = ldt->entries[sel]; 6208c2ecf20Sopenharmony_ci success = true; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci mutex_unlock(¤t->active_mm->context.lock); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return success; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci#endif 6288c2ecf20Sopenharmony_ci native_store_gdt(&gdt_desc); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * Segment descriptors have a size of 8 bytes. Thus, the index is 6328c2ecf20Sopenharmony_ci * multiplied by 8 to obtain the memory offset of the desired descriptor 6338c2ecf20Sopenharmony_ci * from the base of the GDT. As bits [15:3] of the segment selector 6348c2ecf20Sopenharmony_ci * contain the index, it can be regarded as multiplied by 8 already. 6358c2ecf20Sopenharmony_ci * All that remains is to clear bits [2:0]. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci desc_base = sel & ~(SEGMENT_RPL_MASK | SEGMENT_TI_MASK); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (desc_base > gdt_desc.size) 6408c2ecf20Sopenharmony_ci return false; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci *out = *(struct desc_struct *)(gdt_desc.address + desc_base); 6438c2ecf20Sopenharmony_ci return true; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci/** 6478c2ecf20Sopenharmony_ci * insn_get_seg_base() - Obtain base address of segment descriptor. 6488c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 6498c2ecf20Sopenharmony_ci * @seg_reg_idx: Index of the segment register pointing to seg descriptor 6508c2ecf20Sopenharmony_ci * 6518c2ecf20Sopenharmony_ci * Obtain the base address of the segment as indicated by the segment descriptor 6528c2ecf20Sopenharmony_ci * pointed by the segment selector. The segment selector is obtained from the 6538c2ecf20Sopenharmony_ci * input segment register index @seg_reg_idx. 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * Returns: 6568c2ecf20Sopenharmony_ci * 6578c2ecf20Sopenharmony_ci * In protected mode, base address of the segment. Zero in long mode, 6588c2ecf20Sopenharmony_ci * except when FS or GS are used. In virtual-8086 mode, the segment 6598c2ecf20Sopenharmony_ci * selector shifted 4 bits to the right. 6608c2ecf20Sopenharmony_ci * 6618c2ecf20Sopenharmony_ci * -1L in case of error. 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ciunsigned long insn_get_seg_base(struct pt_regs *regs, int seg_reg_idx) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct desc_struct desc; 6668c2ecf20Sopenharmony_ci short sel; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci sel = get_segment_selector(regs, seg_reg_idx); 6698c2ecf20Sopenharmony_ci if (sel < 0) 6708c2ecf20Sopenharmony_ci return -1L; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (v8086_mode(regs)) 6738c2ecf20Sopenharmony_ci /* 6748c2ecf20Sopenharmony_ci * Base is simply the segment selector shifted 4 6758c2ecf20Sopenharmony_ci * bits to the right. 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_ci return (unsigned long)(sel << 4); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (any_64bit_mode(regs)) { 6808c2ecf20Sopenharmony_ci /* 6818c2ecf20Sopenharmony_ci * Only FS or GS will have a base address, the rest of 6828c2ecf20Sopenharmony_ci * the segments' bases are forced to 0. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci unsigned long base; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (seg_reg_idx == INAT_SEG_REG_FS) { 6878c2ecf20Sopenharmony_ci rdmsrl(MSR_FS_BASE, base); 6888c2ecf20Sopenharmony_ci } else if (seg_reg_idx == INAT_SEG_REG_GS) { 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * swapgs was called at the kernel entry point. Thus, 6918c2ecf20Sopenharmony_ci * MSR_KERNEL_GS_BASE will have the user-space GS base. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if (user_mode(regs)) 6948c2ecf20Sopenharmony_ci rdmsrl(MSR_KERNEL_GS_BASE, base); 6958c2ecf20Sopenharmony_ci else 6968c2ecf20Sopenharmony_ci rdmsrl(MSR_GS_BASE, base); 6978c2ecf20Sopenharmony_ci } else { 6988c2ecf20Sopenharmony_ci base = 0; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci return base; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* In protected mode the segment selector cannot be null. */ 7048c2ecf20Sopenharmony_ci if (!sel) 7058c2ecf20Sopenharmony_ci return -1L; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (!get_desc(&desc, sel)) 7088c2ecf20Sopenharmony_ci return -1L; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return get_desc_base(&desc); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci/** 7148c2ecf20Sopenharmony_ci * get_seg_limit() - Obtain the limit of a segment descriptor 7158c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 7168c2ecf20Sopenharmony_ci * @seg_reg_idx: Index of the segment register pointing to seg descriptor 7178c2ecf20Sopenharmony_ci * 7188c2ecf20Sopenharmony_ci * Obtain the limit of the segment as indicated by the segment descriptor 7198c2ecf20Sopenharmony_ci * pointed by the segment selector. The segment selector is obtained from the 7208c2ecf20Sopenharmony_ci * input segment register index @seg_reg_idx. 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * Returns: 7238c2ecf20Sopenharmony_ci * 7248c2ecf20Sopenharmony_ci * In protected mode, the limit of the segment descriptor in bytes. 7258c2ecf20Sopenharmony_ci * In long mode and virtual-8086 mode, segment limits are not enforced. Thus, 7268c2ecf20Sopenharmony_ci * limit is returned as -1L to imply a limit-less segment. 7278c2ecf20Sopenharmony_ci * 7288c2ecf20Sopenharmony_ci * Zero is returned on error. 7298c2ecf20Sopenharmony_ci */ 7308c2ecf20Sopenharmony_cistatic unsigned long get_seg_limit(struct pt_regs *regs, int seg_reg_idx) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct desc_struct desc; 7338c2ecf20Sopenharmony_ci unsigned long limit; 7348c2ecf20Sopenharmony_ci short sel; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci sel = get_segment_selector(regs, seg_reg_idx); 7378c2ecf20Sopenharmony_ci if (sel < 0) 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (any_64bit_mode(regs) || v8086_mode(regs)) 7418c2ecf20Sopenharmony_ci return -1L; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (!sel) 7448c2ecf20Sopenharmony_ci return 0; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!get_desc(&desc, sel)) 7478c2ecf20Sopenharmony_ci return 0; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* 7508c2ecf20Sopenharmony_ci * If the granularity bit is set, the limit is given in multiples 7518c2ecf20Sopenharmony_ci * of 4096. This also means that the 12 least significant bits are 7528c2ecf20Sopenharmony_ci * not tested when checking the segment limits. In practice, 7538c2ecf20Sopenharmony_ci * this means that the segment ends in (limit << 12) + 0xfff. 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci limit = get_desc_limit(&desc); 7568c2ecf20Sopenharmony_ci if (desc.g) 7578c2ecf20Sopenharmony_ci limit = (limit << 12) + 0xfff; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return limit; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci/** 7638c2ecf20Sopenharmony_ci * insn_get_code_seg_params() - Obtain code segment parameters 7648c2ecf20Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 7658c2ecf20Sopenharmony_ci * 7668c2ecf20Sopenharmony_ci * Obtain address and operand sizes of the code segment. It is obtained from the 7678c2ecf20Sopenharmony_ci * selector contained in the CS register in regs. In protected mode, the default 7688c2ecf20Sopenharmony_ci * address is determined by inspecting the L and D bits of the segment 7698c2ecf20Sopenharmony_ci * descriptor. In virtual-8086 mode, the default is always two bytes for both 7708c2ecf20Sopenharmony_ci * address and operand sizes. 7718c2ecf20Sopenharmony_ci * 7728c2ecf20Sopenharmony_ci * Returns: 7738c2ecf20Sopenharmony_ci * 7748c2ecf20Sopenharmony_ci * An int containing ORed-in default parameters on success. 7758c2ecf20Sopenharmony_ci * 7768c2ecf20Sopenharmony_ci * -EINVAL on error. 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ciint insn_get_code_seg_params(struct pt_regs *regs) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct desc_struct desc; 7818c2ecf20Sopenharmony_ci short sel; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci if (v8086_mode(regs)) 7848c2ecf20Sopenharmony_ci /* Address and operand size are both 16-bit. */ 7858c2ecf20Sopenharmony_ci return INSN_CODE_SEG_PARAMS(2, 2); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci sel = get_segment_selector(regs, INAT_SEG_REG_CS); 7888c2ecf20Sopenharmony_ci if (sel < 0) 7898c2ecf20Sopenharmony_ci return sel; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (!get_desc(&desc, sel)) 7928c2ecf20Sopenharmony_ci return -EINVAL; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * The most significant byte of the Type field of the segment descriptor 7968c2ecf20Sopenharmony_ci * determines whether a segment contains data or code. If this is a data 7978c2ecf20Sopenharmony_ci * segment, return error. 7988c2ecf20Sopenharmony_ci */ 7998c2ecf20Sopenharmony_ci if (!(desc.type & BIT(3))) 8008c2ecf20Sopenharmony_ci return -EINVAL; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci switch ((desc.l << 1) | desc.d) { 8038c2ecf20Sopenharmony_ci case 0: /* 8048c2ecf20Sopenharmony_ci * Legacy mode. CS.L=0, CS.D=0. Address and operand size are 8058c2ecf20Sopenharmony_ci * both 16-bit. 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ci return INSN_CODE_SEG_PARAMS(2, 2); 8088c2ecf20Sopenharmony_ci case 1: /* 8098c2ecf20Sopenharmony_ci * Legacy mode. CS.L=0, CS.D=1. Address and operand size are 8108c2ecf20Sopenharmony_ci * both 32-bit. 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_ci return INSN_CODE_SEG_PARAMS(4, 4); 8138c2ecf20Sopenharmony_ci case 2: /* 8148c2ecf20Sopenharmony_ci * IA-32e 64-bit mode. CS.L=1, CS.D=0. Address size is 64-bit; 8158c2ecf20Sopenharmony_ci * operand size is 32-bit. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_ci return INSN_CODE_SEG_PARAMS(4, 8); 8188c2ecf20Sopenharmony_ci case 3: /* Invalid setting. CS.L=1, CS.D=1 */ 8198c2ecf20Sopenharmony_ci fallthrough; 8208c2ecf20Sopenharmony_ci default: 8218c2ecf20Sopenharmony_ci return -EINVAL; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci/** 8268c2ecf20Sopenharmony_ci * insn_get_modrm_rm_off() - Obtain register in r/m part of the ModRM byte 8278c2ecf20Sopenharmony_ci * @insn: Instruction containing the ModRM byte 8288c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 8298c2ecf20Sopenharmony_ci * 8308c2ecf20Sopenharmony_ci * Returns: 8318c2ecf20Sopenharmony_ci * 8328c2ecf20Sopenharmony_ci * The register indicated by the r/m part of the ModRM byte. The 8338c2ecf20Sopenharmony_ci * register is obtained as an offset from the base of pt_regs. In specific 8348c2ecf20Sopenharmony_ci * cases, the returned value can be -EDOM to indicate that the particular value 8358c2ecf20Sopenharmony_ci * of ModRM does not refer to a register and shall be ignored. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_ciint insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci return get_reg_offset(insn, regs, REG_TYPE_RM); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci/** 8438c2ecf20Sopenharmony_ci * insn_get_modrm_reg_off() - Obtain register in reg part of the ModRM byte 8448c2ecf20Sopenharmony_ci * @insn: Instruction containing the ModRM byte 8458c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 8468c2ecf20Sopenharmony_ci * 8478c2ecf20Sopenharmony_ci * Returns: 8488c2ecf20Sopenharmony_ci * 8498c2ecf20Sopenharmony_ci * The register indicated by the reg part of the ModRM byte. The 8508c2ecf20Sopenharmony_ci * register is obtained as an offset from the base of pt_regs. 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_ciint insn_get_modrm_reg_off(struct insn *insn, struct pt_regs *regs) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci return get_reg_offset(insn, regs, REG_TYPE_REG); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci/** 8588c2ecf20Sopenharmony_ci * get_seg_base_limit() - obtain base address and limit of a segment 8598c2ecf20Sopenharmony_ci * @insn: Instruction. Must be valid. 8608c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 8618c2ecf20Sopenharmony_ci * @regoff: Operand offset, in pt_regs, used to resolve segment descriptor 8628c2ecf20Sopenharmony_ci * @base: Obtained segment base 8638c2ecf20Sopenharmony_ci * @limit: Obtained segment limit 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * Obtain the base address and limit of the segment associated with the operand 8668c2ecf20Sopenharmony_ci * @regoff and, if any or allowed, override prefixes in @insn. This function is 8678c2ecf20Sopenharmony_ci * different from insn_get_seg_base() as the latter does not resolve the segment 8688c2ecf20Sopenharmony_ci * associated with the instruction operand. If a limit is not needed (e.g., 8698c2ecf20Sopenharmony_ci * when running in long mode), @limit can be NULL. 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * Returns: 8728c2ecf20Sopenharmony_ci * 8738c2ecf20Sopenharmony_ci * 0 on success. @base and @limit will contain the base address and of the 8748c2ecf20Sopenharmony_ci * resolved segment, respectively. 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci * -EINVAL on error. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_cistatic int get_seg_base_limit(struct insn *insn, struct pt_regs *regs, 8798c2ecf20Sopenharmony_ci int regoff, unsigned long *base, 8808c2ecf20Sopenharmony_ci unsigned long *limit) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci int seg_reg_idx; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (!base) 8858c2ecf20Sopenharmony_ci return -EINVAL; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci seg_reg_idx = resolve_seg_reg(insn, regs, regoff); 8888c2ecf20Sopenharmony_ci if (seg_reg_idx < 0) 8898c2ecf20Sopenharmony_ci return seg_reg_idx; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci *base = insn_get_seg_base(regs, seg_reg_idx); 8928c2ecf20Sopenharmony_ci if (*base == -1L) 8938c2ecf20Sopenharmony_ci return -EINVAL; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (!limit) 8968c2ecf20Sopenharmony_ci return 0; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci *limit = get_seg_limit(regs, seg_reg_idx); 8998c2ecf20Sopenharmony_ci if (!(*limit)) 9008c2ecf20Sopenharmony_ci return -EINVAL; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return 0; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci/** 9068c2ecf20Sopenharmony_ci * get_eff_addr_reg() - Obtain effective address from register operand 9078c2ecf20Sopenharmony_ci * @insn: Instruction. Must be valid. 9088c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 9098c2ecf20Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, with the effective address 9108c2ecf20Sopenharmony_ci * @eff_addr: Obtained effective address 9118c2ecf20Sopenharmony_ci * 9128c2ecf20Sopenharmony_ci * Obtain the effective address stored in the register operand as indicated by 9138c2ecf20Sopenharmony_ci * the ModRM byte. This function is to be used only with register addressing 9148c2ecf20Sopenharmony_ci * (i.e., ModRM.mod is 3). The effective address is saved in @eff_addr. The 9158c2ecf20Sopenharmony_ci * register operand, as an offset from the base of pt_regs, is saved in @regoff; 9168c2ecf20Sopenharmony_ci * such offset can then be used to resolve the segment associated with the 9178c2ecf20Sopenharmony_ci * operand. This function can be used with any of the supported address sizes 9188c2ecf20Sopenharmony_ci * in x86. 9198c2ecf20Sopenharmony_ci * 9208c2ecf20Sopenharmony_ci * Returns: 9218c2ecf20Sopenharmony_ci * 9228c2ecf20Sopenharmony_ci * 0 on success. @eff_addr will have the effective address stored in the 9238c2ecf20Sopenharmony_ci * operand indicated by ModRM. @regoff will have such operand as an offset from 9248c2ecf20Sopenharmony_ci * the base of pt_regs. 9258c2ecf20Sopenharmony_ci * 9268c2ecf20Sopenharmony_ci * -EINVAL on error. 9278c2ecf20Sopenharmony_ci */ 9288c2ecf20Sopenharmony_cistatic int get_eff_addr_reg(struct insn *insn, struct pt_regs *regs, 9298c2ecf20Sopenharmony_ci int *regoff, long *eff_addr) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci int ret; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci ret = insn_get_modrm(insn); 9348c2ecf20Sopenharmony_ci if (ret) 9358c2ecf20Sopenharmony_ci return ret; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) != 3) 9388c2ecf20Sopenharmony_ci return -EINVAL; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci *regoff = get_reg_offset(insn, regs, REG_TYPE_RM); 9418c2ecf20Sopenharmony_ci if (*regoff < 0) 9428c2ecf20Sopenharmony_ci return -EINVAL; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* Ignore bytes that are outside the address size. */ 9458c2ecf20Sopenharmony_ci if (insn->addr_bytes == 2) 9468c2ecf20Sopenharmony_ci *eff_addr = regs_get_register(regs, *regoff) & 0xffff; 9478c2ecf20Sopenharmony_ci else if (insn->addr_bytes == 4) 9488c2ecf20Sopenharmony_ci *eff_addr = regs_get_register(regs, *regoff) & 0xffffffff; 9498c2ecf20Sopenharmony_ci else /* 64-bit address */ 9508c2ecf20Sopenharmony_ci *eff_addr = regs_get_register(regs, *regoff); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci/** 9568c2ecf20Sopenharmony_ci * get_eff_addr_modrm() - Obtain referenced effective address via ModRM 9578c2ecf20Sopenharmony_ci * @insn: Instruction. Must be valid. 9588c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 9598c2ecf20Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, associated with segment 9608c2ecf20Sopenharmony_ci * @eff_addr: Obtained effective address 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * Obtain the effective address referenced by the ModRM byte of @insn. After 9638c2ecf20Sopenharmony_ci * identifying the registers involved in the register-indirect memory reference, 9648c2ecf20Sopenharmony_ci * its value is obtained from the operands in @regs. The computed address is 9658c2ecf20Sopenharmony_ci * stored @eff_addr. Also, the register operand that indicates the associated 9668c2ecf20Sopenharmony_ci * segment is stored in @regoff, this parameter can later be used to determine 9678c2ecf20Sopenharmony_ci * such segment. 9688c2ecf20Sopenharmony_ci * 9698c2ecf20Sopenharmony_ci * Returns: 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * 0 on success. @eff_addr will have the referenced effective address. @regoff 9728c2ecf20Sopenharmony_ci * will have a register, as an offset from the base of pt_regs, that can be used 9738c2ecf20Sopenharmony_ci * to resolve the associated segment. 9748c2ecf20Sopenharmony_ci * 9758c2ecf20Sopenharmony_ci * -EINVAL on error. 9768c2ecf20Sopenharmony_ci */ 9778c2ecf20Sopenharmony_cistatic int get_eff_addr_modrm(struct insn *insn, struct pt_regs *regs, 9788c2ecf20Sopenharmony_ci int *regoff, long *eff_addr) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci long tmp; 9818c2ecf20Sopenharmony_ci int ret; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (insn->addr_bytes != 8 && insn->addr_bytes != 4) 9848c2ecf20Sopenharmony_ci return -EINVAL; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci ret = insn_get_modrm(insn); 9878c2ecf20Sopenharmony_ci if (ret) 9888c2ecf20Sopenharmony_ci return ret; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) > 2) 9918c2ecf20Sopenharmony_ci return -EINVAL; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci *regoff = get_reg_offset(insn, regs, REG_TYPE_RM); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci /* 9968c2ecf20Sopenharmony_ci * -EDOM means that we must ignore the address_offset. In such a case, 9978c2ecf20Sopenharmony_ci * in 64-bit mode the effective address relative to the rIP of the 9988c2ecf20Sopenharmony_ci * following instruction. 9998c2ecf20Sopenharmony_ci */ 10008c2ecf20Sopenharmony_ci if (*regoff == -EDOM) { 10018c2ecf20Sopenharmony_ci if (any_64bit_mode(regs)) 10028c2ecf20Sopenharmony_ci tmp = regs->ip + insn->length; 10038c2ecf20Sopenharmony_ci else 10048c2ecf20Sopenharmony_ci tmp = 0; 10058c2ecf20Sopenharmony_ci } else if (*regoff < 0) { 10068c2ecf20Sopenharmony_ci return -EINVAL; 10078c2ecf20Sopenharmony_ci } else { 10088c2ecf20Sopenharmony_ci tmp = regs_get_register(regs, *regoff); 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (insn->addr_bytes == 4) { 10128c2ecf20Sopenharmony_ci int addr32 = (int)(tmp & 0xffffffff) + insn->displacement.value; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci *eff_addr = addr32 & 0xffffffff; 10158c2ecf20Sopenharmony_ci } else { 10168c2ecf20Sopenharmony_ci *eff_addr = tmp + insn->displacement.value; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci return 0; 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci/** 10238c2ecf20Sopenharmony_ci * get_eff_addr_modrm_16() - Obtain referenced effective address via ModRM 10248c2ecf20Sopenharmony_ci * @insn: Instruction. Must be valid. 10258c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 10268c2ecf20Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, associated with segment 10278c2ecf20Sopenharmony_ci * @eff_addr: Obtained effective address 10288c2ecf20Sopenharmony_ci * 10298c2ecf20Sopenharmony_ci * Obtain the 16-bit effective address referenced by the ModRM byte of @insn. 10308c2ecf20Sopenharmony_ci * After identifying the registers involved in the register-indirect memory 10318c2ecf20Sopenharmony_ci * reference, its value is obtained from the operands in @regs. The computed 10328c2ecf20Sopenharmony_ci * address is stored @eff_addr. Also, the register operand that indicates 10338c2ecf20Sopenharmony_ci * the associated segment is stored in @regoff, this parameter can later be used 10348c2ecf20Sopenharmony_ci * to determine such segment. 10358c2ecf20Sopenharmony_ci * 10368c2ecf20Sopenharmony_ci * Returns: 10378c2ecf20Sopenharmony_ci * 10388c2ecf20Sopenharmony_ci * 0 on success. @eff_addr will have the referenced effective address. @regoff 10398c2ecf20Sopenharmony_ci * will have a register, as an offset from the base of pt_regs, that can be used 10408c2ecf20Sopenharmony_ci * to resolve the associated segment. 10418c2ecf20Sopenharmony_ci * 10428c2ecf20Sopenharmony_ci * -EINVAL on error. 10438c2ecf20Sopenharmony_ci */ 10448c2ecf20Sopenharmony_cistatic int get_eff_addr_modrm_16(struct insn *insn, struct pt_regs *regs, 10458c2ecf20Sopenharmony_ci int *regoff, short *eff_addr) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci int addr_offset1, addr_offset2, ret; 10488c2ecf20Sopenharmony_ci short addr1 = 0, addr2 = 0, displacement; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (insn->addr_bytes != 2) 10518c2ecf20Sopenharmony_ci return -EINVAL; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci insn_get_modrm(insn); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci if (!insn->modrm.nbytes) 10568c2ecf20Sopenharmony_ci return -EINVAL; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) > 2) 10598c2ecf20Sopenharmony_ci return -EINVAL; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci ret = get_reg_offset_16(insn, regs, &addr_offset1, &addr_offset2); 10628c2ecf20Sopenharmony_ci if (ret < 0) 10638c2ecf20Sopenharmony_ci return -EINVAL; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* 10668c2ecf20Sopenharmony_ci * Don't fail on invalid offset values. They might be invalid because 10678c2ecf20Sopenharmony_ci * they cannot be used for this particular value of ModRM. Instead, use 10688c2ecf20Sopenharmony_ci * them in the computation only if they contain a valid value. 10698c2ecf20Sopenharmony_ci */ 10708c2ecf20Sopenharmony_ci if (addr_offset1 != -EDOM) 10718c2ecf20Sopenharmony_ci addr1 = regs_get_register(regs, addr_offset1) & 0xffff; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci if (addr_offset2 != -EDOM) 10748c2ecf20Sopenharmony_ci addr2 = regs_get_register(regs, addr_offset2) & 0xffff; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci displacement = insn->displacement.value & 0xffff; 10778c2ecf20Sopenharmony_ci *eff_addr = addr1 + addr2 + displacement; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* 10808c2ecf20Sopenharmony_ci * The first operand register could indicate to use of either SS or DS 10818c2ecf20Sopenharmony_ci * registers to obtain the segment selector. The second operand 10828c2ecf20Sopenharmony_ci * register can only indicate the use of DS. Thus, the first operand 10838c2ecf20Sopenharmony_ci * will be used to obtain the segment selector. 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci *regoff = addr_offset1; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci return 0; 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci/** 10918c2ecf20Sopenharmony_ci * get_eff_addr_sib() - Obtain referenced effective address via SIB 10928c2ecf20Sopenharmony_ci * @insn: Instruction. Must be valid. 10938c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 10948c2ecf20Sopenharmony_ci * @regoff: Obtained operand offset, in pt_regs, associated with segment 10958c2ecf20Sopenharmony_ci * @eff_addr: Obtained effective address 10968c2ecf20Sopenharmony_ci * 10978c2ecf20Sopenharmony_ci * Obtain the effective address referenced by the SIB byte of @insn. After 10988c2ecf20Sopenharmony_ci * identifying the registers involved in the indexed, register-indirect memory 10998c2ecf20Sopenharmony_ci * reference, its value is obtained from the operands in @regs. The computed 11008c2ecf20Sopenharmony_ci * address is stored @eff_addr. Also, the register operand that indicates the 11018c2ecf20Sopenharmony_ci * associated segment is stored in @regoff, this parameter can later be used to 11028c2ecf20Sopenharmony_ci * determine such segment. 11038c2ecf20Sopenharmony_ci * 11048c2ecf20Sopenharmony_ci * Returns: 11058c2ecf20Sopenharmony_ci * 11068c2ecf20Sopenharmony_ci * 0 on success. @eff_addr will have the referenced effective address. 11078c2ecf20Sopenharmony_ci * @base_offset will have a register, as an offset from the base of pt_regs, 11088c2ecf20Sopenharmony_ci * that can be used to resolve the associated segment. 11098c2ecf20Sopenharmony_ci * 11108c2ecf20Sopenharmony_ci * Negative value on error. 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_cistatic int get_eff_addr_sib(struct insn *insn, struct pt_regs *regs, 11138c2ecf20Sopenharmony_ci int *base_offset, long *eff_addr) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci long base, indx; 11168c2ecf20Sopenharmony_ci int indx_offset; 11178c2ecf20Sopenharmony_ci int ret; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (insn->addr_bytes != 8 && insn->addr_bytes != 4) 11208c2ecf20Sopenharmony_ci return -EINVAL; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci ret = insn_get_modrm(insn); 11238c2ecf20Sopenharmony_ci if (ret) 11248c2ecf20Sopenharmony_ci return ret; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci if (!insn->modrm.nbytes) 11278c2ecf20Sopenharmony_ci return -EINVAL; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) > 2) 11308c2ecf20Sopenharmony_ci return -EINVAL; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci ret = insn_get_sib(insn); 11338c2ecf20Sopenharmony_ci if (ret) 11348c2ecf20Sopenharmony_ci return ret; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (!insn->sib.nbytes) 11378c2ecf20Sopenharmony_ci return -EINVAL; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci *base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE); 11408c2ecf20Sopenharmony_ci indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* 11438c2ecf20Sopenharmony_ci * Negative values in the base and index offset means an error when 11448c2ecf20Sopenharmony_ci * decoding the SIB byte. Except -EDOM, which means that the registers 11458c2ecf20Sopenharmony_ci * should not be used in the address computation. 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ci if (*base_offset == -EDOM) 11488c2ecf20Sopenharmony_ci base = 0; 11498c2ecf20Sopenharmony_ci else if (*base_offset < 0) 11508c2ecf20Sopenharmony_ci return -EINVAL; 11518c2ecf20Sopenharmony_ci else 11528c2ecf20Sopenharmony_ci base = regs_get_register(regs, *base_offset); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (indx_offset == -EDOM) 11558c2ecf20Sopenharmony_ci indx = 0; 11568c2ecf20Sopenharmony_ci else if (indx_offset < 0) 11578c2ecf20Sopenharmony_ci return -EINVAL; 11588c2ecf20Sopenharmony_ci else 11598c2ecf20Sopenharmony_ci indx = regs_get_register(regs, indx_offset); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci if (insn->addr_bytes == 4) { 11628c2ecf20Sopenharmony_ci int addr32, base32, idx32; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci base32 = base & 0xffffffff; 11658c2ecf20Sopenharmony_ci idx32 = indx & 0xffffffff; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci addr32 = base32 + idx32 * (1 << X86_SIB_SCALE(insn->sib.value)); 11688c2ecf20Sopenharmony_ci addr32 += insn->displacement.value; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci *eff_addr = addr32 & 0xffffffff; 11718c2ecf20Sopenharmony_ci } else { 11728c2ecf20Sopenharmony_ci *eff_addr = base + indx * (1 << X86_SIB_SCALE(insn->sib.value)); 11738c2ecf20Sopenharmony_ci *eff_addr += insn->displacement.value; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci return 0; 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci/** 11808c2ecf20Sopenharmony_ci * get_addr_ref_16() - Obtain the 16-bit address referred by instruction 11818c2ecf20Sopenharmony_ci * @insn: Instruction containing ModRM byte and displacement 11828c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 11838c2ecf20Sopenharmony_ci * 11848c2ecf20Sopenharmony_ci * This function is to be used with 16-bit address encodings. Obtain the memory 11858c2ecf20Sopenharmony_ci * address referred by the instruction's ModRM and displacement bytes. Also, the 11868c2ecf20Sopenharmony_ci * segment used as base is determined by either any segment override prefixes in 11878c2ecf20Sopenharmony_ci * @insn or the default segment of the registers involved in the address 11888c2ecf20Sopenharmony_ci * computation. In protected mode, segment limits are enforced. 11898c2ecf20Sopenharmony_ci * 11908c2ecf20Sopenharmony_ci * Returns: 11918c2ecf20Sopenharmony_ci * 11928c2ecf20Sopenharmony_ci * Linear address referenced by the instruction operands on success. 11938c2ecf20Sopenharmony_ci * 11948c2ecf20Sopenharmony_ci * -1L on error. 11958c2ecf20Sopenharmony_ci */ 11968c2ecf20Sopenharmony_cistatic void __user *get_addr_ref_16(struct insn *insn, struct pt_regs *regs) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci unsigned long linear_addr = -1L, seg_base, seg_limit; 11998c2ecf20Sopenharmony_ci int ret, regoff; 12008c2ecf20Sopenharmony_ci short eff_addr; 12018c2ecf20Sopenharmony_ci long tmp; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci if (insn_get_displacement(insn)) 12048c2ecf20Sopenharmony_ci goto out; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (insn->addr_bytes != 2) 12078c2ecf20Sopenharmony_ci goto out; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 12108c2ecf20Sopenharmony_ci ret = get_eff_addr_reg(insn, regs, ®off, &tmp); 12118c2ecf20Sopenharmony_ci if (ret) 12128c2ecf20Sopenharmony_ci goto out; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci eff_addr = tmp; 12158c2ecf20Sopenharmony_ci } else { 12168c2ecf20Sopenharmony_ci ret = get_eff_addr_modrm_16(insn, regs, ®off, &eff_addr); 12178c2ecf20Sopenharmony_ci if (ret) 12188c2ecf20Sopenharmony_ci goto out; 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit); 12228c2ecf20Sopenharmony_ci if (ret) 12238c2ecf20Sopenharmony_ci goto out; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci /* 12268c2ecf20Sopenharmony_ci * Before computing the linear address, make sure the effective address 12278c2ecf20Sopenharmony_ci * is within the limits of the segment. In virtual-8086 mode, segment 12288c2ecf20Sopenharmony_ci * limits are not enforced. In such a case, the segment limit is -1L to 12298c2ecf20Sopenharmony_ci * reflect this fact. 12308c2ecf20Sopenharmony_ci */ 12318c2ecf20Sopenharmony_ci if ((unsigned long)(eff_addr & 0xffff) > seg_limit) 12328c2ecf20Sopenharmony_ci goto out; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci linear_addr = (unsigned long)(eff_addr & 0xffff) + seg_base; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci /* Limit linear address to 20 bits */ 12378c2ecf20Sopenharmony_ci if (v8086_mode(regs)) 12388c2ecf20Sopenharmony_ci linear_addr &= 0xfffff; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ciout: 12418c2ecf20Sopenharmony_ci return (void __user *)linear_addr; 12428c2ecf20Sopenharmony_ci} 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci/** 12458c2ecf20Sopenharmony_ci * get_addr_ref_32() - Obtain a 32-bit linear address 12468c2ecf20Sopenharmony_ci * @insn: Instruction with ModRM, SIB bytes and displacement 12478c2ecf20Sopenharmony_ci * @regs: Register values as seen when entering kernel mode 12488c2ecf20Sopenharmony_ci * 12498c2ecf20Sopenharmony_ci * This function is to be used with 32-bit address encodings to obtain the 12508c2ecf20Sopenharmony_ci * linear memory address referred by the instruction's ModRM, SIB, 12518c2ecf20Sopenharmony_ci * displacement bytes and segment base address, as applicable. If in protected 12528c2ecf20Sopenharmony_ci * mode, segment limits are enforced. 12538c2ecf20Sopenharmony_ci * 12548c2ecf20Sopenharmony_ci * Returns: 12558c2ecf20Sopenharmony_ci * 12568c2ecf20Sopenharmony_ci * Linear address referenced by instruction and registers on success. 12578c2ecf20Sopenharmony_ci * 12588c2ecf20Sopenharmony_ci * -1L on error. 12598c2ecf20Sopenharmony_ci */ 12608c2ecf20Sopenharmony_cistatic void __user *get_addr_ref_32(struct insn *insn, struct pt_regs *regs) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci unsigned long linear_addr = -1L, seg_base, seg_limit; 12638c2ecf20Sopenharmony_ci int eff_addr, regoff; 12648c2ecf20Sopenharmony_ci long tmp; 12658c2ecf20Sopenharmony_ci int ret; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (insn->addr_bytes != 4) 12688c2ecf20Sopenharmony_ci goto out; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 12718c2ecf20Sopenharmony_ci ret = get_eff_addr_reg(insn, regs, ®off, &tmp); 12728c2ecf20Sopenharmony_ci if (ret) 12738c2ecf20Sopenharmony_ci goto out; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci eff_addr = tmp; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci } else { 12788c2ecf20Sopenharmony_ci if (insn->sib.nbytes) { 12798c2ecf20Sopenharmony_ci ret = get_eff_addr_sib(insn, regs, ®off, &tmp); 12808c2ecf20Sopenharmony_ci if (ret) 12818c2ecf20Sopenharmony_ci goto out; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci eff_addr = tmp; 12848c2ecf20Sopenharmony_ci } else { 12858c2ecf20Sopenharmony_ci ret = get_eff_addr_modrm(insn, regs, ®off, &tmp); 12868c2ecf20Sopenharmony_ci if (ret) 12878c2ecf20Sopenharmony_ci goto out; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci eff_addr = tmp; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci ret = get_seg_base_limit(insn, regs, regoff, &seg_base, &seg_limit); 12948c2ecf20Sopenharmony_ci if (ret) 12958c2ecf20Sopenharmony_ci goto out; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* 12988c2ecf20Sopenharmony_ci * In protected mode, before computing the linear address, make sure 12998c2ecf20Sopenharmony_ci * the effective address is within the limits of the segment. 13008c2ecf20Sopenharmony_ci * 32-bit addresses can be used in long and virtual-8086 modes if an 13018c2ecf20Sopenharmony_ci * address override prefix is used. In such cases, segment limits are 13028c2ecf20Sopenharmony_ci * not enforced. When in virtual-8086 mode, the segment limit is -1L 13038c2ecf20Sopenharmony_ci * to reflect this situation. 13048c2ecf20Sopenharmony_ci * 13058c2ecf20Sopenharmony_ci * After computed, the effective address is treated as an unsigned 13068c2ecf20Sopenharmony_ci * quantity. 13078c2ecf20Sopenharmony_ci */ 13088c2ecf20Sopenharmony_ci if (!any_64bit_mode(regs) && ((unsigned int)eff_addr > seg_limit)) 13098c2ecf20Sopenharmony_ci goto out; 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* 13128c2ecf20Sopenharmony_ci * Even though 32-bit address encodings are allowed in virtual-8086 13138c2ecf20Sopenharmony_ci * mode, the address range is still limited to [0x-0xffff]. 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_ci if (v8086_mode(regs) && (eff_addr & ~0xffff)) 13168c2ecf20Sopenharmony_ci goto out; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci /* 13198c2ecf20Sopenharmony_ci * Data type long could be 64 bits in size. Ensure that our 32-bit 13208c2ecf20Sopenharmony_ci * effective address is not sign-extended when computing the linear 13218c2ecf20Sopenharmony_ci * address. 13228c2ecf20Sopenharmony_ci */ 13238c2ecf20Sopenharmony_ci linear_addr = (unsigned long)(eff_addr & 0xffffffff) + seg_base; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci /* Limit linear address to 20 bits */ 13268c2ecf20Sopenharmony_ci if (v8086_mode(regs)) 13278c2ecf20Sopenharmony_ci linear_addr &= 0xfffff; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ciout: 13308c2ecf20Sopenharmony_ci return (void __user *)linear_addr; 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci/** 13348c2ecf20Sopenharmony_ci * get_addr_ref_64() - Obtain a 64-bit linear address 13358c2ecf20Sopenharmony_ci * @insn: Instruction struct with ModRM and SIB bytes and displacement 13368c2ecf20Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 13378c2ecf20Sopenharmony_ci * 13388c2ecf20Sopenharmony_ci * This function is to be used with 64-bit address encodings to obtain the 13398c2ecf20Sopenharmony_ci * linear memory address referred by the instruction's ModRM, SIB, 13408c2ecf20Sopenharmony_ci * displacement bytes and segment base address, as applicable. 13418c2ecf20Sopenharmony_ci * 13428c2ecf20Sopenharmony_ci * Returns: 13438c2ecf20Sopenharmony_ci * 13448c2ecf20Sopenharmony_ci * Linear address referenced by instruction and registers on success. 13458c2ecf20Sopenharmony_ci * 13468c2ecf20Sopenharmony_ci * -1L on error. 13478c2ecf20Sopenharmony_ci */ 13488c2ecf20Sopenharmony_ci#ifndef CONFIG_X86_64 13498c2ecf20Sopenharmony_cistatic void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) 13508c2ecf20Sopenharmony_ci{ 13518c2ecf20Sopenharmony_ci return (void __user *)-1L; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci#else 13548c2ecf20Sopenharmony_cistatic void __user *get_addr_ref_64(struct insn *insn, struct pt_regs *regs) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci unsigned long linear_addr = -1L, seg_base; 13578c2ecf20Sopenharmony_ci int regoff, ret; 13588c2ecf20Sopenharmony_ci long eff_addr; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (insn->addr_bytes != 8) 13618c2ecf20Sopenharmony_ci goto out; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(insn->modrm.value) == 3) { 13648c2ecf20Sopenharmony_ci ret = get_eff_addr_reg(insn, regs, ®off, &eff_addr); 13658c2ecf20Sopenharmony_ci if (ret) 13668c2ecf20Sopenharmony_ci goto out; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci } else { 13698c2ecf20Sopenharmony_ci if (insn->sib.nbytes) { 13708c2ecf20Sopenharmony_ci ret = get_eff_addr_sib(insn, regs, ®off, &eff_addr); 13718c2ecf20Sopenharmony_ci if (ret) 13728c2ecf20Sopenharmony_ci goto out; 13738c2ecf20Sopenharmony_ci } else { 13748c2ecf20Sopenharmony_ci ret = get_eff_addr_modrm(insn, regs, ®off, &eff_addr); 13758c2ecf20Sopenharmony_ci if (ret) 13768c2ecf20Sopenharmony_ci goto out; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci ret = get_seg_base_limit(insn, regs, regoff, &seg_base, NULL); 13828c2ecf20Sopenharmony_ci if (ret) 13838c2ecf20Sopenharmony_ci goto out; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci linear_addr = (unsigned long)eff_addr + seg_base; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ciout: 13888c2ecf20Sopenharmony_ci return (void __user *)linear_addr; 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_64 */ 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci/** 13938c2ecf20Sopenharmony_ci * insn_get_addr_ref() - Obtain the linear address referred by instruction 13948c2ecf20Sopenharmony_ci * @insn: Instruction structure containing ModRM byte and displacement 13958c2ecf20Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 13968c2ecf20Sopenharmony_ci * 13978c2ecf20Sopenharmony_ci * Obtain the linear address referred by the instruction's ModRM, SIB and 13988c2ecf20Sopenharmony_ci * displacement bytes, and segment base, as applicable. In protected mode, 13998c2ecf20Sopenharmony_ci * segment limits are enforced. 14008c2ecf20Sopenharmony_ci * 14018c2ecf20Sopenharmony_ci * Returns: 14028c2ecf20Sopenharmony_ci * 14038c2ecf20Sopenharmony_ci * Linear address referenced by instruction and registers on success. 14048c2ecf20Sopenharmony_ci * 14058c2ecf20Sopenharmony_ci * -1L on error. 14068c2ecf20Sopenharmony_ci */ 14078c2ecf20Sopenharmony_civoid __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci if (!insn || !regs) 14108c2ecf20Sopenharmony_ci return (void __user *)-1L; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci switch (insn->addr_bytes) { 14138c2ecf20Sopenharmony_ci case 2: 14148c2ecf20Sopenharmony_ci return get_addr_ref_16(insn, regs); 14158c2ecf20Sopenharmony_ci case 4: 14168c2ecf20Sopenharmony_ci return get_addr_ref_32(insn, regs); 14178c2ecf20Sopenharmony_ci case 8: 14188c2ecf20Sopenharmony_ci return get_addr_ref_64(insn, regs); 14198c2ecf20Sopenharmony_ci default: 14208c2ecf20Sopenharmony_ci return (void __user *)-1L; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ciunsigned long insn_get_effective_ip(struct pt_regs *regs) 14258c2ecf20Sopenharmony_ci{ 14268c2ecf20Sopenharmony_ci unsigned long seg_base = 0; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* 14298c2ecf20Sopenharmony_ci * If not in user-space long mode, a custom code segment could be in 14308c2ecf20Sopenharmony_ci * use. This is true in protected mode (if the process defined a local 14318c2ecf20Sopenharmony_ci * descriptor table), or virtual-8086 mode. In most of the cases 14328c2ecf20Sopenharmony_ci * seg_base will be zero as in USER_CS. 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_ci if (!user_64bit_mode(regs)) { 14358c2ecf20Sopenharmony_ci seg_base = insn_get_seg_base(regs, INAT_SEG_REG_CS); 14368c2ecf20Sopenharmony_ci if (seg_base == -1L) 14378c2ecf20Sopenharmony_ci return 0; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci return seg_base + regs->ip; 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci/** 14448c2ecf20Sopenharmony_ci * insn_fetch_from_user() - Copy instruction bytes from user-space memory 14458c2ecf20Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 14468c2ecf20Sopenharmony_ci * @buf: Array to store the fetched instruction 14478c2ecf20Sopenharmony_ci * 14488c2ecf20Sopenharmony_ci * Gets the linear address of the instruction and copies the instruction bytes 14498c2ecf20Sopenharmony_ci * to the buf. 14508c2ecf20Sopenharmony_ci * 14518c2ecf20Sopenharmony_ci * Returns: 14528c2ecf20Sopenharmony_ci * 14538c2ecf20Sopenharmony_ci * Number of instruction bytes copied. 14548c2ecf20Sopenharmony_ci * 14558c2ecf20Sopenharmony_ci * 0 if nothing was copied. 14568c2ecf20Sopenharmony_ci */ 14578c2ecf20Sopenharmony_ciint insn_fetch_from_user(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci unsigned long ip; 14608c2ecf20Sopenharmony_ci int not_copied; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci ip = insn_get_effective_ip(regs); 14638c2ecf20Sopenharmony_ci if (!ip) 14648c2ecf20Sopenharmony_ci return 0; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci not_copied = copy_from_user(buf, (void __user *)ip, MAX_INSN_SIZE); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci return MAX_INSN_SIZE - not_copied; 14698c2ecf20Sopenharmony_ci} 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci/** 14728c2ecf20Sopenharmony_ci * insn_fetch_from_user_inatomic() - Copy instruction bytes from user-space memory 14738c2ecf20Sopenharmony_ci * while in atomic code 14748c2ecf20Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 14758c2ecf20Sopenharmony_ci * @buf: Array to store the fetched instruction 14768c2ecf20Sopenharmony_ci * 14778c2ecf20Sopenharmony_ci * Gets the linear address of the instruction and copies the instruction bytes 14788c2ecf20Sopenharmony_ci * to the buf. This function must be used in atomic context. 14798c2ecf20Sopenharmony_ci * 14808c2ecf20Sopenharmony_ci * Returns: 14818c2ecf20Sopenharmony_ci * 14828c2ecf20Sopenharmony_ci * Number of instruction bytes copied. 14838c2ecf20Sopenharmony_ci * 14848c2ecf20Sopenharmony_ci * 0 if nothing was copied. 14858c2ecf20Sopenharmony_ci */ 14868c2ecf20Sopenharmony_ciint insn_fetch_from_user_inatomic(struct pt_regs *regs, unsigned char buf[MAX_INSN_SIZE]) 14878c2ecf20Sopenharmony_ci{ 14888c2ecf20Sopenharmony_ci unsigned long ip; 14898c2ecf20Sopenharmony_ci int not_copied; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci ip = insn_get_effective_ip(regs); 14928c2ecf20Sopenharmony_ci if (!ip) 14938c2ecf20Sopenharmony_ci return 0; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci not_copied = __copy_from_user_inatomic(buf, (void __user *)ip, MAX_INSN_SIZE); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci return MAX_INSN_SIZE - not_copied; 14988c2ecf20Sopenharmony_ci} 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci/** 15018c2ecf20Sopenharmony_ci * insn_decode_from_regs() - Decode an instruction 15028c2ecf20Sopenharmony_ci * @insn: Structure to store decoded instruction 15038c2ecf20Sopenharmony_ci * @regs: Structure with register values as seen when entering kernel mode 15048c2ecf20Sopenharmony_ci * @buf: Buffer containing the instruction bytes 15058c2ecf20Sopenharmony_ci * @buf_size: Number of instruction bytes available in buf 15068c2ecf20Sopenharmony_ci * 15078c2ecf20Sopenharmony_ci * Decodes the instruction provided in buf and stores the decoding results in 15088c2ecf20Sopenharmony_ci * insn. Also determines the correct address and operand sizes. 15098c2ecf20Sopenharmony_ci * 15108c2ecf20Sopenharmony_ci * Returns: 15118c2ecf20Sopenharmony_ci * 15128c2ecf20Sopenharmony_ci * True if instruction was decoded, False otherwise. 15138c2ecf20Sopenharmony_ci */ 15148c2ecf20Sopenharmony_cibool insn_decode_from_regs(struct insn *insn, struct pt_regs *regs, 15158c2ecf20Sopenharmony_ci unsigned char buf[MAX_INSN_SIZE], int buf_size) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci int seg_defs; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci insn_init(insn, buf, buf_size, user_64bit_mode(regs)); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci /* 15228c2ecf20Sopenharmony_ci * Override the default operand and address sizes with what is specified 15238c2ecf20Sopenharmony_ci * in the code segment descriptor. The instruction decoder only sets 15248c2ecf20Sopenharmony_ci * the address size it to either 4 or 8 address bytes and does nothing 15258c2ecf20Sopenharmony_ci * for the operand bytes. This OK for most of the cases, but we could 15268c2ecf20Sopenharmony_ci * have special cases where, for instance, a 16-bit code segment 15278c2ecf20Sopenharmony_ci * descriptor is used. 15288c2ecf20Sopenharmony_ci * If there is an address override prefix, the instruction decoder 15298c2ecf20Sopenharmony_ci * correctly updates these values, even for 16-bit defaults. 15308c2ecf20Sopenharmony_ci */ 15318c2ecf20Sopenharmony_ci seg_defs = insn_get_code_seg_params(regs); 15328c2ecf20Sopenharmony_ci if (seg_defs == -EINVAL) 15338c2ecf20Sopenharmony_ci return false; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci insn->addr_bytes = INSN_CODE_SEG_ADDR_SZ(seg_defs); 15368c2ecf20Sopenharmony_ci insn->opnd_bytes = INSN_CODE_SEG_OPND_SZ(seg_defs); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci if (insn_get_length(insn)) 15398c2ecf20Sopenharmony_ci return false; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (buf_size < insn->length) 15428c2ecf20Sopenharmony_ci return false; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci return true; 15458c2ecf20Sopenharmony_ci} 1546