1*74fe6c29SRuslan Bukin /* 2*74fe6c29SRuslan Bukin * Copyright (c) 2013-2018, Intel Corporation 3*74fe6c29SRuslan Bukin * 4*74fe6c29SRuslan Bukin * Redistribution and use in source and binary forms, with or without 5*74fe6c29SRuslan Bukin * modification, are permitted provided that the following conditions are met: 6*74fe6c29SRuslan Bukin * 7*74fe6c29SRuslan Bukin * * Redistributions of source code must retain the above copyright notice, 8*74fe6c29SRuslan Bukin * this list of conditions and the following disclaimer. 9*74fe6c29SRuslan Bukin * * Redistributions in binary form must reproduce the above copyright notice, 10*74fe6c29SRuslan Bukin * this list of conditions and the following disclaimer in the documentation 11*74fe6c29SRuslan Bukin * and/or other materials provided with the distribution. 12*74fe6c29SRuslan Bukin * * Neither the name of Intel Corporation nor the names of its contributors 13*74fe6c29SRuslan Bukin * may be used to endorse or promote products derived from this software 14*74fe6c29SRuslan Bukin * without specific prior written permission. 15*74fe6c29SRuslan Bukin * 16*74fe6c29SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17*74fe6c29SRuslan Bukin * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*74fe6c29SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*74fe6c29SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20*74fe6c29SRuslan Bukin * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21*74fe6c29SRuslan Bukin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22*74fe6c29SRuslan Bukin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23*74fe6c29SRuslan Bukin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24*74fe6c29SRuslan Bukin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25*74fe6c29SRuslan Bukin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26*74fe6c29SRuslan Bukin * POSSIBILITY OF SUCH DAMAGE. 27*74fe6c29SRuslan Bukin */ 28*74fe6c29SRuslan Bukin 29*74fe6c29SRuslan Bukin #include "pt_ild.h" 30*74fe6c29SRuslan Bukin #include "pti-imm-defs.h" 31*74fe6c29SRuslan Bukin #include "pti-imm.h" 32*74fe6c29SRuslan Bukin #include "pti-modrm-defs.h" 33*74fe6c29SRuslan Bukin #include "pti-modrm.h" 34*74fe6c29SRuslan Bukin #include "pti-disp-defs.h" 35*74fe6c29SRuslan Bukin #include "pti-disp.h" 36*74fe6c29SRuslan Bukin 37*74fe6c29SRuslan Bukin #include <string.h> 38*74fe6c29SRuslan Bukin 39*74fe6c29SRuslan Bukin /* SET UP 3 TABLES */ 40*74fe6c29SRuslan Bukin 41*74fe6c29SRuslan Bukin static uint8_t has_disp_regular[4][4][8]; 42*74fe6c29SRuslan Bukin 43*74fe6c29SRuslan Bukin static void init_has_disp_regular_table(void) 44*74fe6c29SRuslan Bukin { 45*74fe6c29SRuslan Bukin uint8_t mod, rm; 46*74fe6c29SRuslan Bukin 47*74fe6c29SRuslan Bukin memset(has_disp_regular, 0, sizeof(has_disp_regular)); 48*74fe6c29SRuslan Bukin 49*74fe6c29SRuslan Bukin /*fill eamode16 */ 50*74fe6c29SRuslan Bukin has_disp_regular[ptem_16bit][0][6] = 2; 51*74fe6c29SRuslan Bukin for (rm = 0; rm < 8; rm++) 52*74fe6c29SRuslan Bukin for (mod = 1; mod <= 2; mod++) 53*74fe6c29SRuslan Bukin has_disp_regular[ptem_16bit][mod][rm] = mod; 54*74fe6c29SRuslan Bukin 55*74fe6c29SRuslan Bukin /*fill eamode32/64 */ 56*74fe6c29SRuslan Bukin has_disp_regular[ptem_32bit][0][5] = 4; 57*74fe6c29SRuslan Bukin has_disp_regular[ptem_64bit][0][5] = 4; 58*74fe6c29SRuslan Bukin for (rm = 0; rm < 8; rm++) { 59*74fe6c29SRuslan Bukin has_disp_regular[ptem_32bit][1][rm] = 1; 60*74fe6c29SRuslan Bukin has_disp_regular[ptem_32bit][2][rm] = 4; 61*74fe6c29SRuslan Bukin 62*74fe6c29SRuslan Bukin has_disp_regular[ptem_64bit][1][rm] = 1; 63*74fe6c29SRuslan Bukin has_disp_regular[ptem_64bit][2][rm] = 4; 64*74fe6c29SRuslan Bukin } 65*74fe6c29SRuslan Bukin } 66*74fe6c29SRuslan Bukin 67*74fe6c29SRuslan Bukin static uint8_t eamode_table[2][4]; 68*74fe6c29SRuslan Bukin 69*74fe6c29SRuslan Bukin static void init_eamode_table(void) 70*74fe6c29SRuslan Bukin { 71*74fe6c29SRuslan Bukin eamode_table[0][ptem_unknown] = ptem_unknown; 72*74fe6c29SRuslan Bukin eamode_table[0][ptem_16bit] = ptem_16bit; 73*74fe6c29SRuslan Bukin eamode_table[0][ptem_32bit] = ptem_32bit; 74*74fe6c29SRuslan Bukin eamode_table[0][ptem_64bit] = ptem_64bit; 75*74fe6c29SRuslan Bukin 76*74fe6c29SRuslan Bukin eamode_table[1][ptem_unknown] = ptem_unknown; 77*74fe6c29SRuslan Bukin eamode_table[1][ptem_16bit] = ptem_32bit; 78*74fe6c29SRuslan Bukin eamode_table[1][ptem_32bit] = ptem_16bit; 79*74fe6c29SRuslan Bukin eamode_table[1][ptem_64bit] = ptem_32bit; 80*74fe6c29SRuslan Bukin } 81*74fe6c29SRuslan Bukin 82*74fe6c29SRuslan Bukin static uint8_t has_sib_table[4][4][8]; 83*74fe6c29SRuslan Bukin 84*74fe6c29SRuslan Bukin static void init_has_sib_table(void) 85*74fe6c29SRuslan Bukin { 86*74fe6c29SRuslan Bukin uint8_t mod; 87*74fe6c29SRuslan Bukin 88*74fe6c29SRuslan Bukin memset(has_sib_table, 0, sizeof(has_sib_table)); 89*74fe6c29SRuslan Bukin 90*74fe6c29SRuslan Bukin /*for eamode32/64 there is sib byte for mod!=3 and rm==4 */ 91*74fe6c29SRuslan Bukin for (mod = 0; mod <= 2; mod++) { 92*74fe6c29SRuslan Bukin has_sib_table[ptem_32bit][mod][4] = 1; 93*74fe6c29SRuslan Bukin has_sib_table[ptem_64bit][mod][4] = 1; 94*74fe6c29SRuslan Bukin } 95*74fe6c29SRuslan Bukin } 96*74fe6c29SRuslan Bukin 97*74fe6c29SRuslan Bukin /* SOME ACCESSORS */ 98*74fe6c29SRuslan Bukin 99*74fe6c29SRuslan Bukin static inline uint8_t get_byte(const struct pt_ild *ild, uint8_t i) 100*74fe6c29SRuslan Bukin { 101*74fe6c29SRuslan Bukin return ild->itext[i]; 102*74fe6c29SRuslan Bukin } 103*74fe6c29SRuslan Bukin 104*74fe6c29SRuslan Bukin static inline uint8_t const *get_byte_ptr(const struct pt_ild *ild, uint8_t i) 105*74fe6c29SRuslan Bukin { 106*74fe6c29SRuslan Bukin return ild->itext + i; 107*74fe6c29SRuslan Bukin } 108*74fe6c29SRuslan Bukin 109*74fe6c29SRuslan Bukin static inline int mode_64b(const struct pt_ild *ild) 110*74fe6c29SRuslan Bukin { 111*74fe6c29SRuslan Bukin return ild->mode == ptem_64bit; 112*74fe6c29SRuslan Bukin } 113*74fe6c29SRuslan Bukin 114*74fe6c29SRuslan Bukin static inline int mode_32b(const struct pt_ild *ild) 115*74fe6c29SRuslan Bukin { 116*74fe6c29SRuslan Bukin return ild->mode == ptem_32bit; 117*74fe6c29SRuslan Bukin } 118*74fe6c29SRuslan Bukin 119*74fe6c29SRuslan Bukin static inline int bits_match(uint8_t x, uint8_t mask, uint8_t target) 120*74fe6c29SRuslan Bukin { 121*74fe6c29SRuslan Bukin return (x & mask) == target; 122*74fe6c29SRuslan Bukin } 123*74fe6c29SRuslan Bukin 124*74fe6c29SRuslan Bukin static inline enum pt_exec_mode 125*74fe6c29SRuslan Bukin pti_get_nominal_eosz_non64(const struct pt_ild *ild) 126*74fe6c29SRuslan Bukin { 127*74fe6c29SRuslan Bukin if (mode_32b(ild)) { 128*74fe6c29SRuslan Bukin if (ild->u.s.osz) 129*74fe6c29SRuslan Bukin return ptem_16bit; 130*74fe6c29SRuslan Bukin return ptem_32bit; 131*74fe6c29SRuslan Bukin } 132*74fe6c29SRuslan Bukin if (ild->u.s.osz) 133*74fe6c29SRuslan Bukin return ptem_32bit; 134*74fe6c29SRuslan Bukin return ptem_16bit; 135*74fe6c29SRuslan Bukin } 136*74fe6c29SRuslan Bukin 137*74fe6c29SRuslan Bukin static inline enum pt_exec_mode 138*74fe6c29SRuslan Bukin pti_get_nominal_eosz(const struct pt_ild *ild) 139*74fe6c29SRuslan Bukin { 140*74fe6c29SRuslan Bukin if (mode_64b(ild)) { 141*74fe6c29SRuslan Bukin if (ild->u.s.rex_w) 142*74fe6c29SRuslan Bukin return ptem_64bit; 143*74fe6c29SRuslan Bukin if (ild->u.s.osz) 144*74fe6c29SRuslan Bukin return ptem_16bit; 145*74fe6c29SRuslan Bukin return ptem_32bit; 146*74fe6c29SRuslan Bukin } 147*74fe6c29SRuslan Bukin return pti_get_nominal_eosz_non64(ild); 148*74fe6c29SRuslan Bukin } 149*74fe6c29SRuslan Bukin 150*74fe6c29SRuslan Bukin static inline enum pt_exec_mode 151*74fe6c29SRuslan Bukin pti_get_nominal_eosz_df64(const struct pt_ild *ild) 152*74fe6c29SRuslan Bukin { 153*74fe6c29SRuslan Bukin if (mode_64b(ild)) { 154*74fe6c29SRuslan Bukin if (ild->u.s.rex_w) 155*74fe6c29SRuslan Bukin return ptem_64bit; 156*74fe6c29SRuslan Bukin if (ild->u.s.osz) 157*74fe6c29SRuslan Bukin return ptem_16bit; 158*74fe6c29SRuslan Bukin /* only this next line of code is different relative 159*74fe6c29SRuslan Bukin to pti_get_nominal_eosz(), above */ 160*74fe6c29SRuslan Bukin return ptem_64bit; 161*74fe6c29SRuslan Bukin } 162*74fe6c29SRuslan Bukin return pti_get_nominal_eosz_non64(ild); 163*74fe6c29SRuslan Bukin } 164*74fe6c29SRuslan Bukin 165*74fe6c29SRuslan Bukin static inline enum pt_exec_mode 166*74fe6c29SRuslan Bukin pti_get_nominal_easz_non64(const struct pt_ild *ild) 167*74fe6c29SRuslan Bukin { 168*74fe6c29SRuslan Bukin if (mode_32b(ild)) { 169*74fe6c29SRuslan Bukin if (ild->u.s.asz) 170*74fe6c29SRuslan Bukin return ptem_16bit; 171*74fe6c29SRuslan Bukin return ptem_32bit; 172*74fe6c29SRuslan Bukin } 173*74fe6c29SRuslan Bukin if (ild->u.s.asz) 174*74fe6c29SRuslan Bukin return ptem_32bit; 175*74fe6c29SRuslan Bukin return ptem_16bit; 176*74fe6c29SRuslan Bukin } 177*74fe6c29SRuslan Bukin 178*74fe6c29SRuslan Bukin static inline enum pt_exec_mode 179*74fe6c29SRuslan Bukin pti_get_nominal_easz(const struct pt_ild *ild) 180*74fe6c29SRuslan Bukin { 181*74fe6c29SRuslan Bukin if (mode_64b(ild)) { 182*74fe6c29SRuslan Bukin if (ild->u.s.asz) 183*74fe6c29SRuslan Bukin return ptem_32bit; 184*74fe6c29SRuslan Bukin return ptem_64bit; 185*74fe6c29SRuslan Bukin } 186*74fe6c29SRuslan Bukin return pti_get_nominal_easz_non64(ild); 187*74fe6c29SRuslan Bukin } 188*74fe6c29SRuslan Bukin 189*74fe6c29SRuslan Bukin static inline int resolve_z(uint8_t *pbytes, enum pt_exec_mode eosz) 190*74fe6c29SRuslan Bukin { 191*74fe6c29SRuslan Bukin static const uint8_t bytes[] = { 2, 4, 4 }; 192*74fe6c29SRuslan Bukin unsigned int idx; 193*74fe6c29SRuslan Bukin 194*74fe6c29SRuslan Bukin if (!pbytes) 195*74fe6c29SRuslan Bukin return -pte_internal; 196*74fe6c29SRuslan Bukin 197*74fe6c29SRuslan Bukin idx = (unsigned int) eosz - 1; 198*74fe6c29SRuslan Bukin if (sizeof(bytes) <= idx) 199*74fe6c29SRuslan Bukin return -pte_bad_insn; 200*74fe6c29SRuslan Bukin 201*74fe6c29SRuslan Bukin *pbytes = bytes[idx]; 202*74fe6c29SRuslan Bukin return 0; 203*74fe6c29SRuslan Bukin } 204*74fe6c29SRuslan Bukin 205*74fe6c29SRuslan Bukin static inline int resolve_v(uint8_t *pbytes, enum pt_exec_mode eosz) 206*74fe6c29SRuslan Bukin { 207*74fe6c29SRuslan Bukin static const uint8_t bytes[] = { 2, 4, 8 }; 208*74fe6c29SRuslan Bukin unsigned int idx; 209*74fe6c29SRuslan Bukin 210*74fe6c29SRuslan Bukin if (!pbytes) 211*74fe6c29SRuslan Bukin return -pte_internal; 212*74fe6c29SRuslan Bukin 213*74fe6c29SRuslan Bukin idx = (unsigned int) eosz - 1; 214*74fe6c29SRuslan Bukin if (sizeof(bytes) <= idx) 215*74fe6c29SRuslan Bukin return -pte_bad_insn; 216*74fe6c29SRuslan Bukin 217*74fe6c29SRuslan Bukin *pbytes = bytes[idx]; 218*74fe6c29SRuslan Bukin return 0; 219*74fe6c29SRuslan Bukin } 220*74fe6c29SRuslan Bukin 221*74fe6c29SRuslan Bukin /* DECODERS */ 222*74fe6c29SRuslan Bukin 223*74fe6c29SRuslan Bukin static int set_imm_bytes(struct pt_ild *ild) 224*74fe6c29SRuslan Bukin { 225*74fe6c29SRuslan Bukin /*: set ild->imm1_bytes and ild->imm2_bytes for maps 0/1 */ 226*74fe6c29SRuslan Bukin static uint8_t const *const map_map[] = { 227*74fe6c29SRuslan Bukin /* map 0 */ imm_bytes_map_0x0, 228*74fe6c29SRuslan Bukin /* map 1 */ imm_bytes_map_0x0F 229*74fe6c29SRuslan Bukin }; 230*74fe6c29SRuslan Bukin uint8_t map, imm_code; 231*74fe6c29SRuslan Bukin 232*74fe6c29SRuslan Bukin if (!ild) 233*74fe6c29SRuslan Bukin return -pte_internal; 234*74fe6c29SRuslan Bukin 235*74fe6c29SRuslan Bukin map = ild->map; 236*74fe6c29SRuslan Bukin 237*74fe6c29SRuslan Bukin if ((sizeof(map_map) / sizeof(*map_map)) <= map) 238*74fe6c29SRuslan Bukin return 0; 239*74fe6c29SRuslan Bukin 240*74fe6c29SRuslan Bukin imm_code = map_map[map][ild->nominal_opcode]; 241*74fe6c29SRuslan Bukin switch (imm_code) { 242*74fe6c29SRuslan Bukin case PTI_IMM_NONE: 243*74fe6c29SRuslan Bukin case PTI_0_IMM_WIDTH_CONST_l2: 244*74fe6c29SRuslan Bukin default: 245*74fe6c29SRuslan Bukin return 0; 246*74fe6c29SRuslan Bukin 247*74fe6c29SRuslan Bukin case PTI_UIMM8_IMM_WIDTH_CONST_l2: 248*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 249*74fe6c29SRuslan Bukin return 0; 250*74fe6c29SRuslan Bukin 251*74fe6c29SRuslan Bukin case PTI_SIMM8_IMM_WIDTH_CONST_l2: 252*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 253*74fe6c29SRuslan Bukin return 0; 254*74fe6c29SRuslan Bukin 255*74fe6c29SRuslan Bukin case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2: 256*74fe6c29SRuslan Bukin /* SIMMz(eosz) */ 257*74fe6c29SRuslan Bukin return resolve_z(&ild->imm1_bytes, pti_get_nominal_eosz(ild)); 258*74fe6c29SRuslan Bukin 259*74fe6c29SRuslan Bukin case PTI_UIMMv_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2: 260*74fe6c29SRuslan Bukin /* UIMMv(eosz) */ 261*74fe6c29SRuslan Bukin return resolve_v(&ild->imm1_bytes, pti_get_nominal_eosz(ild)); 262*74fe6c29SRuslan Bukin 263*74fe6c29SRuslan Bukin case PTI_UIMM16_IMM_WIDTH_CONST_l2: 264*74fe6c29SRuslan Bukin ild->imm1_bytes = 2; 265*74fe6c29SRuslan Bukin return 0; 266*74fe6c29SRuslan Bukin 267*74fe6c29SRuslan Bukin case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_DF64_EOSZ_l2: 268*74fe6c29SRuslan Bukin /* push defaults to eosz64 in 64b mode, then uses SIMMz */ 269*74fe6c29SRuslan Bukin return resolve_z(&ild->imm1_bytes, 270*74fe6c29SRuslan Bukin pti_get_nominal_eosz_df64(ild)); 271*74fe6c29SRuslan Bukin 272*74fe6c29SRuslan Bukin case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf7_l1: 273*74fe6c29SRuslan Bukin if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2) { 274*74fe6c29SRuslan Bukin return resolve_z(&ild->imm1_bytes, 275*74fe6c29SRuslan Bukin pti_get_nominal_eosz(ild)); 276*74fe6c29SRuslan Bukin } 277*74fe6c29SRuslan Bukin return 0; 278*74fe6c29SRuslan Bukin 279*74fe6c29SRuslan Bukin case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xc7_l1: 280*74fe6c29SRuslan Bukin if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 0) { 281*74fe6c29SRuslan Bukin return resolve_z(&ild->imm1_bytes, 282*74fe6c29SRuslan Bukin pti_get_nominal_eosz(ild)); 283*74fe6c29SRuslan Bukin } 284*74fe6c29SRuslan Bukin return 0; 285*74fe6c29SRuslan Bukin 286*74fe6c29SRuslan Bukin case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf6_l1: 287*74fe6c29SRuslan Bukin if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2) 288*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 289*74fe6c29SRuslan Bukin 290*74fe6c29SRuslan Bukin return 0; 291*74fe6c29SRuslan Bukin 292*74fe6c29SRuslan Bukin case PTI_IMM_hasimm_map0x0_op0xc8_l1: 293*74fe6c29SRuslan Bukin if (ild->map == PTI_MAP_0) { 294*74fe6c29SRuslan Bukin /*enter -> imm1=2, imm2=1 */ 295*74fe6c29SRuslan Bukin ild->imm1_bytes = 2; 296*74fe6c29SRuslan Bukin ild->imm2_bytes = 1; 297*74fe6c29SRuslan Bukin } 298*74fe6c29SRuslan Bukin return 0; 299*74fe6c29SRuslan Bukin 300*74fe6c29SRuslan Bukin case PTI_IMM_hasimm_map0x0F_op0x78_l1: 301*74fe6c29SRuslan Bukin /* AMD SSE4a (insertq/extrq use osz/f2) vs vmread 302*74fe6c29SRuslan Bukin * (no prefixes) 303*74fe6c29SRuslan Bukin */ 304*74fe6c29SRuslan Bukin if (ild->map == PTI_MAP_1) { 305*74fe6c29SRuslan Bukin if (ild->u.s.osz || ild->u.s.last_f2f3 == 2) { 306*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 307*74fe6c29SRuslan Bukin ild->imm2_bytes = 1; 308*74fe6c29SRuslan Bukin } 309*74fe6c29SRuslan Bukin } 310*74fe6c29SRuslan Bukin return 0; 311*74fe6c29SRuslan Bukin } 312*74fe6c29SRuslan Bukin } 313*74fe6c29SRuslan Bukin 314*74fe6c29SRuslan Bukin static int imm_dec(struct pt_ild *ild, uint8_t length) 315*74fe6c29SRuslan Bukin { 316*74fe6c29SRuslan Bukin int errcode; 317*74fe6c29SRuslan Bukin 318*74fe6c29SRuslan Bukin if (!ild) 319*74fe6c29SRuslan Bukin return -pte_internal; 320*74fe6c29SRuslan Bukin 321*74fe6c29SRuslan Bukin if (ild->map == PTI_MAP_AMD3DNOW) { 322*74fe6c29SRuslan Bukin if (ild->max_bytes <= length) 323*74fe6c29SRuslan Bukin return -pte_bad_insn; 324*74fe6c29SRuslan Bukin 325*74fe6c29SRuslan Bukin ild->nominal_opcode = get_byte(ild, length); 326*74fe6c29SRuslan Bukin return length + 1; 327*74fe6c29SRuslan Bukin } 328*74fe6c29SRuslan Bukin 329*74fe6c29SRuslan Bukin errcode = set_imm_bytes(ild); 330*74fe6c29SRuslan Bukin if (errcode < 0) 331*74fe6c29SRuslan Bukin return errcode; 332*74fe6c29SRuslan Bukin 333*74fe6c29SRuslan Bukin length += ild->imm1_bytes; 334*74fe6c29SRuslan Bukin length += ild->imm2_bytes; 335*74fe6c29SRuslan Bukin if (ild->max_bytes < length) 336*74fe6c29SRuslan Bukin return -pte_bad_insn; 337*74fe6c29SRuslan Bukin 338*74fe6c29SRuslan Bukin return length; 339*74fe6c29SRuslan Bukin } 340*74fe6c29SRuslan Bukin 341*74fe6c29SRuslan Bukin static int compute_disp_dec(struct pt_ild *ild) 342*74fe6c29SRuslan Bukin { 343*74fe6c29SRuslan Bukin /* set ild->disp_bytes for maps 0 and 1. */ 344*74fe6c29SRuslan Bukin static uint8_t const *const map_map[] = { 345*74fe6c29SRuslan Bukin /* map 0 */ disp_bytes_map_0x0, 346*74fe6c29SRuslan Bukin /* map 1 */ disp_bytes_map_0x0F 347*74fe6c29SRuslan Bukin }; 348*74fe6c29SRuslan Bukin uint8_t map, disp_kind; 349*74fe6c29SRuslan Bukin 350*74fe6c29SRuslan Bukin if (!ild) 351*74fe6c29SRuslan Bukin return -pte_internal; 352*74fe6c29SRuslan Bukin 353*74fe6c29SRuslan Bukin if (0 < ild->disp_bytes) 354*74fe6c29SRuslan Bukin return 0; 355*74fe6c29SRuslan Bukin 356*74fe6c29SRuslan Bukin map = ild->map; 357*74fe6c29SRuslan Bukin 358*74fe6c29SRuslan Bukin if ((sizeof(map_map) / sizeof(*map_map)) <= map) 359*74fe6c29SRuslan Bukin return 0; 360*74fe6c29SRuslan Bukin 361*74fe6c29SRuslan Bukin disp_kind = map_map[map][ild->nominal_opcode]; 362*74fe6c29SRuslan Bukin switch (disp_kind) { 363*74fe6c29SRuslan Bukin case PTI_DISP_NONE: 364*74fe6c29SRuslan Bukin ild->disp_bytes = 0; 365*74fe6c29SRuslan Bukin return 0; 366*74fe6c29SRuslan Bukin 367*74fe6c29SRuslan Bukin case PTI_PRESERVE_DEFAULT: 368*74fe6c29SRuslan Bukin /* nothing to do */ 369*74fe6c29SRuslan Bukin return 0; 370*74fe6c29SRuslan Bukin 371*74fe6c29SRuslan Bukin case PTI_BRDISP8: 372*74fe6c29SRuslan Bukin ild->disp_bytes = 1; 373*74fe6c29SRuslan Bukin return 0; 374*74fe6c29SRuslan Bukin 375*74fe6c29SRuslan Bukin case PTI_DISP_BUCKET_0_l1: 376*74fe6c29SRuslan Bukin /* BRDISPz(eosz) for 16/32 modes, and BRDISP32 for 64b mode */ 377*74fe6c29SRuslan Bukin if (mode_64b(ild)) { 378*74fe6c29SRuslan Bukin ild->disp_bytes = 4; 379*74fe6c29SRuslan Bukin return 0; 380*74fe6c29SRuslan Bukin } 381*74fe6c29SRuslan Bukin 382*74fe6c29SRuslan Bukin return resolve_z(&ild->disp_bytes, 383*74fe6c29SRuslan Bukin pti_get_nominal_eosz(ild)); 384*74fe6c29SRuslan Bukin 385*74fe6c29SRuslan Bukin case PTI_MEMDISPv_DISP_WIDTH_ASZ_NONTERM_EASZ_l2: 386*74fe6c29SRuslan Bukin /* MEMDISPv(easz) */ 387*74fe6c29SRuslan Bukin return resolve_v(&ild->disp_bytes, pti_get_nominal_easz(ild)); 388*74fe6c29SRuslan Bukin 389*74fe6c29SRuslan Bukin case PTI_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2: 390*74fe6c29SRuslan Bukin /* BRDISPz(eosz) for 16/32/64 modes */ 391*74fe6c29SRuslan Bukin return resolve_z(&ild->disp_bytes, pti_get_nominal_eosz(ild)); 392*74fe6c29SRuslan Bukin 393*74fe6c29SRuslan Bukin case PTI_RESOLVE_BYREG_DISP_map0x0_op0xc7_l1: 394*74fe6c29SRuslan Bukin /* reg=0 -> preserve, reg=7 -> BRDISPz(eosz) */ 395*74fe6c29SRuslan Bukin if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 7) { 396*74fe6c29SRuslan Bukin return resolve_z(&ild->disp_bytes, 397*74fe6c29SRuslan Bukin pti_get_nominal_eosz(ild)); 398*74fe6c29SRuslan Bukin } 399*74fe6c29SRuslan Bukin return 0; 400*74fe6c29SRuslan Bukin 401*74fe6c29SRuslan Bukin default: 402*74fe6c29SRuslan Bukin return -pte_bad_insn; 403*74fe6c29SRuslan Bukin } 404*74fe6c29SRuslan Bukin } 405*74fe6c29SRuslan Bukin 406*74fe6c29SRuslan Bukin static int disp_dec(struct pt_ild *ild, uint8_t length) 407*74fe6c29SRuslan Bukin { 408*74fe6c29SRuslan Bukin uint8_t disp_bytes; 409*74fe6c29SRuslan Bukin int errcode; 410*74fe6c29SRuslan Bukin 411*74fe6c29SRuslan Bukin if (!ild) 412*74fe6c29SRuslan Bukin return -pte_internal; 413*74fe6c29SRuslan Bukin 414*74fe6c29SRuslan Bukin errcode = compute_disp_dec(ild); 415*74fe6c29SRuslan Bukin if (errcode < 0) 416*74fe6c29SRuslan Bukin return errcode; 417*74fe6c29SRuslan Bukin 418*74fe6c29SRuslan Bukin disp_bytes = ild->disp_bytes; 419*74fe6c29SRuslan Bukin if (disp_bytes == 0) 420*74fe6c29SRuslan Bukin return imm_dec(ild, length); 421*74fe6c29SRuslan Bukin 422*74fe6c29SRuslan Bukin if (length + disp_bytes > ild->max_bytes) 423*74fe6c29SRuslan Bukin return -pte_bad_insn; 424*74fe6c29SRuslan Bukin 425*74fe6c29SRuslan Bukin /*Record only position; must be able to re-read itext bytes for actual 426*74fe6c29SRuslan Bukin value. (SMC/CMC issue). */ 427*74fe6c29SRuslan Bukin ild->disp_pos = length; 428*74fe6c29SRuslan Bukin 429*74fe6c29SRuslan Bukin return imm_dec(ild, length + disp_bytes); 430*74fe6c29SRuslan Bukin } 431*74fe6c29SRuslan Bukin 432*74fe6c29SRuslan Bukin static int sib_dec(struct pt_ild *ild, uint8_t length) 433*74fe6c29SRuslan Bukin { 434*74fe6c29SRuslan Bukin uint8_t sib; 435*74fe6c29SRuslan Bukin 436*74fe6c29SRuslan Bukin if (!ild) 437*74fe6c29SRuslan Bukin return -pte_internal; 438*74fe6c29SRuslan Bukin 439*74fe6c29SRuslan Bukin if (ild->max_bytes <= length) 440*74fe6c29SRuslan Bukin return -pte_bad_insn; 441*74fe6c29SRuslan Bukin 442*74fe6c29SRuslan Bukin sib = get_byte(ild, length); 443*74fe6c29SRuslan Bukin if ((sib & 0x07) == 0x05 && pti_get_modrm_mod(ild) == 0) 444*74fe6c29SRuslan Bukin ild->disp_bytes = 4; 445*74fe6c29SRuslan Bukin 446*74fe6c29SRuslan Bukin return disp_dec(ild, length + 1); 447*74fe6c29SRuslan Bukin } 448*74fe6c29SRuslan Bukin 449*74fe6c29SRuslan Bukin static int modrm_dec(struct pt_ild *ild, uint8_t length) 450*74fe6c29SRuslan Bukin { 451*74fe6c29SRuslan Bukin static uint8_t const *const has_modrm_2d[2] = { 452*74fe6c29SRuslan Bukin has_modrm_map_0x0, 453*74fe6c29SRuslan Bukin has_modrm_map_0x0F 454*74fe6c29SRuslan Bukin }; 455*74fe6c29SRuslan Bukin int has_modrm = PTI_MODRM_FALSE; 456*74fe6c29SRuslan Bukin pti_map_enum_t map; 457*74fe6c29SRuslan Bukin 458*74fe6c29SRuslan Bukin if (!ild) 459*74fe6c29SRuslan Bukin return -pte_internal; 460*74fe6c29SRuslan Bukin 461*74fe6c29SRuslan Bukin map = pti_get_map(ild); 462*74fe6c29SRuslan Bukin if (map >= PTI_MAP_2) 463*74fe6c29SRuslan Bukin has_modrm = PTI_MODRM_TRUE; 464*74fe6c29SRuslan Bukin else 465*74fe6c29SRuslan Bukin has_modrm = has_modrm_2d[map][ild->nominal_opcode]; 466*74fe6c29SRuslan Bukin 467*74fe6c29SRuslan Bukin if (has_modrm == PTI_MODRM_FALSE || has_modrm == PTI_MODRM_UNDEF) 468*74fe6c29SRuslan Bukin return disp_dec(ild, length); 469*74fe6c29SRuslan Bukin 470*74fe6c29SRuslan Bukin /* really >= here because we have not eaten the byte yet */ 471*74fe6c29SRuslan Bukin if (length >= ild->max_bytes) 472*74fe6c29SRuslan Bukin return -pte_bad_insn; 473*74fe6c29SRuslan Bukin 474*74fe6c29SRuslan Bukin ild->modrm_byte = get_byte(ild, length); 475*74fe6c29SRuslan Bukin 476*74fe6c29SRuslan Bukin if (has_modrm != PTI_MODRM_IGNORE_MOD) { 477*74fe6c29SRuslan Bukin /* set disp_bytes and sib using simple tables */ 478*74fe6c29SRuslan Bukin 479*74fe6c29SRuslan Bukin uint8_t eamode = eamode_table[ild->u.s.asz][ild->mode]; 480*74fe6c29SRuslan Bukin uint8_t mod = (uint8_t) pti_get_modrm_mod(ild); 481*74fe6c29SRuslan Bukin uint8_t rm = (uint8_t) pti_get_modrm_rm(ild); 482*74fe6c29SRuslan Bukin uint8_t has_sib; 483*74fe6c29SRuslan Bukin 484*74fe6c29SRuslan Bukin ild->disp_bytes = has_disp_regular[eamode][mod][rm]; 485*74fe6c29SRuslan Bukin 486*74fe6c29SRuslan Bukin has_sib = has_sib_table[eamode][mod][rm]; 487*74fe6c29SRuslan Bukin if (has_sib) 488*74fe6c29SRuslan Bukin return sib_dec(ild, length + 1); 489*74fe6c29SRuslan Bukin } 490*74fe6c29SRuslan Bukin 491*74fe6c29SRuslan Bukin return disp_dec(ild, length + 1); 492*74fe6c29SRuslan Bukin } 493*74fe6c29SRuslan Bukin 494*74fe6c29SRuslan Bukin static inline int get_next_as_opcode(struct pt_ild *ild, uint8_t length) 495*74fe6c29SRuslan Bukin { 496*74fe6c29SRuslan Bukin if (!ild) 497*74fe6c29SRuslan Bukin return -pte_internal; 498*74fe6c29SRuslan Bukin 499*74fe6c29SRuslan Bukin if (ild->max_bytes <= length) 500*74fe6c29SRuslan Bukin return -pte_bad_insn; 501*74fe6c29SRuslan Bukin 502*74fe6c29SRuslan Bukin ild->nominal_opcode = get_byte(ild, length); 503*74fe6c29SRuslan Bukin 504*74fe6c29SRuslan Bukin return modrm_dec(ild, length + 1); 505*74fe6c29SRuslan Bukin } 506*74fe6c29SRuslan Bukin 507*74fe6c29SRuslan Bukin static int opcode_dec(struct pt_ild *ild, uint8_t length) 508*74fe6c29SRuslan Bukin { 509*74fe6c29SRuslan Bukin uint8_t b, m; 510*74fe6c29SRuslan Bukin 511*74fe6c29SRuslan Bukin if (!ild) 512*74fe6c29SRuslan Bukin return -pte_internal; 513*74fe6c29SRuslan Bukin 514*74fe6c29SRuslan Bukin /*no need to check max_bytes - it was checked in previous scanners */ 515*74fe6c29SRuslan Bukin b = get_byte(ild, length); 516*74fe6c29SRuslan Bukin if (b != 0x0F) { /* 1B opcodes, map 0 */ 517*74fe6c29SRuslan Bukin ild->map = PTI_MAP_0; 518*74fe6c29SRuslan Bukin ild->nominal_opcode = b; 519*74fe6c29SRuslan Bukin 520*74fe6c29SRuslan Bukin return modrm_dec(ild, length + 1); 521*74fe6c29SRuslan Bukin } 522*74fe6c29SRuslan Bukin 523*74fe6c29SRuslan Bukin length++; /* eat the 0x0F */ 524*74fe6c29SRuslan Bukin 525*74fe6c29SRuslan Bukin if (ild->max_bytes <= length) 526*74fe6c29SRuslan Bukin return -pte_bad_insn; 527*74fe6c29SRuslan Bukin 528*74fe6c29SRuslan Bukin /* 0x0F opcodes MAPS 1,2,3 */ 529*74fe6c29SRuslan Bukin m = get_byte(ild, length); 530*74fe6c29SRuslan Bukin if (m == 0x38) { 531*74fe6c29SRuslan Bukin ild->map = PTI_MAP_2; 532*74fe6c29SRuslan Bukin 533*74fe6c29SRuslan Bukin return get_next_as_opcode(ild, length + 1); 534*74fe6c29SRuslan Bukin } else if (m == 0x3A) { 535*74fe6c29SRuslan Bukin ild->map = PTI_MAP_3; 536*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 537*74fe6c29SRuslan Bukin 538*74fe6c29SRuslan Bukin return get_next_as_opcode(ild, length + 1); 539*74fe6c29SRuslan Bukin } else if (bits_match(m, 0xf8, 0x38)) { 540*74fe6c29SRuslan Bukin ild->map = PTI_MAP_INVALID; 541*74fe6c29SRuslan Bukin 542*74fe6c29SRuslan Bukin return get_next_as_opcode(ild, length + 1); 543*74fe6c29SRuslan Bukin } else if (m == 0x0F) { /* 3dNow */ 544*74fe6c29SRuslan Bukin ild->map = PTI_MAP_AMD3DNOW; 545*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 546*74fe6c29SRuslan Bukin /* real opcode is in immediate later on, but we need an 547*74fe6c29SRuslan Bukin * opcode now. */ 548*74fe6c29SRuslan Bukin ild->nominal_opcode = 0x0F; 549*74fe6c29SRuslan Bukin 550*74fe6c29SRuslan Bukin return modrm_dec(ild, length + 1); 551*74fe6c29SRuslan Bukin } else { /* map 1 (simple two byte opcodes) */ 552*74fe6c29SRuslan Bukin ild->nominal_opcode = m; 553*74fe6c29SRuslan Bukin ild->map = PTI_MAP_1; 554*74fe6c29SRuslan Bukin 555*74fe6c29SRuslan Bukin return modrm_dec(ild, length + 1); 556*74fe6c29SRuslan Bukin } 557*74fe6c29SRuslan Bukin } 558*74fe6c29SRuslan Bukin 559*74fe6c29SRuslan Bukin typedef int (*prefix_decoder)(struct pt_ild *ild, uint8_t length, uint8_t rex); 560*74fe6c29SRuslan Bukin static prefix_decoder prefix_table[256]; 561*74fe6c29SRuslan Bukin 562*74fe6c29SRuslan Bukin static inline int prefix_decode(struct pt_ild *ild, uint8_t length, uint8_t rex) 563*74fe6c29SRuslan Bukin { 564*74fe6c29SRuslan Bukin uint8_t byte; 565*74fe6c29SRuslan Bukin 566*74fe6c29SRuslan Bukin if (!ild) 567*74fe6c29SRuslan Bukin return -pte_internal; 568*74fe6c29SRuslan Bukin 569*74fe6c29SRuslan Bukin if (ild->max_bytes <= length) 570*74fe6c29SRuslan Bukin return -pte_bad_insn; 571*74fe6c29SRuslan Bukin 572*74fe6c29SRuslan Bukin byte = get_byte(ild, length); 573*74fe6c29SRuslan Bukin 574*74fe6c29SRuslan Bukin return prefix_table[byte](ild, length, rex); 575*74fe6c29SRuslan Bukin } 576*74fe6c29SRuslan Bukin 577*74fe6c29SRuslan Bukin static inline int prefix_next(struct pt_ild *ild, uint8_t length, uint8_t rex) 578*74fe6c29SRuslan Bukin { 579*74fe6c29SRuslan Bukin return prefix_decode(ild, length + 1, rex); 580*74fe6c29SRuslan Bukin } 581*74fe6c29SRuslan Bukin 582*74fe6c29SRuslan Bukin static int prefix_osz(struct pt_ild *ild, uint8_t length, uint8_t rex) 583*74fe6c29SRuslan Bukin { 584*74fe6c29SRuslan Bukin (void) rex; 585*74fe6c29SRuslan Bukin 586*74fe6c29SRuslan Bukin if (!ild) 587*74fe6c29SRuslan Bukin return -pte_internal; 588*74fe6c29SRuslan Bukin 589*74fe6c29SRuslan Bukin ild->u.s.osz = 1; 590*74fe6c29SRuslan Bukin 591*74fe6c29SRuslan Bukin return prefix_next(ild, length, 0); 592*74fe6c29SRuslan Bukin } 593*74fe6c29SRuslan Bukin 594*74fe6c29SRuslan Bukin static int prefix_asz(struct pt_ild *ild, uint8_t length, uint8_t rex) 595*74fe6c29SRuslan Bukin { 596*74fe6c29SRuslan Bukin (void) rex; 597*74fe6c29SRuslan Bukin 598*74fe6c29SRuslan Bukin if (!ild) 599*74fe6c29SRuslan Bukin return -pte_internal; 600*74fe6c29SRuslan Bukin 601*74fe6c29SRuslan Bukin ild->u.s.asz = 1; 602*74fe6c29SRuslan Bukin 603*74fe6c29SRuslan Bukin return prefix_next(ild, length, 0); 604*74fe6c29SRuslan Bukin } 605*74fe6c29SRuslan Bukin 606*74fe6c29SRuslan Bukin static int prefix_lock(struct pt_ild *ild, uint8_t length, uint8_t rex) 607*74fe6c29SRuslan Bukin { 608*74fe6c29SRuslan Bukin (void) rex; 609*74fe6c29SRuslan Bukin 610*74fe6c29SRuslan Bukin if (!ild) 611*74fe6c29SRuslan Bukin return -pte_internal; 612*74fe6c29SRuslan Bukin 613*74fe6c29SRuslan Bukin ild->u.s.lock = 1; 614*74fe6c29SRuslan Bukin 615*74fe6c29SRuslan Bukin return prefix_next(ild, length, 0); 616*74fe6c29SRuslan Bukin } 617*74fe6c29SRuslan Bukin 618*74fe6c29SRuslan Bukin static int prefix_f2(struct pt_ild *ild, uint8_t length, uint8_t rex) 619*74fe6c29SRuslan Bukin { 620*74fe6c29SRuslan Bukin (void) rex; 621*74fe6c29SRuslan Bukin 622*74fe6c29SRuslan Bukin if (!ild) 623*74fe6c29SRuslan Bukin return -pte_internal; 624*74fe6c29SRuslan Bukin 625*74fe6c29SRuslan Bukin ild->u.s.f2 = 1; 626*74fe6c29SRuslan Bukin ild->u.s.last_f2f3 = 2; 627*74fe6c29SRuslan Bukin 628*74fe6c29SRuslan Bukin return prefix_next(ild, length, 0); 629*74fe6c29SRuslan Bukin } 630*74fe6c29SRuslan Bukin 631*74fe6c29SRuslan Bukin static int prefix_f3(struct pt_ild *ild, uint8_t length, uint8_t rex) 632*74fe6c29SRuslan Bukin { 633*74fe6c29SRuslan Bukin (void) rex; 634*74fe6c29SRuslan Bukin 635*74fe6c29SRuslan Bukin if (!ild) 636*74fe6c29SRuslan Bukin return -pte_internal; 637*74fe6c29SRuslan Bukin 638*74fe6c29SRuslan Bukin ild->u.s.f3 = 1; 639*74fe6c29SRuslan Bukin ild->u.s.last_f2f3 = 3; 640*74fe6c29SRuslan Bukin 641*74fe6c29SRuslan Bukin return prefix_next(ild, length, 0); 642*74fe6c29SRuslan Bukin } 643*74fe6c29SRuslan Bukin 644*74fe6c29SRuslan Bukin static int prefix_ignore(struct pt_ild *ild, uint8_t length, uint8_t rex) 645*74fe6c29SRuslan Bukin { 646*74fe6c29SRuslan Bukin (void) rex; 647*74fe6c29SRuslan Bukin 648*74fe6c29SRuslan Bukin return prefix_next(ild, length, 0); 649*74fe6c29SRuslan Bukin } 650*74fe6c29SRuslan Bukin 651*74fe6c29SRuslan Bukin static int prefix_done(struct pt_ild *ild, uint8_t length, uint8_t rex) 652*74fe6c29SRuslan Bukin { 653*74fe6c29SRuslan Bukin if (!ild) 654*74fe6c29SRuslan Bukin return -pte_internal; 655*74fe6c29SRuslan Bukin 656*74fe6c29SRuslan Bukin if (rex & 0x04) 657*74fe6c29SRuslan Bukin ild->u.s.rex_r = 1; 658*74fe6c29SRuslan Bukin if (rex & 0x08) 659*74fe6c29SRuslan Bukin ild->u.s.rex_w = 1; 660*74fe6c29SRuslan Bukin 661*74fe6c29SRuslan Bukin return opcode_dec(ild, length); 662*74fe6c29SRuslan Bukin } 663*74fe6c29SRuslan Bukin 664*74fe6c29SRuslan Bukin static int prefix_rex(struct pt_ild *ild, uint8_t length, uint8_t rex) 665*74fe6c29SRuslan Bukin { 666*74fe6c29SRuslan Bukin (void) rex; 667*74fe6c29SRuslan Bukin 668*74fe6c29SRuslan Bukin if (!ild) 669*74fe6c29SRuslan Bukin return -pte_internal; 670*74fe6c29SRuslan Bukin 671*74fe6c29SRuslan Bukin if (mode_64b(ild)) 672*74fe6c29SRuslan Bukin return prefix_next(ild, length, get_byte(ild, length)); 673*74fe6c29SRuslan Bukin else 674*74fe6c29SRuslan Bukin return opcode_dec(ild, length); 675*74fe6c29SRuslan Bukin } 676*74fe6c29SRuslan Bukin 677*74fe6c29SRuslan Bukin static inline int prefix_vex_done(struct pt_ild *ild, uint8_t length) 678*74fe6c29SRuslan Bukin { 679*74fe6c29SRuslan Bukin if (!ild) 680*74fe6c29SRuslan Bukin return -pte_internal; 681*74fe6c29SRuslan Bukin 682*74fe6c29SRuslan Bukin ild->nominal_opcode = get_byte(ild, length); 683*74fe6c29SRuslan Bukin 684*74fe6c29SRuslan Bukin return modrm_dec(ild, length + 1); 685*74fe6c29SRuslan Bukin } 686*74fe6c29SRuslan Bukin 687*74fe6c29SRuslan Bukin static int prefix_vex_c5(struct pt_ild *ild, uint8_t length, uint8_t rex) 688*74fe6c29SRuslan Bukin { 689*74fe6c29SRuslan Bukin uint8_t max_bytes; 690*74fe6c29SRuslan Bukin uint8_t p1; 691*74fe6c29SRuslan Bukin 692*74fe6c29SRuslan Bukin (void) rex; 693*74fe6c29SRuslan Bukin 694*74fe6c29SRuslan Bukin if (!ild) 695*74fe6c29SRuslan Bukin return -pte_internal; 696*74fe6c29SRuslan Bukin 697*74fe6c29SRuslan Bukin max_bytes = ild->max_bytes; 698*74fe6c29SRuslan Bukin 699*74fe6c29SRuslan Bukin /* Read the next byte to validate that this is indeed VEX. */ 700*74fe6c29SRuslan Bukin if (max_bytes <= (length + 1)) 701*74fe6c29SRuslan Bukin return -pte_bad_insn; 702*74fe6c29SRuslan Bukin 703*74fe6c29SRuslan Bukin p1 = get_byte(ild, length + 1); 704*74fe6c29SRuslan Bukin 705*74fe6c29SRuslan Bukin /* If p1[7:6] is not 11b in non-64-bit mode, this is LDS, not VEX. */ 706*74fe6c29SRuslan Bukin if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0)) 707*74fe6c29SRuslan Bukin return opcode_dec(ild, length); 708*74fe6c29SRuslan Bukin 709*74fe6c29SRuslan Bukin /* We need at least 3 bytes 710*74fe6c29SRuslan Bukin * - 2 for the VEX prefix and payload and 711*74fe6c29SRuslan Bukin * - 1 for the opcode. 712*74fe6c29SRuslan Bukin */ 713*74fe6c29SRuslan Bukin if (max_bytes < (length + 3)) 714*74fe6c29SRuslan Bukin return -pte_bad_insn; 715*74fe6c29SRuslan Bukin 716*74fe6c29SRuslan Bukin ild->u.s.vex = 1; 717*74fe6c29SRuslan Bukin if (p1 & 0x80) 718*74fe6c29SRuslan Bukin ild->u.s.rex_r = 1; 719*74fe6c29SRuslan Bukin 720*74fe6c29SRuslan Bukin ild->map = PTI_MAP_1; 721*74fe6c29SRuslan Bukin 722*74fe6c29SRuslan Bukin /* Eat the VEX. */ 723*74fe6c29SRuslan Bukin length += 2; 724*74fe6c29SRuslan Bukin return prefix_vex_done(ild, length); 725*74fe6c29SRuslan Bukin } 726*74fe6c29SRuslan Bukin 727*74fe6c29SRuslan Bukin static int prefix_vex_c4(struct pt_ild *ild, uint8_t length, uint8_t rex) 728*74fe6c29SRuslan Bukin { 729*74fe6c29SRuslan Bukin uint8_t max_bytes; 730*74fe6c29SRuslan Bukin uint8_t p1, p2, map; 731*74fe6c29SRuslan Bukin 732*74fe6c29SRuslan Bukin (void) rex; 733*74fe6c29SRuslan Bukin 734*74fe6c29SRuslan Bukin if (!ild) 735*74fe6c29SRuslan Bukin return -pte_internal; 736*74fe6c29SRuslan Bukin 737*74fe6c29SRuslan Bukin max_bytes = ild->max_bytes; 738*74fe6c29SRuslan Bukin 739*74fe6c29SRuslan Bukin /* Read the next byte to validate that this is indeed VEX. */ 740*74fe6c29SRuslan Bukin if (max_bytes <= (length + 1)) 741*74fe6c29SRuslan Bukin return -pte_bad_insn; 742*74fe6c29SRuslan Bukin 743*74fe6c29SRuslan Bukin p1 = get_byte(ild, length + 1); 744*74fe6c29SRuslan Bukin 745*74fe6c29SRuslan Bukin /* If p1[7:6] is not 11b in non-64-bit mode, this is LES, not VEX. */ 746*74fe6c29SRuslan Bukin if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0)) 747*74fe6c29SRuslan Bukin return opcode_dec(ild, length); 748*74fe6c29SRuslan Bukin 749*74fe6c29SRuslan Bukin /* We need at least 4 bytes 750*74fe6c29SRuslan Bukin * - 3 for the VEX prefix and payload and 751*74fe6c29SRuslan Bukin * - 1 for the opcode. 752*74fe6c29SRuslan Bukin */ 753*74fe6c29SRuslan Bukin if (max_bytes < (length + 4)) 754*74fe6c29SRuslan Bukin return -pte_bad_insn; 755*74fe6c29SRuslan Bukin 756*74fe6c29SRuslan Bukin p2 = get_byte(ild, length + 2); 757*74fe6c29SRuslan Bukin 758*74fe6c29SRuslan Bukin ild->u.s.vex = 1; 759*74fe6c29SRuslan Bukin if (p1 & 0x80) 760*74fe6c29SRuslan Bukin ild->u.s.rex_r = 1; 761*74fe6c29SRuslan Bukin if (p2 & 0x80) 762*74fe6c29SRuslan Bukin ild->u.s.rex_w = 1; 763*74fe6c29SRuslan Bukin 764*74fe6c29SRuslan Bukin map = p1 & 0x1f; 765*74fe6c29SRuslan Bukin if (PTI_MAP_INVALID <= map) 766*74fe6c29SRuslan Bukin return -pte_bad_insn; 767*74fe6c29SRuslan Bukin 768*74fe6c29SRuslan Bukin ild->map = map; 769*74fe6c29SRuslan Bukin if (map == PTI_MAP_3) 770*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 771*74fe6c29SRuslan Bukin 772*74fe6c29SRuslan Bukin /* Eat the VEX. */ 773*74fe6c29SRuslan Bukin length += 3; 774*74fe6c29SRuslan Bukin return prefix_vex_done(ild, length); 775*74fe6c29SRuslan Bukin } 776*74fe6c29SRuslan Bukin 777*74fe6c29SRuslan Bukin static int prefix_evex(struct pt_ild *ild, uint8_t length, uint8_t rex) 778*74fe6c29SRuslan Bukin { 779*74fe6c29SRuslan Bukin uint8_t max_bytes; 780*74fe6c29SRuslan Bukin uint8_t p1, p2, map; 781*74fe6c29SRuslan Bukin 782*74fe6c29SRuslan Bukin (void) rex; 783*74fe6c29SRuslan Bukin 784*74fe6c29SRuslan Bukin if (!ild) 785*74fe6c29SRuslan Bukin return -pte_internal; 786*74fe6c29SRuslan Bukin 787*74fe6c29SRuslan Bukin max_bytes = ild->max_bytes; 788*74fe6c29SRuslan Bukin 789*74fe6c29SRuslan Bukin /* Read the next byte to validate that this is indeed EVEX. */ 790*74fe6c29SRuslan Bukin if (max_bytes <= (length + 1)) 791*74fe6c29SRuslan Bukin return -pte_bad_insn; 792*74fe6c29SRuslan Bukin 793*74fe6c29SRuslan Bukin p1 = get_byte(ild, length + 1); 794*74fe6c29SRuslan Bukin 795*74fe6c29SRuslan Bukin /* If p1[7:6] is not 11b in non-64-bit mode, this is BOUND, not EVEX. */ 796*74fe6c29SRuslan Bukin if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0)) 797*74fe6c29SRuslan Bukin return opcode_dec(ild, length); 798*74fe6c29SRuslan Bukin 799*74fe6c29SRuslan Bukin /* We need at least 5 bytes 800*74fe6c29SRuslan Bukin * - 4 for the EVEX prefix and payload and 801*74fe6c29SRuslan Bukin * - 1 for the opcode. 802*74fe6c29SRuslan Bukin */ 803*74fe6c29SRuslan Bukin if (max_bytes < (length + 5)) 804*74fe6c29SRuslan Bukin return -pte_bad_insn; 805*74fe6c29SRuslan Bukin 806*74fe6c29SRuslan Bukin p2 = get_byte(ild, length + 2); 807*74fe6c29SRuslan Bukin 808*74fe6c29SRuslan Bukin ild->u.s.vex = 1; 809*74fe6c29SRuslan Bukin if (p1 & 0x80) 810*74fe6c29SRuslan Bukin ild->u.s.rex_r = 1; 811*74fe6c29SRuslan Bukin if (p2 & 0x80) 812*74fe6c29SRuslan Bukin ild->u.s.rex_w = 1; 813*74fe6c29SRuslan Bukin 814*74fe6c29SRuslan Bukin map = p1 & 0x03; 815*74fe6c29SRuslan Bukin ild->map = map; 816*74fe6c29SRuslan Bukin 817*74fe6c29SRuslan Bukin if (map == PTI_MAP_3) 818*74fe6c29SRuslan Bukin ild->imm1_bytes = 1; 819*74fe6c29SRuslan Bukin 820*74fe6c29SRuslan Bukin /* Eat the EVEX. */ 821*74fe6c29SRuslan Bukin length += 4; 822*74fe6c29SRuslan Bukin return prefix_vex_done(ild, length); 823*74fe6c29SRuslan Bukin } 824*74fe6c29SRuslan Bukin 825*74fe6c29SRuslan Bukin static void init_prefix_table(void) 826*74fe6c29SRuslan Bukin { 827*74fe6c29SRuslan Bukin unsigned int byte; 828*74fe6c29SRuslan Bukin 829*74fe6c29SRuslan Bukin for (byte = 0; byte <= 0xff; ++byte) 830*74fe6c29SRuslan Bukin prefix_table[byte] = prefix_done; 831*74fe6c29SRuslan Bukin 832*74fe6c29SRuslan Bukin prefix_table[0x66] = prefix_osz; 833*74fe6c29SRuslan Bukin prefix_table[0x67] = prefix_asz; 834*74fe6c29SRuslan Bukin 835*74fe6c29SRuslan Bukin /* Segment prefixes. */ 836*74fe6c29SRuslan Bukin prefix_table[0x2e] = prefix_ignore; 837*74fe6c29SRuslan Bukin prefix_table[0x3e] = prefix_ignore; 838*74fe6c29SRuslan Bukin prefix_table[0x26] = prefix_ignore; 839*74fe6c29SRuslan Bukin prefix_table[0x36] = prefix_ignore; 840*74fe6c29SRuslan Bukin prefix_table[0x64] = prefix_ignore; 841*74fe6c29SRuslan Bukin prefix_table[0x65] = prefix_ignore; 842*74fe6c29SRuslan Bukin 843*74fe6c29SRuslan Bukin prefix_table[0xf0] = prefix_lock; 844*74fe6c29SRuslan Bukin prefix_table[0xf2] = prefix_f2; 845*74fe6c29SRuslan Bukin prefix_table[0xf3] = prefix_f3; 846*74fe6c29SRuslan Bukin 847*74fe6c29SRuslan Bukin for (byte = 0x40; byte <= 0x4f; ++byte) 848*74fe6c29SRuslan Bukin prefix_table[byte] = prefix_rex; 849*74fe6c29SRuslan Bukin 850*74fe6c29SRuslan Bukin prefix_table[0xc4] = prefix_vex_c4; 851*74fe6c29SRuslan Bukin prefix_table[0xc5] = prefix_vex_c5; 852*74fe6c29SRuslan Bukin prefix_table[0x62] = prefix_evex; 853*74fe6c29SRuslan Bukin } 854*74fe6c29SRuslan Bukin 855*74fe6c29SRuslan Bukin static int decode(struct pt_ild *ild) 856*74fe6c29SRuslan Bukin { 857*74fe6c29SRuslan Bukin return prefix_decode(ild, 0, 0); 858*74fe6c29SRuslan Bukin } 859*74fe6c29SRuslan Bukin 860*74fe6c29SRuslan Bukin static int set_branch_target(struct pt_insn_ext *iext, const struct pt_ild *ild) 861*74fe6c29SRuslan Bukin { 862*74fe6c29SRuslan Bukin if (!iext || !ild) 863*74fe6c29SRuslan Bukin return -pte_internal; 864*74fe6c29SRuslan Bukin 865*74fe6c29SRuslan Bukin iext->variant.branch.is_direct = 1; 866*74fe6c29SRuslan Bukin 867*74fe6c29SRuslan Bukin if (ild->disp_bytes == 1) { 868*74fe6c29SRuslan Bukin const int8_t *b = (const int8_t *) 869*74fe6c29SRuslan Bukin get_byte_ptr(ild, ild->disp_pos); 870*74fe6c29SRuslan Bukin 871*74fe6c29SRuslan Bukin iext->variant.branch.displacement = *b; 872*74fe6c29SRuslan Bukin } else if (ild->disp_bytes == 2) { 873*74fe6c29SRuslan Bukin const int16_t *w = (const int16_t *) 874*74fe6c29SRuslan Bukin get_byte_ptr(ild, ild->disp_pos); 875*74fe6c29SRuslan Bukin 876*74fe6c29SRuslan Bukin iext->variant.branch.displacement = *w; 877*74fe6c29SRuslan Bukin } else if (ild->disp_bytes == 4) { 878*74fe6c29SRuslan Bukin const int32_t *d = (const int32_t *) 879*74fe6c29SRuslan Bukin get_byte_ptr(ild, ild->disp_pos); 880*74fe6c29SRuslan Bukin 881*74fe6c29SRuslan Bukin iext->variant.branch.displacement = *d; 882*74fe6c29SRuslan Bukin } else 883*74fe6c29SRuslan Bukin return -pte_bad_insn; 884*74fe6c29SRuslan Bukin 885*74fe6c29SRuslan Bukin return 0; 886*74fe6c29SRuslan Bukin } 887*74fe6c29SRuslan Bukin 888*74fe6c29SRuslan Bukin /* MAIN ENTRY POINTS */ 889*74fe6c29SRuslan Bukin 890*74fe6c29SRuslan Bukin void pt_ild_init(void) 891*74fe6c29SRuslan Bukin { /* initialization */ 892*74fe6c29SRuslan Bukin init_has_disp_regular_table(); 893*74fe6c29SRuslan Bukin init_has_sib_table(); 894*74fe6c29SRuslan Bukin init_eamode_table(); 895*74fe6c29SRuslan Bukin init_prefix_table(); 896*74fe6c29SRuslan Bukin } 897*74fe6c29SRuslan Bukin 898*74fe6c29SRuslan Bukin static int pt_instruction_length_decode(struct pt_ild *ild) 899*74fe6c29SRuslan Bukin { 900*74fe6c29SRuslan Bukin if (!ild) 901*74fe6c29SRuslan Bukin return -pte_internal; 902*74fe6c29SRuslan Bukin 903*74fe6c29SRuslan Bukin ild->u.i = 0; 904*74fe6c29SRuslan Bukin ild->imm1_bytes = 0; 905*74fe6c29SRuslan Bukin ild->imm2_bytes = 0; 906*74fe6c29SRuslan Bukin ild->disp_bytes = 0; 907*74fe6c29SRuslan Bukin ild->modrm_byte = 0; 908*74fe6c29SRuslan Bukin ild->map = PTI_MAP_INVALID; 909*74fe6c29SRuslan Bukin 910*74fe6c29SRuslan Bukin if (!ild->mode) 911*74fe6c29SRuslan Bukin return -pte_bad_insn; 912*74fe6c29SRuslan Bukin 913*74fe6c29SRuslan Bukin return decode(ild); 914*74fe6c29SRuslan Bukin } 915*74fe6c29SRuslan Bukin 916*74fe6c29SRuslan Bukin static int pt_instruction_decode(struct pt_insn *insn, struct pt_insn_ext *iext, 917*74fe6c29SRuslan Bukin const struct pt_ild *ild) 918*74fe6c29SRuslan Bukin { 919*74fe6c29SRuslan Bukin uint8_t opcode, map; 920*74fe6c29SRuslan Bukin 921*74fe6c29SRuslan Bukin if (!iext || !ild) 922*74fe6c29SRuslan Bukin return -pte_internal; 923*74fe6c29SRuslan Bukin 924*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_INVALID; 925*74fe6c29SRuslan Bukin memset(&iext->variant, 0, sizeof(iext->variant)); 926*74fe6c29SRuslan Bukin 927*74fe6c29SRuslan Bukin insn->iclass = ptic_other; 928*74fe6c29SRuslan Bukin 929*74fe6c29SRuslan Bukin opcode = ild->nominal_opcode; 930*74fe6c29SRuslan Bukin map = ild->map; 931*74fe6c29SRuslan Bukin 932*74fe6c29SRuslan Bukin if (map > PTI_MAP_1) 933*74fe6c29SRuslan Bukin return 0; /* uninteresting */ 934*74fe6c29SRuslan Bukin if (ild->u.s.vex) 935*74fe6c29SRuslan Bukin return 0; /* uninteresting */ 936*74fe6c29SRuslan Bukin 937*74fe6c29SRuslan Bukin /* PTI_INST_JCC, 70...7F, 0F (0x80...0x8F) */ 938*74fe6c29SRuslan Bukin if (opcode >= 0x70 && opcode <= 0x7F) { 939*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 940*74fe6c29SRuslan Bukin insn->iclass = ptic_cond_jump; 941*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JCC; 942*74fe6c29SRuslan Bukin 943*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 944*74fe6c29SRuslan Bukin } 945*74fe6c29SRuslan Bukin return 0; 946*74fe6c29SRuslan Bukin } 947*74fe6c29SRuslan Bukin if (opcode >= 0x80 && opcode <= 0x8F) { 948*74fe6c29SRuslan Bukin if (map == PTI_MAP_1) { 949*74fe6c29SRuslan Bukin insn->iclass = ptic_cond_jump; 950*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JCC; 951*74fe6c29SRuslan Bukin 952*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 953*74fe6c29SRuslan Bukin } 954*74fe6c29SRuslan Bukin return 0; 955*74fe6c29SRuslan Bukin } 956*74fe6c29SRuslan Bukin 957*74fe6c29SRuslan Bukin switch (ild->nominal_opcode) { 958*74fe6c29SRuslan Bukin case 0x9A: 959*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 960*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 961*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_CALL_9A; 962*74fe6c29SRuslan Bukin } 963*74fe6c29SRuslan Bukin return 0; 964*74fe6c29SRuslan Bukin 965*74fe6c29SRuslan Bukin case 0xFF: 966*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 967*74fe6c29SRuslan Bukin uint8_t reg = pti_get_modrm_reg(ild); 968*74fe6c29SRuslan Bukin 969*74fe6c29SRuslan Bukin if (reg == 2) { 970*74fe6c29SRuslan Bukin insn->iclass = ptic_call; 971*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_CALL_FFr2; 972*74fe6c29SRuslan Bukin } else if (reg == 3) { 973*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 974*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_CALL_FFr3; 975*74fe6c29SRuslan Bukin } else if (reg == 4) { 976*74fe6c29SRuslan Bukin insn->iclass = ptic_jump; 977*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JMP_FFr4; 978*74fe6c29SRuslan Bukin } else if (reg == 5) { 979*74fe6c29SRuslan Bukin insn->iclass = ptic_far_jump; 980*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JMP_FFr5; 981*74fe6c29SRuslan Bukin } 982*74fe6c29SRuslan Bukin } 983*74fe6c29SRuslan Bukin return 0; 984*74fe6c29SRuslan Bukin 985*74fe6c29SRuslan Bukin case 0xE8: 986*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 987*74fe6c29SRuslan Bukin insn->iclass = ptic_call; 988*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_CALL_E8; 989*74fe6c29SRuslan Bukin 990*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 991*74fe6c29SRuslan Bukin } 992*74fe6c29SRuslan Bukin return 0; 993*74fe6c29SRuslan Bukin 994*74fe6c29SRuslan Bukin case 0xCD: 995*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 996*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 997*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_INT; 998*74fe6c29SRuslan Bukin } 999*74fe6c29SRuslan Bukin 1000*74fe6c29SRuslan Bukin return 0; 1001*74fe6c29SRuslan Bukin 1002*74fe6c29SRuslan Bukin case 0xCC: 1003*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1004*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 1005*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_INT3; 1006*74fe6c29SRuslan Bukin } 1007*74fe6c29SRuslan Bukin 1008*74fe6c29SRuslan Bukin return 0; 1009*74fe6c29SRuslan Bukin 1010*74fe6c29SRuslan Bukin case 0xCE: 1011*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1012*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 1013*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_INTO; 1014*74fe6c29SRuslan Bukin } 1015*74fe6c29SRuslan Bukin 1016*74fe6c29SRuslan Bukin return 0; 1017*74fe6c29SRuslan Bukin 1018*74fe6c29SRuslan Bukin case 0xF1: 1019*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1020*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 1021*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_INT1; 1022*74fe6c29SRuslan Bukin } 1023*74fe6c29SRuslan Bukin 1024*74fe6c29SRuslan Bukin return 0; 1025*74fe6c29SRuslan Bukin 1026*74fe6c29SRuslan Bukin case 0xCF: 1027*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1028*74fe6c29SRuslan Bukin insn->iclass = ptic_far_return; 1029*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_IRET; 1030*74fe6c29SRuslan Bukin } 1031*74fe6c29SRuslan Bukin return 0; 1032*74fe6c29SRuslan Bukin 1033*74fe6c29SRuslan Bukin case 0xE9: 1034*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1035*74fe6c29SRuslan Bukin insn->iclass = ptic_jump; 1036*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JMP_E9; 1037*74fe6c29SRuslan Bukin 1038*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 1039*74fe6c29SRuslan Bukin } 1040*74fe6c29SRuslan Bukin return 0; 1041*74fe6c29SRuslan Bukin 1042*74fe6c29SRuslan Bukin case 0xEA: 1043*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1044*74fe6c29SRuslan Bukin /* Far jumps are treated as indirect jumps. */ 1045*74fe6c29SRuslan Bukin insn->iclass = ptic_far_jump; 1046*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JMP_EA; 1047*74fe6c29SRuslan Bukin } 1048*74fe6c29SRuslan Bukin return 0; 1049*74fe6c29SRuslan Bukin 1050*74fe6c29SRuslan Bukin case 0xEB: 1051*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1052*74fe6c29SRuslan Bukin insn->iclass = ptic_jump; 1053*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JMP_EB; 1054*74fe6c29SRuslan Bukin 1055*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 1056*74fe6c29SRuslan Bukin } 1057*74fe6c29SRuslan Bukin return 0; 1058*74fe6c29SRuslan Bukin 1059*74fe6c29SRuslan Bukin case 0xE3: 1060*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1061*74fe6c29SRuslan Bukin insn->iclass = ptic_cond_jump; 1062*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_JrCXZ; 1063*74fe6c29SRuslan Bukin 1064*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 1065*74fe6c29SRuslan Bukin } 1066*74fe6c29SRuslan Bukin return 0; 1067*74fe6c29SRuslan Bukin 1068*74fe6c29SRuslan Bukin case 0xE0: 1069*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1070*74fe6c29SRuslan Bukin insn->iclass = ptic_cond_jump; 1071*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_LOOPNE; 1072*74fe6c29SRuslan Bukin 1073*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 1074*74fe6c29SRuslan Bukin } 1075*74fe6c29SRuslan Bukin return 0; 1076*74fe6c29SRuslan Bukin 1077*74fe6c29SRuslan Bukin case 0xE1: 1078*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1079*74fe6c29SRuslan Bukin insn->iclass = ptic_cond_jump; 1080*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_LOOPE; 1081*74fe6c29SRuslan Bukin 1082*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 1083*74fe6c29SRuslan Bukin } 1084*74fe6c29SRuslan Bukin return 0; 1085*74fe6c29SRuslan Bukin 1086*74fe6c29SRuslan Bukin case 0xE2: 1087*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1088*74fe6c29SRuslan Bukin insn->iclass = ptic_cond_jump; 1089*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_LOOP; 1090*74fe6c29SRuslan Bukin 1091*74fe6c29SRuslan Bukin return set_branch_target(iext, ild); 1092*74fe6c29SRuslan Bukin } 1093*74fe6c29SRuslan Bukin return 0; 1094*74fe6c29SRuslan Bukin 1095*74fe6c29SRuslan Bukin case 0x22: 1096*74fe6c29SRuslan Bukin if (map == PTI_MAP_1) 1097*74fe6c29SRuslan Bukin if (pti_get_modrm_reg(ild) == 3) 1098*74fe6c29SRuslan Bukin if (!ild->u.s.rex_r) 1099*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_MOV_CR3; 1100*74fe6c29SRuslan Bukin 1101*74fe6c29SRuslan Bukin return 0; 1102*74fe6c29SRuslan Bukin 1103*74fe6c29SRuslan Bukin case 0xC3: 1104*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1105*74fe6c29SRuslan Bukin insn->iclass = ptic_return; 1106*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_RET_C3; 1107*74fe6c29SRuslan Bukin } 1108*74fe6c29SRuslan Bukin return 0; 1109*74fe6c29SRuslan Bukin 1110*74fe6c29SRuslan Bukin case 0xC2: 1111*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1112*74fe6c29SRuslan Bukin insn->iclass = ptic_return; 1113*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_RET_C2; 1114*74fe6c29SRuslan Bukin } 1115*74fe6c29SRuslan Bukin return 0; 1116*74fe6c29SRuslan Bukin 1117*74fe6c29SRuslan Bukin case 0xCB: 1118*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1119*74fe6c29SRuslan Bukin insn->iclass = ptic_far_return; 1120*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_RET_CB; 1121*74fe6c29SRuslan Bukin } 1122*74fe6c29SRuslan Bukin return 0; 1123*74fe6c29SRuslan Bukin 1124*74fe6c29SRuslan Bukin case 0xCA: 1125*74fe6c29SRuslan Bukin if (map == PTI_MAP_0) { 1126*74fe6c29SRuslan Bukin insn->iclass = ptic_far_return; 1127*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_RET_CA; 1128*74fe6c29SRuslan Bukin } 1129*74fe6c29SRuslan Bukin return 0; 1130*74fe6c29SRuslan Bukin 1131*74fe6c29SRuslan Bukin case 0x05: 1132*74fe6c29SRuslan Bukin if (map == PTI_MAP_1) { 1133*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 1134*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_SYSCALL; 1135*74fe6c29SRuslan Bukin } 1136*74fe6c29SRuslan Bukin return 0; 1137*74fe6c29SRuslan Bukin 1138*74fe6c29SRuslan Bukin case 0x34: 1139*74fe6c29SRuslan Bukin if (map == PTI_MAP_1) { 1140*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 1141*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_SYSENTER; 1142*74fe6c29SRuslan Bukin } 1143*74fe6c29SRuslan Bukin return 0; 1144*74fe6c29SRuslan Bukin 1145*74fe6c29SRuslan Bukin case 0x35: 1146*74fe6c29SRuslan Bukin if (map == PTI_MAP_1) { 1147*74fe6c29SRuslan Bukin insn->iclass = ptic_far_return; 1148*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_SYSEXIT; 1149*74fe6c29SRuslan Bukin } 1150*74fe6c29SRuslan Bukin return 0; 1151*74fe6c29SRuslan Bukin 1152*74fe6c29SRuslan Bukin case 0x07: 1153*74fe6c29SRuslan Bukin if (map == PTI_MAP_1) { 1154*74fe6c29SRuslan Bukin insn->iclass = ptic_far_return; 1155*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_SYSRET; 1156*74fe6c29SRuslan Bukin } 1157*74fe6c29SRuslan Bukin return 0; 1158*74fe6c29SRuslan Bukin 1159*74fe6c29SRuslan Bukin case 0x01: 1160*74fe6c29SRuslan Bukin if (map == PTI_MAP_1) { 1161*74fe6c29SRuslan Bukin switch (ild->modrm_byte) { 1162*74fe6c29SRuslan Bukin case 0xc1: 1163*74fe6c29SRuslan Bukin insn->iclass = ptic_far_call; 1164*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_VMCALL; 1165*74fe6c29SRuslan Bukin break; 1166*74fe6c29SRuslan Bukin 1167*74fe6c29SRuslan Bukin case 0xc2: 1168*74fe6c29SRuslan Bukin insn->iclass = ptic_far_return; 1169*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_VMLAUNCH; 1170*74fe6c29SRuslan Bukin break; 1171*74fe6c29SRuslan Bukin 1172*74fe6c29SRuslan Bukin case 0xc3: 1173*74fe6c29SRuslan Bukin insn->iclass = ptic_far_return; 1174*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_VMRESUME; 1175*74fe6c29SRuslan Bukin break; 1176*74fe6c29SRuslan Bukin 1177*74fe6c29SRuslan Bukin default: 1178*74fe6c29SRuslan Bukin break; 1179*74fe6c29SRuslan Bukin } 1180*74fe6c29SRuslan Bukin } 1181*74fe6c29SRuslan Bukin return 0; 1182*74fe6c29SRuslan Bukin 1183*74fe6c29SRuslan Bukin case 0xc7: 1184*74fe6c29SRuslan Bukin if (map == PTI_MAP_1 && 1185*74fe6c29SRuslan Bukin pti_get_modrm_mod(ild) != 3 && 1186*74fe6c29SRuslan Bukin pti_get_modrm_reg(ild) == 6) 1187*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_VMPTRLD; 1188*74fe6c29SRuslan Bukin 1189*74fe6c29SRuslan Bukin return 0; 1190*74fe6c29SRuslan Bukin 1191*74fe6c29SRuslan Bukin case 0xae: 1192*74fe6c29SRuslan Bukin if (map == PTI_MAP_1 && ild->u.s.f3 && !ild->u.s.osz && 1193*74fe6c29SRuslan Bukin pti_get_modrm_reg(ild) == 4) { 1194*74fe6c29SRuslan Bukin insn->iclass = ptic_ptwrite; 1195*74fe6c29SRuslan Bukin iext->iclass = PTI_INST_PTWRITE; 1196*74fe6c29SRuslan Bukin } 1197*74fe6c29SRuslan Bukin return 0; 1198*74fe6c29SRuslan Bukin 1199*74fe6c29SRuslan Bukin default: 1200*74fe6c29SRuslan Bukin return 0; 1201*74fe6c29SRuslan Bukin } 1202*74fe6c29SRuslan Bukin } 1203*74fe6c29SRuslan Bukin 1204*74fe6c29SRuslan Bukin int pt_ild_decode(struct pt_insn *insn, struct pt_insn_ext *iext) 1205*74fe6c29SRuslan Bukin { 1206*74fe6c29SRuslan Bukin struct pt_ild ild; 1207*74fe6c29SRuslan Bukin int size; 1208*74fe6c29SRuslan Bukin 1209*74fe6c29SRuslan Bukin if (!insn || !iext) 1210*74fe6c29SRuslan Bukin return -pte_internal; 1211*74fe6c29SRuslan Bukin 1212*74fe6c29SRuslan Bukin ild.mode = insn->mode; 1213*74fe6c29SRuslan Bukin ild.itext = insn->raw; 1214*74fe6c29SRuslan Bukin ild.max_bytes = insn->size; 1215*74fe6c29SRuslan Bukin 1216*74fe6c29SRuslan Bukin size = pt_instruction_length_decode(&ild); 1217*74fe6c29SRuslan Bukin if (size < 0) 1218*74fe6c29SRuslan Bukin return size; 1219*74fe6c29SRuslan Bukin 1220*74fe6c29SRuslan Bukin insn->size = (uint8_t) size; 1221*74fe6c29SRuslan Bukin 1222*74fe6c29SRuslan Bukin return pt_instruction_decode(insn, iext, &ild); 1223*74fe6c29SRuslan Bukin } 1224