blob: 405ffeb1c38281acd7c1098decb64a2a54131909 [file] [log] [blame]
Ricardo Neri32542ee2017-10-27 13:25:36 -07001/*
2 * Utility functions for x86 operand and address decoding
3 *
4 * Copyright (C) Intel Corporation 2017
5 */
6#include <linux/kernel.h>
7#include <linux/string.h>
Ricardo Neried594e42017-10-27 13:25:37 -07008#include <linux/ratelimit.h>
Ricardo Neri32542ee2017-10-27 13:25:36 -07009#include <asm/inat.h>
10#include <asm/insn.h>
11#include <asm/insn-eval.h>
12
Ricardo Neried594e42017-10-27 13:25:37 -070013#undef pr_fmt
14#define pr_fmt(fmt) "insn: " fmt
15
Ricardo Neri32542ee2017-10-27 13:25:36 -070016enum reg_type {
17 REG_TYPE_RM = 0,
18 REG_TYPE_INDEX,
19 REG_TYPE_BASE,
20};
21
22static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
23 enum reg_type type)
24{
25 int regno = 0;
26
27 static const int regoff[] = {
28 offsetof(struct pt_regs, ax),
29 offsetof(struct pt_regs, cx),
30 offsetof(struct pt_regs, dx),
31 offsetof(struct pt_regs, bx),
32 offsetof(struct pt_regs, sp),
33 offsetof(struct pt_regs, bp),
34 offsetof(struct pt_regs, si),
35 offsetof(struct pt_regs, di),
36#ifdef CONFIG_X86_64
37 offsetof(struct pt_regs, r8),
38 offsetof(struct pt_regs, r9),
39 offsetof(struct pt_regs, r10),
40 offsetof(struct pt_regs, r11),
41 offsetof(struct pt_regs, r12),
42 offsetof(struct pt_regs, r13),
43 offsetof(struct pt_regs, r14),
44 offsetof(struct pt_regs, r15),
45#endif
46 };
47 int nr_registers = ARRAY_SIZE(regoff);
48 /*
49 * Don't possibly decode a 32-bit instructions as
50 * reading a 64-bit-only register.
51 */
52 if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
53 nr_registers -= 8;
54
55 switch (type) {
56 case REG_TYPE_RM:
57 regno = X86_MODRM_RM(insn->modrm.value);
58 if (X86_REX_B(insn->rex_prefix.value))
59 regno += 8;
60 break;
61
62 case REG_TYPE_INDEX:
63 regno = X86_SIB_INDEX(insn->sib.value);
64 if (X86_REX_X(insn->rex_prefix.value))
65 regno += 8;
66
67 /*
68 * If ModRM.mod != 3 and SIB.index = 4 the scale*index
69 * portion of the address computation is null. This is
70 * true only if REX.X is 0. In such a case, the SIB index
71 * is used in the address computation.
72 */
73 if (X86_MODRM_MOD(insn->modrm.value) != 3 && regno == 4)
74 return -EDOM;
75 break;
76
77 case REG_TYPE_BASE:
78 regno = X86_SIB_BASE(insn->sib.value);
79 /*
80 * If ModRM.mod is 0 and SIB.base == 5, the base of the
81 * register-indirect addressing is 0. In this case, a
82 * 32-bit displacement follows the SIB byte.
83 */
84 if (!X86_MODRM_MOD(insn->modrm.value) && regno == 5)
85 return -EDOM;
86
87 if (X86_REX_B(insn->rex_prefix.value))
88 regno += 8;
89 break;
90
91 default:
Ricardo Neried594e42017-10-27 13:25:37 -070092 pr_err_ratelimited("invalid register type: %d\n", type);
93 return -EINVAL;
Ricardo Neri32542ee2017-10-27 13:25:36 -070094 }
95
96 if (regno >= nr_registers) {
97 WARN_ONCE(1, "decoded an instruction with an invalid register");
98 return -EINVAL;
99 }
100 return regoff[regno];
101}
102
Ricardo Nerie5e45f12017-10-27 13:25:38 -0700103/**
104 * insn_get_modrm_rm_off() - Obtain register in r/m part of the ModRM byte
105 * @insn: Instruction containing the ModRM byte
106 * @regs: Register values as seen when entering kernel mode
107 *
108 * Returns:
109 *
110 * The register indicated by the r/m part of the ModRM byte. The
111 * register is obtained as an offset from the base of pt_regs. In specific
112 * cases, the returned value can be -EDOM to indicate that the particular value
113 * of ModRM does not refer to a register and shall be ignored.
114 */
115int insn_get_modrm_rm_off(struct insn *insn, struct pt_regs *regs)
116{
117 return get_reg_offset(insn, regs, REG_TYPE_RM);
118}
119
Ricardo Neri32542ee2017-10-27 13:25:36 -0700120/*
121 * return the address being referenced be instruction
122 * for rm=3 returning the content of the rm reg
123 * for rm!=3 calculates the address using SIB and Disp
124 */
125void __user *insn_get_addr_ref(struct insn *insn, struct pt_regs *regs)
126{
127 int addr_offset, base_offset, indx_offset;
128 unsigned long linear_addr = -1L;
129 long eff_addr, base, indx;
130 insn_byte_t sib;
131
132 insn_get_modrm(insn);
133 insn_get_sib(insn);
134 sib = insn->sib.value;
135
136 if (X86_MODRM_MOD(insn->modrm.value) == 3) {
137 addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
138 if (addr_offset < 0)
139 goto out;
140
141 eff_addr = regs_get_register(regs, addr_offset);
142 } else {
143 if (insn->sib.nbytes) {
144 /*
145 * Negative values in the base and index offset means
146 * an error when decoding the SIB byte. Except -EDOM,
147 * which means that the registers should not be used
148 * in the address computation.
149 */
150 base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
151 if (base_offset == -EDOM)
152 base = 0;
153 else if (base_offset < 0)
154 goto out;
155 else
156 base = regs_get_register(regs, base_offset);
157
158 indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
159
160 if (indx_offset == -EDOM)
161 indx = 0;
162 else if (indx_offset < 0)
163 goto out;
164 else
165 indx = regs_get_register(regs, indx_offset);
166
167 eff_addr = base + indx * (1 << X86_SIB_SCALE(sib));
168 } else {
169 addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
170 if (addr_offset < 0)
171 goto out;
172
173 eff_addr = regs_get_register(regs, addr_offset);
174 }
175
176 eff_addr += insn->displacement.value;
177 }
178
179 linear_addr = (unsigned long)eff_addr;
180
181out:
182 return (void __user *)linear_addr;
183}