blob: a46be75b00863b6024ae21b2726e3f2806ff1437 [file] [log] [blame]
bellard2c0262a2003-09-30 20:34:21 +00001/*
2 * i386 translation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard2c0262a2003-09-30 20:34:21 +00004 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
Chetan Pantd9ff33a2020-10-23 12:28:01 +00009 * version 2.1 of the License, or (at your option) any later version.
bellard2c0262a2003-09-30 20:34:21 +000010 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard2c0262a2003-09-30 20:34:21 +000018 */
Peter Maydellb6a0aa02016-01-26 18:17:03 +000019#include "qemu/osdep.h"
bellard2c0262a2003-09-30 20:34:21 +000020
Richard Hendersonbec93d72013-01-23 14:21:52 -080021#include "qemu/host-utils.h"
bellard2c0262a2003-09-30 20:34:21 +000022#include "cpu.h"
Paolo Bonzini76cad712012-10-24 11:12:21 +020023#include "disas/disas.h"
Paolo Bonzini63c91552016-03-15 13:18:37 +010024#include "exec/exec-all.h"
Philippe Mathieu-Daudédcb32f12020-01-01 12:23:00 +010025#include "tcg/tcg-op.h"
Paolo Bonzinif08b6172014-03-28 19:42:10 +010026#include "exec/cpu_ldst.h"
Lluís Vilanova77fc6f52017-07-14 11:21:37 +030027#include "exec/translator.h"
bellard2c0262a2003-09-30 20:34:21 +000028
Richard Henderson2ef61752014-04-07 22:31:41 -070029#include "exec/helper-proto.h"
30#include "exec/helper-gen.h"
Claudio Fontanaed69e832020-12-12 16:55:14 +010031#include "helper-tcg.h"
pbrooka7812ae2008-11-17 14:43:54 +000032
Paolo Bonzini508127e2016-01-07 16:55:28 +030033#include "exec/log.h"
Lluís Vilanovaa7e30d82014-05-30 14:12:25 +020034
bellard2c0262a2003-09-30 20:34:21 +000035#define PREFIX_REPZ 0x01
36#define PREFIX_REPNZ 0x02
37#define PREFIX_LOCK 0x04
38#define PREFIX_DATA 0x08
39#define PREFIX_ADR 0x10
Richard Henderson701ed212013-01-11 11:35:02 -080040#define PREFIX_VEX 0x20
Richard Henderson1e92b722021-05-14 10:13:07 -050041#define PREFIX_REX 0x40
bellard2c0262a2003-09-30 20:34:21 +000042
bellard14ce26e2005-01-03 23:50:08 +000043#ifdef TARGET_X86_64
Richard Hendersonbec93d72013-01-23 14:21:52 -080044# define ctztl ctz64
45# define clztl clz64
46#else
47# define ctztl ctz32
48# define clztl clz32
49#endif
50
Richard Henderson1906b2a2015-07-02 13:59:21 +010051/* For a switch indexed by MODRM, match all memory operands for a given OP. */
Paolo Bonzini880f8482016-03-01 16:12:14 +010052#define CASE_MODRM_MEM_OP(OP) \
Richard Henderson1906b2a2015-07-02 13:59:21 +010053 case (0 << 6) | (OP << 3) | 0 ... (0 << 6) | (OP << 3) | 7: \
54 case (1 << 6) | (OP << 3) | 0 ... (1 << 6) | (OP << 3) | 7: \
55 case (2 << 6) | (OP << 3) | 0 ... (2 << 6) | (OP << 3) | 7
56
Paolo Bonzini880f8482016-03-01 16:12:14 +010057#define CASE_MODRM_OP(OP) \
58 case (0 << 6) | (OP << 3) | 0 ... (0 << 6) | (OP << 3) | 7: \
59 case (1 << 6) | (OP << 3) | 0 ... (1 << 6) | (OP << 3) | 7: \
60 case (2 << 6) | (OP << 3) | 0 ... (2 << 6) | (OP << 3) | 7: \
61 case (3 << 6) | (OP << 3) | 0 ... (3 << 6) | (OP << 3) | 7
62
bellard57fec1f2008-02-01 10:50:11 +000063//#define MACRO_TEST 1
64
bellard57fec1f2008-02-01 10:50:11 +000065/* global register indexes */
Emilio G. Cota93a3e102018-09-11 14:38:47 -040066static TCGv cpu_cc_dst, cpu_cc_src, cpu_cc_src2;
pbrooka7812ae2008-11-17 14:43:54 +000067static TCGv_i32 cpu_cc_op;
Laurent Desnoguescc739bb2009-09-29 11:58:04 +020068static TCGv cpu_regs[CPU_NB_REGS];
Richard Henderson3558f802015-12-17 11:19:21 -080069static TCGv cpu_seg_base[6];
Richard Henderson149b4272015-07-09 08:22:46 +010070static TCGv_i64 cpu_bndl[4];
71static TCGv_i64 cpu_bndu[4];
Emilio G. Cotafbd80f02018-09-11 14:07:57 -040072
Paolo Bonzini022c62c2012-12-17 18:19:49 +010073#include "exec/gen-icount.h"
pbrook2e70f6e2008-06-29 01:03:05 +000074
bellard2c0262a2003-09-30 20:34:21 +000075typedef struct DisasContext {
Lluís Vilanova6cf147a2017-07-14 11:29:42 +030076 DisasContextBase base;
77
Richard Hendersona6f62102021-05-14 10:13:20 -050078 target_ulong pc; /* pc = eip + cs_base */
79 target_ulong pc_start; /* pc at TB entry */
80 target_ulong cs_base; /* base of CS segment */
81
Tony Nguyen14776ab2019-08-24 04:10:58 +100082 MemOp aflag;
83 MemOp dflag;
Richard Hendersona6f62102021-05-14 10:13:20 -050084
85 int8_t override; /* -1 if no override, else R_CS, R_DS, etc */
86 uint8_t prefix;
Richard Henderson01b9d8c2021-05-14 10:12:59 -050087
88#ifndef CONFIG_USER_ONLY
89 uint8_t cpl; /* code priv level */
Richard Henderson0ab011c2021-05-14 10:13:00 -050090 uint8_t iopl; /* i/o priv level */
Richard Henderson01b9d8c2021-05-14 10:12:59 -050091#endif
Richard Hendersona6f62102021-05-14 10:13:20 -050092 uint8_t vex_l; /* vex vector length */
93 uint8_t vex_v; /* vex vvvv register, without 1's complement. */
94 uint8_t popl_esp_hack; /* for correct popl with esp base handling */
95 uint8_t rip_offset; /* only used in x86_64, but left for simplicity */
Richard Henderson01b9d8c2021-05-14 10:12:59 -050096
bellard14ce26e2005-01-03 23:50:08 +000097#ifdef TARGET_X86_64
Richard Hendersonbbdb4232021-05-14 10:13:09 -050098 uint8_t rex_r;
Richard Henderson915ffe82021-05-14 10:13:08 -050099 uint8_t rex_x;
100 uint8_t rex_b;
Richard Henderson8ab1e482021-05-14 10:13:10 -0500101 bool rex_w;
bellard14ce26e2005-01-03 23:50:08 +0000102#endif
Richard Henderson305d08e2021-05-14 10:13:18 -0500103 bool jmp_opt; /* use direct block chaining for direct jumps */
104 bool repz_opt; /* optimize jumps within repz instructions */
Richard Hendersona6f62102021-05-14 10:13:20 -0500105 bool cc_op_dirty;
106
107 CCOp cc_op; /* current CC operation */
bellard2c0262a2003-09-30 20:34:21 +0000108 int mem_index; /* select memory access functions */
Richard Hendersonc6ad6f42021-05-14 10:13:12 -0500109 uint32_t flags; /* all execution flags */
bellard14ce26e2005-01-03 23:50:08 +0000110 int cpuid_features;
bellard3d7374c2006-07-10 19:53:04 +0000111 int cpuid_ext_features;
aurel32e771eda2008-04-09 06:41:37 +0000112 int cpuid_ext2_features;
bellard12e26b72008-05-22 10:13:38 +0000113 int cpuid_ext3_features;
H. Peter Anvina9321a42012-09-26 13:18:43 -0700114 int cpuid_7_0_ebx_features;
Richard Hendersonc9cfe8f2015-07-02 15:21:23 +0100115 int cpuid_xsave_features;
Emilio G. Cota93a3e102018-09-11 14:38:47 -0400116
117 /* TCG local temps */
118 TCGv cc_srcT;
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400119 TCGv A0;
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400120 TCGv T0;
Emilio G. Cotab48597b2018-09-11 14:50:46 -0400121 TCGv T1;
Emilio G. Cota93a3e102018-09-11 14:38:47 -0400122
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400123 /* TCG local register indexes (only used inside old micro ops) */
124 TCGv tmp0;
Emilio G. Cota5022f282018-09-11 14:10:21 -0400125 TCGv tmp4;
Emilio G. Cota2ee26462018-09-11 14:11:35 -0400126 TCGv_ptr ptr0;
Emilio G. Cota6387e832018-09-11 14:14:06 -0400127 TCGv_ptr ptr1;
Emilio G. Cota6bd48f62018-09-11 14:17:18 -0400128 TCGv_i32 tmp2_i32;
Emilio G. Cota4f824462018-09-11 14:17:56 -0400129 TCGv_i32 tmp3_i32;
Emilio G. Cota776678b2018-09-11 14:22:31 -0400130 TCGv_i64 tmp1_i64;
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400131
Paolo Bonzinib066c532017-03-22 11:57:10 +0100132 sigjmp_buf jmpbuf;
bellard2c0262a2003-09-30 20:34:21 +0000133} DisasContext;
134
Richard Hendersond75f9122021-05-14 10:12:58 -0500135/* The environment in which user-only runs is constrained. */
136#ifdef CONFIG_USER_ONLY
137#define PE(S) true
Richard Henderson01b9d8c2021-05-14 10:12:59 -0500138#define CPL(S) 3
Richard Henderson0ab011c2021-05-14 10:13:00 -0500139#define IOPL(S) 0
Richard Henderson5d223882021-05-14 10:13:22 -0500140#define SVME(S) false
Richard Hendersonb322b3a2021-05-14 10:13:23 -0500141#define GUEST(S) false
Richard Hendersond75f9122021-05-14 10:12:58 -0500142#else
143#define PE(S) (((S)->flags & HF_PE_MASK) != 0)
Richard Henderson01b9d8c2021-05-14 10:12:59 -0500144#define CPL(S) ((S)->cpl)
Richard Henderson0ab011c2021-05-14 10:13:00 -0500145#define IOPL(S) ((S)->iopl)
Richard Henderson5d223882021-05-14 10:13:22 -0500146#define SVME(S) (((S)->flags & HF_SVME_MASK) != 0)
Richard Hendersonb322b3a2021-05-14 10:13:23 -0500147#define GUEST(S) (((S)->flags & HF_GUEST_MASK) != 0)
Richard Hendersond75f9122021-05-14 10:12:58 -0500148#endif
Richard Hendersonf8a35842021-05-14 10:13:01 -0500149#if defined(CONFIG_USER_ONLY) && defined(TARGET_X86_64)
150#define VM86(S) false
Richard Henderson9996dcf2021-05-14 10:13:02 -0500151#define CODE32(S) true
Richard Hendersonb40a47a2021-05-14 10:13:03 -0500152#define SS32(S) true
Richard Hendersonbeedb932021-05-14 10:13:06 -0500153#define ADDSEG(S) false
Richard Hendersonf8a35842021-05-14 10:13:01 -0500154#else
155#define VM86(S) (((S)->flags & HF_VM_MASK) != 0)
Richard Henderson9996dcf2021-05-14 10:13:02 -0500156#define CODE32(S) (((S)->flags & HF_CS32_MASK) != 0)
Richard Hendersonb40a47a2021-05-14 10:13:03 -0500157#define SS32(S) (((S)->flags & HF_SS32_MASK) != 0)
Richard Hendersonbeedb932021-05-14 10:13:06 -0500158#define ADDSEG(S) (((S)->flags & HF_ADDSEG_MASK) != 0)
Richard Hendersonf8a35842021-05-14 10:13:01 -0500159#endif
Richard Hendersoneec7d0f2021-05-14 10:13:04 -0500160#if !defined(TARGET_X86_64)
161#define CODE64(S) false
Richard Henderson73e90dc2021-05-14 10:13:05 -0500162#define LMA(S) false
Richard Hendersoneec7d0f2021-05-14 10:13:04 -0500163#elif defined(CONFIG_USER_ONLY)
164#define CODE64(S) true
Richard Henderson73e90dc2021-05-14 10:13:05 -0500165#define LMA(S) true
Richard Hendersoneec7d0f2021-05-14 10:13:04 -0500166#else
167#define CODE64(S) (((S)->flags & HF_CS64_MASK) != 0)
Richard Henderson73e90dc2021-05-14 10:13:05 -0500168#define LMA(S) (((S)->flags & HF_LMA_MASK) != 0)
Richard Hendersoneec7d0f2021-05-14 10:13:04 -0500169#endif
Richard Hendersond75f9122021-05-14 10:12:58 -0500170
Richard Henderson1e92b722021-05-14 10:13:07 -0500171#ifdef TARGET_X86_64
172#define REX_PREFIX(S) (((S)->prefix & PREFIX_REX) != 0)
Richard Henderson8ab1e482021-05-14 10:13:10 -0500173#define REX_W(S) ((S)->rex_w)
Richard Hendersonbbdb4232021-05-14 10:13:09 -0500174#define REX_R(S) ((S)->rex_r + 0)
Richard Henderson915ffe82021-05-14 10:13:08 -0500175#define REX_X(S) ((S)->rex_x + 0)
176#define REX_B(S) ((S)->rex_b + 0)
Richard Henderson1e92b722021-05-14 10:13:07 -0500177#else
178#define REX_PREFIX(S) false
Richard Henderson8ab1e482021-05-14 10:13:10 -0500179#define REX_W(S) false
Richard Hendersonbbdb4232021-05-14 10:13:09 -0500180#define REX_R(S) 0
Richard Henderson915ffe82021-05-14 10:13:08 -0500181#define REX_X(S) 0
182#define REX_B(S) 0
Richard Henderson1e92b722021-05-14 10:13:07 -0500183#endif
184
Richard Henderson9f55e5a2021-05-14 10:13:21 -0500185/*
186 * Many sysemu-only helpers are not reachable for user-only.
187 * Define stub generators here, so that we need not either sprinkle
188 * ifdefs through the translator, nor provide the helper function.
189 */
190#define STUB_HELPER(NAME, ...) \
191 static inline void gen_helper_##NAME(__VA_ARGS__) \
192 { qemu_build_not_reached(); }
193
194#ifdef CONFIG_USER_ONLY
Richard Henderson8d6806c2021-05-14 10:13:25 -0500195STUB_HELPER(clgi, TCGv_env env)
Richard Henderson35e5a5d2021-05-14 10:13:34 -0500196STUB_HELPER(flush_page, TCGv_env env, TCGv addr)
Richard Henderson4ea24492021-05-14 10:13:33 -0500197STUB_HELPER(hlt, TCGv_env env, TCGv_i32 pc_ofs)
Richard Henderson7fb7c422021-05-14 10:13:42 -0500198STUB_HELPER(inb, TCGv ret, TCGv_env env, TCGv_i32 port)
199STUB_HELPER(inw, TCGv ret, TCGv_env env, TCGv_i32 port)
200STUB_HELPER(inl, TCGv ret, TCGv_env env, TCGv_i32 port)
Richard Henderson4ea24492021-05-14 10:13:33 -0500201STUB_HELPER(monitor, TCGv_env env, TCGv addr)
202STUB_HELPER(mwait, TCGv_env env, TCGv_i32 pc_ofs)
Richard Henderson7fb7c422021-05-14 10:13:42 -0500203STUB_HELPER(outb, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
204STUB_HELPER(outw, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
205STUB_HELPER(outl, TCGv_env env, TCGv_i32 port, TCGv_i32 val)
Richard Hendersonf7803b72021-05-14 10:13:36 -0500206STUB_HELPER(rdmsr, TCGv_env env)
207STUB_HELPER(read_crN, TCGv ret, TCGv_env env, TCGv_i32 reg)
Paolo Bonzini533883f2021-07-06 17:53:29 +0200208STUB_HELPER(get_dr, TCGv ret, TCGv_env env, TCGv_i32 reg)
Richard Henderson9f55e5a2021-05-14 10:13:21 -0500209STUB_HELPER(set_dr, TCGv_env env, TCGv_i32 reg, TCGv val)
Richard Henderson8d6806c2021-05-14 10:13:25 -0500210STUB_HELPER(stgi, TCGv_env env)
Richard Hendersond051ea02021-05-14 10:13:28 -0500211STUB_HELPER(svm_check_intercept, TCGv_env env, TCGv_i32 type)
Richard Henderson8d6806c2021-05-14 10:13:25 -0500212STUB_HELPER(vmload, TCGv_env env, TCGv_i32 aflag)
213STUB_HELPER(vmmcall, TCGv_env env)
214STUB_HELPER(vmrun, TCGv_env env, TCGv_i32 aflag, TCGv_i32 pc_ofs)
215STUB_HELPER(vmsave, TCGv_env env, TCGv_i32 aflag)
Richard Hendersonf7803b72021-05-14 10:13:36 -0500216STUB_HELPER(write_crN, TCGv_env env, TCGv_i32 reg, TCGv val)
217STUB_HELPER(wrmsr, TCGv_env env)
Richard Henderson9f55e5a2021-05-14 10:13:21 -0500218#endif
219
bellard2c0262a2003-09-30 20:34:21 +0000220static void gen_eob(DisasContext *s);
Emilio G. Cota1ebb1af2017-04-26 23:29:21 -0400221static void gen_jr(DisasContext *s, TCGv dest);
bellard14ce26e2005-01-03 23:50:08 +0000222static void gen_jmp(DisasContext *s, target_ulong eip);
223static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
Tony Nguyen14776ab2019-08-24 04:10:58 +1000224static void gen_op(DisasContext *s1, int op, MemOp ot, int d);
Richard Hendersond76b9c62021-05-14 10:13:41 -0500225static void gen_exception_gpf(DisasContext *s);
bellard2c0262a2003-09-30 20:34:21 +0000226
227/* i386 arith/logic operations */
228enum {
ths5fafdf22007-09-16 21:08:06 +0000229 OP_ADDL,
230 OP_ORL,
231 OP_ADCL,
bellard2c0262a2003-09-30 20:34:21 +0000232 OP_SBBL,
ths5fafdf22007-09-16 21:08:06 +0000233 OP_ANDL,
234 OP_SUBL,
235 OP_XORL,
bellard2c0262a2003-09-30 20:34:21 +0000236 OP_CMPL,
237};
238
239/* i386 shift ops */
240enum {
ths5fafdf22007-09-16 21:08:06 +0000241 OP_ROL,
242 OP_ROR,
243 OP_RCL,
244 OP_RCR,
245 OP_SHL,
246 OP_SHR,
bellard2c0262a2003-09-30 20:34:21 +0000247 OP_SHL1, /* undocumented */
248 OP_SAR = 7,
249};
250
bellard8e1c85e2008-05-21 19:16:45 +0000251enum {
252 JCC_O,
253 JCC_B,
254 JCC_Z,
255 JCC_BE,
256 JCC_S,
257 JCC_P,
258 JCC_L,
259 JCC_LE,
260};
261
bellard2c0262a2003-09-30 20:34:21 +0000262enum {
263 /* I386 int registers */
264 OR_EAX, /* MUST be even numbered */
265 OR_ECX,
266 OR_EDX,
267 OR_EBX,
268 OR_ESP,
269 OR_EBP,
270 OR_ESI,
271 OR_EDI,
bellard14ce26e2005-01-03 23:50:08 +0000272
273 OR_TMP0 = 16, /* temporary operand register */
bellard2c0262a2003-09-30 20:34:21 +0000274 OR_TMP1,
275 OR_A0, /* temporary register used when doing address evaluation */
bellard2c0262a2003-09-30 20:34:21 +0000276};
277
Richard Hendersonb6662652013-01-23 13:26:38 -0800278enum {
Richard Hendersona3251182013-01-23 15:43:03 -0800279 USES_CC_DST = 1,
280 USES_CC_SRC = 2,
Richard Henderson988c3eb2013-01-23 16:03:16 -0800281 USES_CC_SRC2 = 4,
282 USES_CC_SRCT = 8,
Richard Hendersonb6662652013-01-23 13:26:38 -0800283};
284
285/* Bit set if the global variable is live after setting CC_OP to X. */
286static const uint8_t cc_op_live[CC_OP_NB] = {
Richard Henderson988c3eb2013-01-23 16:03:16 -0800287 [CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
Richard Hendersonb6662652013-01-23 13:26:38 -0800288 [CC_OP_EFLAGS] = USES_CC_SRC,
289 [CC_OP_MULB ... CC_OP_MULQ] = USES_CC_DST | USES_CC_SRC,
290 [CC_OP_ADDB ... CC_OP_ADDQ] = USES_CC_DST | USES_CC_SRC,
Richard Henderson988c3eb2013-01-23 16:03:16 -0800291 [CC_OP_ADCB ... CC_OP_ADCQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
Richard Hendersona3251182013-01-23 15:43:03 -0800292 [CC_OP_SUBB ... CC_OP_SUBQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRCT,
Richard Henderson988c3eb2013-01-23 16:03:16 -0800293 [CC_OP_SBBB ... CC_OP_SBBQ] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
Richard Hendersonb6662652013-01-23 13:26:38 -0800294 [CC_OP_LOGICB ... CC_OP_LOGICQ] = USES_CC_DST,
295 [CC_OP_INCB ... CC_OP_INCQ] = USES_CC_DST | USES_CC_SRC,
296 [CC_OP_DECB ... CC_OP_DECQ] = USES_CC_DST | USES_CC_SRC,
297 [CC_OP_SHLB ... CC_OP_SHLQ] = USES_CC_DST | USES_CC_SRC,
298 [CC_OP_SARB ... CC_OP_SARQ] = USES_CC_DST | USES_CC_SRC,
Richard Hendersonbc4b43d2013-01-23 16:44:37 -0800299 [CC_OP_BMILGB ... CC_OP_BMILGQ] = USES_CC_DST | USES_CC_SRC,
Richard Hendersoncd7f97c2013-01-23 18:17:33 -0800300 [CC_OP_ADCX] = USES_CC_DST | USES_CC_SRC,
301 [CC_OP_ADOX] = USES_CC_SRC | USES_CC_SRC2,
302 [CC_OP_ADCOX] = USES_CC_DST | USES_CC_SRC | USES_CC_SRC2,
Richard Henderson436ff2d2013-01-29 13:38:43 -0800303 [CC_OP_CLR] = 0,
Richard Henderson4885c3c2016-11-21 12:18:53 +0100304 [CC_OP_POPCNT] = USES_CC_SRC,
Richard Hendersonb6662652013-01-23 13:26:38 -0800305};
306
Richard Hendersone2075822013-01-23 12:34:26 -0800307static void set_cc_op(DisasContext *s, CCOp op)
Richard Henderson3ca51d02013-01-23 12:30:52 -0800308{
Richard Hendersonb6662652013-01-23 13:26:38 -0800309 int dead;
310
311 if (s->cc_op == op) {
312 return;
Richard Hendersone2075822013-01-23 12:34:26 -0800313 }
Richard Hendersonb6662652013-01-23 13:26:38 -0800314
315 /* Discard CC computation that will no longer be used. */
316 dead = cc_op_live[s->cc_op] & ~cc_op_live[op];
317 if (dead & USES_CC_DST) {
318 tcg_gen_discard_tl(cpu_cc_dst);
319 }
320 if (dead & USES_CC_SRC) {
321 tcg_gen_discard_tl(cpu_cc_src);
322 }
Richard Henderson988c3eb2013-01-23 16:03:16 -0800323 if (dead & USES_CC_SRC2) {
324 tcg_gen_discard_tl(cpu_cc_src2);
325 }
Richard Hendersona3251182013-01-23 15:43:03 -0800326 if (dead & USES_CC_SRCT) {
Emilio G. Cota93a3e102018-09-11 14:38:47 -0400327 tcg_gen_discard_tl(s->cc_srcT);
Richard Hendersona3251182013-01-23 15:43:03 -0800328 }
Richard Hendersonb6662652013-01-23 13:26:38 -0800329
Richard Hendersone2f515c2013-02-19 14:48:43 -0800330 if (op == CC_OP_DYNAMIC) {
331 /* The DYNAMIC setting is translator only, and should never be
332 stored. Thus we always consider it clean. */
333 s->cc_op_dirty = false;
334 } else {
335 /* Discard any computed CC_OP value (see shifts). */
336 if (s->cc_op == CC_OP_DYNAMIC) {
337 tcg_gen_discard_i32(cpu_cc_op);
338 }
339 s->cc_op_dirty = true;
340 }
Richard Hendersonb6662652013-01-23 13:26:38 -0800341 s->cc_op = op;
Richard Hendersone2075822013-01-23 12:34:26 -0800342}
343
Richard Hendersone2075822013-01-23 12:34:26 -0800344static void gen_update_cc_op(DisasContext *s)
345{
346 if (s->cc_op_dirty) {
Richard Henderson773cdfc2013-01-23 12:43:12 -0800347 tcg_gen_movi_i32(cpu_cc_op, s->cc_op);
Richard Hendersone2075822013-01-23 12:34:26 -0800348 s->cc_op_dirty = false;
349 }
Richard Henderson3ca51d02013-01-23 12:30:52 -0800350}
351
bellard14ce26e2005-01-03 23:50:08 +0000352#ifdef TARGET_X86_64
353
354#define NB_OP_SIZES 4
355
bellard14ce26e2005-01-03 23:50:08 +0000356#else /* !TARGET_X86_64 */
357
358#define NB_OP_SIZES 3
359
bellard14ce26e2005-01-03 23:50:08 +0000360#endif /* !TARGET_X86_64 */
361
Juan Quintelae2542fe2009-07-27 16:13:06 +0200362#if defined(HOST_WORDS_BIGENDIAN)
bellard57fec1f2008-02-01 10:50:11 +0000363#define REG_B_OFFSET (sizeof(target_ulong) - 1)
364#define REG_H_OFFSET (sizeof(target_ulong) - 2)
365#define REG_W_OFFSET (sizeof(target_ulong) - 2)
366#define REG_L_OFFSET (sizeof(target_ulong) - 4)
367#define REG_LH_OFFSET (sizeof(target_ulong) - 8)
bellard14ce26e2005-01-03 23:50:08 +0000368#else
bellard57fec1f2008-02-01 10:50:11 +0000369#define REG_B_OFFSET 0
370#define REG_H_OFFSET 1
371#define REG_W_OFFSET 0
372#define REG_L_OFFSET 0
373#define REG_LH_OFFSET 4
bellard14ce26e2005-01-03 23:50:08 +0000374#endif
bellard2c0262a2003-09-30 20:34:21 +0000375
Peter Maydell96d70732012-07-05 22:28:59 +0100376/* In instruction encodings for byte register accesses the
377 * register number usually indicates "low 8 bits of register N";
378 * however there are some special cases where N 4..7 indicates
379 * [AH, CH, DH, BH], ie "bits 15..8 of register N-4". Return
380 * true for this special case, false otherwise.
381 */
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -0400382static inline bool byte_reg_is_xH(DisasContext *s, int reg)
Peter Maydell96d70732012-07-05 22:28:59 +0100383{
Richard Henderson1e92b722021-05-14 10:13:07 -0500384 /* Any time the REX prefix is present, byte registers are uniform */
385 if (reg < 4 || REX_PREFIX(s)) {
Peter Maydell96d70732012-07-05 22:28:59 +0100386 return false;
387 }
Peter Maydell96d70732012-07-05 22:28:59 +0100388 return true;
389}
390
Richard Hendersonab4e4ae2013-11-06 09:37:57 +1000391/* Select the size of a push/pop operation. */
Tony Nguyen14776ab2019-08-24 04:10:58 +1000392static inline MemOp mo_pushpop(DisasContext *s, MemOp ot)
Richard Hendersonab4e4ae2013-11-06 09:37:57 +1000393{
394 if (CODE64(s)) {
395 return ot == MO_16 ? MO_16 : MO_64;
396 } else {
397 return ot;
398 }
399}
400
Richard Henderson64ae2562015-12-17 11:19:18 -0800401/* Select the size of the stack pointer. */
Tony Nguyen14776ab2019-08-24 04:10:58 +1000402static inline MemOp mo_stacksize(DisasContext *s)
Richard Henderson64ae2562015-12-17 11:19:18 -0800403{
Richard Hendersonb40a47a2021-05-14 10:13:03 -0500404 return CODE64(s) ? MO_64 : SS32(s) ? MO_32 : MO_16;
Richard Henderson64ae2562015-12-17 11:19:18 -0800405}
406
Richard Hendersonab4e4ae2013-11-06 09:37:57 +1000407/* Select only size 64 else 32. Used for SSE operand sizes. */
Tony Nguyen14776ab2019-08-24 04:10:58 +1000408static inline MemOp mo_64_32(MemOp ot)
Richard Hendersonab4e4ae2013-11-06 09:37:57 +1000409{
410#ifdef TARGET_X86_64
411 return ot == MO_64 ? MO_64 : MO_32;
412#else
413 return MO_32;
414#endif
415}
416
417/* Select size 8 if lsb of B is clear, else OT. Used for decoding
418 byte vs word opcodes. */
Tony Nguyen14776ab2019-08-24 04:10:58 +1000419static inline MemOp mo_b_d(int b, MemOp ot)
Richard Hendersonab4e4ae2013-11-06 09:37:57 +1000420{
421 return b & 1 ? ot : MO_8;
422}
423
424/* Select size 8 if lsb of B is clear, else OT capped at 32.
425 Used for decoding operand size of port opcodes. */
Tony Nguyen14776ab2019-08-24 04:10:58 +1000426static inline MemOp mo_b_d32(int b, MemOp ot)
Richard Hendersonab4e4ae2013-11-06 09:37:57 +1000427{
428 return b & 1 ? (ot == MO_16 ? MO_16 : MO_32) : MO_8;
429}
430
Tony Nguyen14776ab2019-08-24 04:10:58 +1000431static void gen_op_mov_reg_v(DisasContext *s, MemOp ot, int reg, TCGv t0)
bellard2c0262a2003-09-30 20:34:21 +0000432{
bellard57fec1f2008-02-01 10:50:11 +0000433 switch(ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -0700434 case MO_8:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -0400435 if (!byte_reg_is_xH(s, reg)) {
Richard Hendersonc832e3d2011-01-10 19:23:47 -0800436 tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 8);
bellard57fec1f2008-02-01 10:50:11 +0000437 } else {
Richard Hendersonc832e3d2011-01-10 19:23:47 -0800438 tcg_gen_deposit_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], t0, 8, 8);
bellard57fec1f2008-02-01 10:50:11 +0000439 }
440 break;
Richard Henderson4ba99382013-11-02 09:54:47 -0700441 case MO_16:
Richard Hendersonc832e3d2011-01-10 19:23:47 -0800442 tcg_gen_deposit_tl(cpu_regs[reg], cpu_regs[reg], t0, 0, 16);
Laurent Desnoguescc739bb2009-09-29 11:58:04 +0200443 break;
Richard Henderson4ba99382013-11-02 09:54:47 -0700444 case MO_32:
Laurent Desnoguescc739bb2009-09-29 11:58:04 +0200445 /* For x86_64, this sets the higher half of register to zero.
446 For i386, this is equivalent to a mov. */
447 tcg_gen_ext32u_tl(cpu_regs[reg], t0);
bellard57fec1f2008-02-01 10:50:11 +0000448 break;
bellard14ce26e2005-01-03 23:50:08 +0000449#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -0700450 case MO_64:
Laurent Desnoguescc739bb2009-09-29 11:58:04 +0200451 tcg_gen_mov_tl(cpu_regs[reg], t0);
bellard57fec1f2008-02-01 10:50:11 +0000452 break;
bellard14ce26e2005-01-03 23:50:08 +0000453#endif
Richard Hendersond67dc9e2013-11-06 07:25:05 +1000454 default:
455 tcg_abort();
bellard57fec1f2008-02-01 10:50:11 +0000456 }
457}
458
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -0400459static inline
Tony Nguyen14776ab2019-08-24 04:10:58 +1000460void gen_op_mov_v_reg(DisasContext *s, MemOp ot, TCGv t0, int reg)
bellard57fec1f2008-02-01 10:50:11 +0000461{
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -0400462 if (ot == MO_8 && byte_reg_is_xH(s, reg)) {
Richard Henderson04fc2f12016-10-15 11:54:17 -0500463 tcg_gen_extract_tl(t0, cpu_regs[reg - 4], 8, 8);
Peter Maydell96d70732012-07-05 22:28:59 +0100464 } else {
Laurent Desnoguescc739bb2009-09-29 11:58:04 +0200465 tcg_gen_mov_tl(t0, cpu_regs[reg]);
bellard57fec1f2008-02-01 10:50:11 +0000466 }
467}
468
bellard57fec1f2008-02-01 10:50:11 +0000469static void gen_add_A0_im(DisasContext *s, int val)
470{
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400471 tcg_gen_addi_tl(s->A0, s->A0, val);
Richard Henderson4e850572015-12-17 11:19:25 -0800472 if (!CODE64(s)) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400473 tcg_gen_ext32u_tl(s->A0, s->A0);
Richard Henderson4e850572015-12-17 11:19:25 -0800474 }
bellard57fec1f2008-02-01 10:50:11 +0000475}
bellard14ce26e2005-01-03 23:50:08 +0000476
Richard Henderson74bdfbd2013-11-07 09:33:53 +1000477static inline void gen_op_jmp_v(TCGv dest)
bellard57fec1f2008-02-01 10:50:11 +0000478{
Richard Henderson74bdfbd2013-11-07 09:33:53 +1000479 tcg_gen_st_tl(dest, cpu_env, offsetof(CPUX86State, eip));
bellard57fec1f2008-02-01 10:50:11 +0000480}
481
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400482static inline
Tony Nguyen14776ab2019-08-24 04:10:58 +1000483void gen_op_add_reg_im(DisasContext *s, MemOp size, int reg, int32_t val)
bellard57fec1f2008-02-01 10:50:11 +0000484{
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400485 tcg_gen_addi_tl(s->tmp0, cpu_regs[reg], val);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -0400486 gen_op_mov_reg_v(s, size, reg, s->tmp0);
bellard57fec1f2008-02-01 10:50:11 +0000487}
488
Tony Nguyen14776ab2019-08-24 04:10:58 +1000489static inline void gen_op_add_reg_T0(DisasContext *s, MemOp size, int reg)
bellard57fec1f2008-02-01 10:50:11 +0000490{
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400491 tcg_gen_add_tl(s->tmp0, cpu_regs[reg], s->T0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -0400492 gen_op_mov_reg_v(s, size, reg, s->tmp0);
bellard6e0d8672008-05-18 19:28:26 +0000493}
bellard57fec1f2008-02-01 10:50:11 +0000494
Richard Henderson323d1872013-10-30 22:04:05 -0700495static inline void gen_op_ld_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
bellard57fec1f2008-02-01 10:50:11 +0000496{
Richard Henderson3c5f4112013-11-02 09:30:34 -0700497 tcg_gen_qemu_ld_tl(t0, a0, s->mem_index, idx | MO_LE);
bellard57fec1f2008-02-01 10:50:11 +0000498}
bellard2c0262a2003-09-30 20:34:21 +0000499
Richard Henderson323d1872013-10-30 22:04:05 -0700500static inline void gen_op_st_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
bellard1e4840b2008-05-25 17:26:41 +0000501{
Richard Henderson3523e4b2013-11-02 09:49:20 -0700502 tcg_gen_qemu_st_tl(t0, a0, s->mem_index, idx | MO_LE);
bellard57fec1f2008-02-01 10:50:11 +0000503}
bellard2c0262a2003-09-30 20:34:21 +0000504
Richard Hendersond4faa3e2013-11-02 10:59:43 -0700505static inline void gen_op_st_rm_T0_A0(DisasContext *s, int idx, int d)
506{
507 if (d == OR_TMP0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400508 gen_op_st_v(s, idx, s->T0, s->A0);
Richard Hendersond4faa3e2013-11-02 10:59:43 -0700509 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -0400510 gen_op_mov_reg_v(s, idx, d, s->T0);
Richard Hendersond4faa3e2013-11-02 10:59:43 -0700511 }
512}
513
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400514static inline void gen_jmp_im(DisasContext *s, target_ulong pc)
bellard14ce26e2005-01-03 23:50:08 +0000515{
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400516 tcg_gen_movi_tl(s->tmp0, pc);
517 gen_op_jmp_v(s->tmp0);
bellard14ce26e2005-01-03 23:50:08 +0000518}
519
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800520/* Compute SEG:REG into A0. SEG is selected from the override segment
521 (OVR_SEG) and the default segment (DEF_SEG). OVR_SEG may be -1 to
522 indicate no override. */
Tony Nguyen14776ab2019-08-24 04:10:58 +1000523static void gen_lea_v_seg(DisasContext *s, MemOp aflag, TCGv a0,
Richard Henderson77ebcad2015-12-17 11:19:20 -0800524 int def_seg, int ovr_seg)
bellard2c0262a2003-09-30 20:34:21 +0000525{
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800526 switch (aflag) {
bellard14ce26e2005-01-03 23:50:08 +0000527#ifdef TARGET_X86_64
Richard Henderson1d71ddb2013-11-06 08:27:33 +1000528 case MO_64:
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800529 if (ovr_seg < 0) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400530 tcg_gen_mov_tl(s->A0, a0);
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800531 return;
bellard14ce26e2005-01-03 23:50:08 +0000532 }
Richard Henderson1d71ddb2013-11-06 08:27:33 +1000533 break;
bellard14ce26e2005-01-03 23:50:08 +0000534#endif
Richard Henderson1d71ddb2013-11-06 08:27:33 +1000535 case MO_32:
bellard2c0262a2003-09-30 20:34:21 +0000536 /* 32 bit address */
Richard Hendersonbeedb932021-05-14 10:13:06 -0500537 if (ovr_seg < 0 && ADDSEG(s)) {
Paolo Bonzini620abfb2016-10-12 09:23:39 +0200538 ovr_seg = def_seg;
539 }
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800540 if (ovr_seg < 0) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400541 tcg_gen_ext32u_tl(s->A0, a0);
Paolo Bonzini620abfb2016-10-12 09:23:39 +0200542 return;
bellard2c0262a2003-09-30 20:34:21 +0000543 }
Richard Henderson1d71ddb2013-11-06 08:27:33 +1000544 break;
545 case MO_16:
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800546 /* 16 bit address */
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400547 tcg_gen_ext16u_tl(s->A0, a0);
548 a0 = s->A0;
Paolo Bonzinie2e02a82016-03-02 16:04:38 +0100549 if (ovr_seg < 0) {
Richard Hendersonbeedb932021-05-14 10:13:06 -0500550 if (ADDSEG(s)) {
Paolo Bonzinie2e02a82016-03-02 16:04:38 +0100551 ovr_seg = def_seg;
552 } else {
553 return;
554 }
555 }
Richard Henderson1d71ddb2013-11-06 08:27:33 +1000556 break;
557 default:
558 tcg_abort();
bellard2c0262a2003-09-30 20:34:21 +0000559 }
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800560
561 if (ovr_seg >= 0) {
Richard Henderson3558f802015-12-17 11:19:21 -0800562 TCGv seg = cpu_seg_base[ovr_seg];
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800563
564 if (aflag == MO_64) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400565 tcg_gen_add_tl(s->A0, a0, seg);
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800566 } else if (CODE64(s)) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400567 tcg_gen_ext32u_tl(s->A0, a0);
568 tcg_gen_add_tl(s->A0, s->A0, seg);
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800569 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -0400570 tcg_gen_add_tl(s->A0, a0, seg);
571 tcg_gen_ext32u_tl(s->A0, s->A0);
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800572 }
Richard Hendersonca2f29f2015-12-17 11:19:17 -0800573 }
574}
575
576static inline void gen_string_movl_A0_ESI(DisasContext *s)
577{
Richard Henderson77ebcad2015-12-17 11:19:20 -0800578 gen_lea_v_seg(s, s->aflag, cpu_regs[R_ESI], R_DS, s->override);
bellard2c0262a2003-09-30 20:34:21 +0000579}
580
581static inline void gen_string_movl_A0_EDI(DisasContext *s)
582{
Richard Henderson77ebcad2015-12-17 11:19:20 -0800583 gen_lea_v_seg(s, s->aflag, cpu_regs[R_EDI], R_ES, -1);
bellard2c0262a2003-09-30 20:34:21 +0000584}
585
Tony Nguyen14776ab2019-08-24 04:10:58 +1000586static inline void gen_op_movl_T0_Dshift(DisasContext *s, MemOp ot)
bellard6e0d8672008-05-18 19:28:26 +0000587{
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400588 tcg_gen_ld32s_tl(s->T0, cpu_env, offsetof(CPUX86State, df));
589 tcg_gen_shli_tl(s->T0, s->T0, ot);
bellard2c0262a2003-09-30 20:34:21 +0000590};
591
Tony Nguyen14776ab2019-08-24 04:10:58 +1000592static TCGv gen_ext_tl(TCGv dst, TCGv src, MemOp size, bool sign)
Paolo Bonzinid824df32012-10-05 18:02:41 +0200593{
594 switch (size) {
Richard Henderson4ba99382013-11-02 09:54:47 -0700595 case MO_8:
Paolo Bonzinid824df32012-10-05 18:02:41 +0200596 if (sign) {
597 tcg_gen_ext8s_tl(dst, src);
598 } else {
599 tcg_gen_ext8u_tl(dst, src);
600 }
601 return dst;
Richard Henderson4ba99382013-11-02 09:54:47 -0700602 case MO_16:
Paolo Bonzinid824df32012-10-05 18:02:41 +0200603 if (sign) {
604 tcg_gen_ext16s_tl(dst, src);
605 } else {
606 tcg_gen_ext16u_tl(dst, src);
607 }
608 return dst;
609#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -0700610 case MO_32:
Paolo Bonzinid824df32012-10-05 18:02:41 +0200611 if (sign) {
612 tcg_gen_ext32s_tl(dst, src);
613 } else {
614 tcg_gen_ext32u_tl(dst, src);
615 }
616 return dst;
617#endif
618 default:
619 return src;
620 }
621}
622
Tony Nguyen14776ab2019-08-24 04:10:58 +1000623static void gen_extu(MemOp ot, TCGv reg)
bellard6e0d8672008-05-18 19:28:26 +0000624{
Paolo Bonzinid824df32012-10-05 18:02:41 +0200625 gen_ext_tl(reg, reg, ot, false);
bellard6e0d8672008-05-18 19:28:26 +0000626}
ths3b46e622007-09-17 08:09:54 +0000627
Tony Nguyen14776ab2019-08-24 04:10:58 +1000628static void gen_exts(MemOp ot, TCGv reg)
bellard6e0d8672008-05-18 19:28:26 +0000629{
Paolo Bonzinid824df32012-10-05 18:02:41 +0200630 gen_ext_tl(reg, reg, ot, true);
bellard6e0d8672008-05-18 19:28:26 +0000631}
bellard2c0262a2003-09-30 20:34:21 +0000632
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400633static inline
Tony Nguyen14776ab2019-08-24 04:10:58 +1000634void gen_op_jnz_ecx(DisasContext *s, MemOp size, TCGLabel *label1)
bellard6e0d8672008-05-18 19:28:26 +0000635{
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400636 tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]);
637 gen_extu(size, s->tmp0);
638 tcg_gen_brcondi_tl(TCG_COND_NE, s->tmp0, 0, label1);
bellard6e0d8672008-05-18 19:28:26 +0000639}
640
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400641static inline
Tony Nguyen14776ab2019-08-24 04:10:58 +1000642void gen_op_jz_ecx(DisasContext *s, MemOp size, TCGLabel *label1)
bellard6e0d8672008-05-18 19:28:26 +0000643{
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400644 tcg_gen_mov_tl(s->tmp0, cpu_regs[R_ECX]);
645 gen_extu(size, s->tmp0);
646 tcg_gen_brcondi_tl(TCG_COND_EQ, s->tmp0, 0, label1);
bellard6e0d8672008-05-18 19:28:26 +0000647}
bellard2c0262a2003-09-30 20:34:21 +0000648
Tony Nguyen14776ab2019-08-24 04:10:58 +1000649static void gen_helper_in_func(MemOp ot, TCGv v, TCGv_i32 n)
pbrooka7812ae2008-11-17 14:43:54 +0000650{
651 switch (ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -0700652 case MO_8:
Paolo Bonzini3f7d8462015-04-08 14:45:53 +0200653 gen_helper_inb(v, cpu_env, n);
Paolo Bonzini93ab25d2012-10-06 01:56:03 +0200654 break;
Richard Henderson4ba99382013-11-02 09:54:47 -0700655 case MO_16:
Paolo Bonzini3f7d8462015-04-08 14:45:53 +0200656 gen_helper_inw(v, cpu_env, n);
Paolo Bonzini93ab25d2012-10-06 01:56:03 +0200657 break;
Richard Henderson4ba99382013-11-02 09:54:47 -0700658 case MO_32:
Paolo Bonzini3f7d8462015-04-08 14:45:53 +0200659 gen_helper_inl(v, cpu_env, n);
Paolo Bonzini93ab25d2012-10-06 01:56:03 +0200660 break;
Richard Hendersond67dc9e2013-11-06 07:25:05 +1000661 default:
662 tcg_abort();
pbrooka7812ae2008-11-17 14:43:54 +0000663 }
pbrooka7812ae2008-11-17 14:43:54 +0000664}
bellard2c0262a2003-09-30 20:34:21 +0000665
Tony Nguyen14776ab2019-08-24 04:10:58 +1000666static void gen_helper_out_func(MemOp ot, TCGv_i32 v, TCGv_i32 n)
pbrooka7812ae2008-11-17 14:43:54 +0000667{
668 switch (ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -0700669 case MO_8:
Paolo Bonzini3f7d8462015-04-08 14:45:53 +0200670 gen_helper_outb(cpu_env, v, n);
Paolo Bonzini93ab25d2012-10-06 01:56:03 +0200671 break;
Richard Henderson4ba99382013-11-02 09:54:47 -0700672 case MO_16:
Paolo Bonzini3f7d8462015-04-08 14:45:53 +0200673 gen_helper_outw(cpu_env, v, n);
Paolo Bonzini93ab25d2012-10-06 01:56:03 +0200674 break;
Richard Henderson4ba99382013-11-02 09:54:47 -0700675 case MO_32:
Paolo Bonzini3f7d8462015-04-08 14:45:53 +0200676 gen_helper_outl(cpu_env, v, n);
Paolo Bonzini93ab25d2012-10-06 01:56:03 +0200677 break;
Richard Hendersond67dc9e2013-11-06 07:25:05 +1000678 default:
679 tcg_abort();
pbrooka7812ae2008-11-17 14:43:54 +0000680 }
pbrooka7812ae2008-11-17 14:43:54 +0000681}
bellardf115e912003-11-13 01:43:28 +0000682
Richard Henderson1bca40f2021-05-14 10:13:39 -0500683/*
684 * Validate that access to [port, port + 1<<ot) is allowed.
685 * Raise #GP, or VMM exit if not.
686 */
687static bool gen_check_io(DisasContext *s, MemOp ot, TCGv_i32 port,
688 uint32_t svm_flags)
bellardf115e912003-11-13 01:43:28 +0000689{
Richard Hendersond76b9c62021-05-14 10:13:41 -0500690#ifdef CONFIG_USER_ONLY
691 /*
692 * We do not implement the ioperm(2) syscall, so the TSS check
693 * will always fail.
694 */
695 gen_exception_gpf(s);
696 return false;
697#else
Richard Hendersonf8a35842021-05-14 10:13:01 -0500698 if (PE(s) && (CPL(s) > IOPL(s) || VM86(s))) {
Richard Hendersone4978032021-05-14 10:13:40 -0500699 gen_helper_check_io(cpu_env, port, tcg_constant_i32(1 << ot));
bellardb8b6a502008-05-15 16:46:30 +0000700 }
Richard Hendersonb322b3a2021-05-14 10:13:23 -0500701 if (GUEST(s)) {
Richard Hendersonbc2e4362021-05-14 10:13:38 -0500702 target_ulong cur_eip = s->base.pc_next - s->cs_base;
703 target_ulong next_eip = s->pc - s->cs_base;
704
Pavel Dovgalyuk100ec092015-07-10 12:57:36 +0300705 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400706 gen_jmp_im(s, cur_eip);
Richard Hendersonbc2e4362021-05-14 10:13:38 -0500707 if (s->prefix & (PREFIX_REPZ | PREFIX_REPNZ)) {
708 svm_flags |= SVM_IOIO_REP_MASK;
709 }
710 svm_flags |= 1 << (SVM_IOIO_SIZE_SHIFT + ot);
Richard Henderson1bca40f2021-05-14 10:13:39 -0500711 gen_helper_svm_check_io(cpu_env, port,
Richard Hendersonbc2e4362021-05-14 10:13:38 -0500712 tcg_constant_i32(svm_flags),
713 tcg_constant_i32(next_eip - cur_eip));
bellardf115e912003-11-13 01:43:28 +0000714 }
Richard Hendersonbc2e4362021-05-14 10:13:38 -0500715 return true;
Richard Hendersond76b9c62021-05-14 10:13:41 -0500716#endif
bellardf115e912003-11-13 01:43:28 +0000717}
718
Tony Nguyen14776ab2019-08-24 04:10:58 +1000719static inline void gen_movs(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +0000720{
721 gen_string_movl_A0_ESI(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400722 gen_op_ld_v(s, ot, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +0000723 gen_string_movl_A0_EDI(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400724 gen_op_st_v(s, ot, s->T0, s->A0);
725 gen_op_movl_T0_Dshift(s, ot);
726 gen_op_add_reg_T0(s, s->aflag, R_ESI);
727 gen_op_add_reg_T0(s, s->aflag, R_EDI);
bellard2c0262a2003-09-30 20:34:21 +0000728}
729
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400730static void gen_op_update1_cc(DisasContext *s)
bellardb6abf972008-05-17 12:44:31 +0000731{
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400732 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
bellardb6abf972008-05-17 12:44:31 +0000733}
734
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400735static void gen_op_update2_cc(DisasContext *s)
bellardb6abf972008-05-17 12:44:31 +0000736{
Emilio G. Cotab48597b2018-09-11 14:50:46 -0400737 tcg_gen_mov_tl(cpu_cc_src, s->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400738 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
bellardb6abf972008-05-17 12:44:31 +0000739}
740
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400741static void gen_op_update3_cc(DisasContext *s, TCGv reg)
Richard Henderson988c3eb2013-01-23 16:03:16 -0800742{
743 tcg_gen_mov_tl(cpu_cc_src2, reg);
Emilio G. Cotab48597b2018-09-11 14:50:46 -0400744 tcg_gen_mov_tl(cpu_cc_src, s->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400745 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
Richard Henderson988c3eb2013-01-23 16:03:16 -0800746}
747
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400748static inline void gen_op_testl_T0_T1_cc(DisasContext *s)
bellardb6abf972008-05-17 12:44:31 +0000749{
Emilio G. Cotab48597b2018-09-11 14:50:46 -0400750 tcg_gen_and_tl(cpu_cc_dst, s->T0, s->T1);
bellardb6abf972008-05-17 12:44:31 +0000751}
752
Emilio G. Cota93a3e102018-09-11 14:38:47 -0400753static void gen_op_update_neg_cc(DisasContext *s)
bellardb6abf972008-05-17 12:44:31 +0000754{
Emilio G. Cotac66f9722018-09-11 14:48:41 -0400755 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
756 tcg_gen_neg_tl(cpu_cc_src, s->T0);
Emilio G. Cota93a3e102018-09-11 14:38:47 -0400757 tcg_gen_movi_tl(s->cc_srcT, 0);
bellardb6abf972008-05-17 12:44:31 +0000758}
759
Richard Hendersond229edc2013-01-23 13:03:26 -0800760/* compute all eflags to cc_src */
761static void gen_compute_eflags(DisasContext *s)
bellard8e1c85e2008-05-21 19:16:45 +0000762{
Richard Henderson988c3eb2013-01-23 16:03:16 -0800763 TCGv zero, dst, src1, src2;
Richard Hendersondb9f2592013-01-23 16:10:49 -0800764 int live, dead;
765
Richard Hendersond229edc2013-01-23 13:03:26 -0800766 if (s->cc_op == CC_OP_EFLAGS) {
767 return;
768 }
Richard Henderson436ff2d2013-01-29 13:38:43 -0800769 if (s->cc_op == CC_OP_CLR) {
Richard Hendersond2fe51b2014-01-10 12:38:40 -0800770 tcg_gen_movi_tl(cpu_cc_src, CC_Z | CC_P);
Richard Henderson436ff2d2013-01-29 13:38:43 -0800771 set_cc_op(s, CC_OP_EFLAGS);
772 return;
773 }
Richard Hendersondb9f2592013-01-23 16:10:49 -0800774
Richard Hendersonf7647182017-11-02 12:47:37 +0100775 zero = NULL;
Richard Hendersondb9f2592013-01-23 16:10:49 -0800776 dst = cpu_cc_dst;
777 src1 = cpu_cc_src;
Richard Henderson988c3eb2013-01-23 16:03:16 -0800778 src2 = cpu_cc_src2;
Richard Hendersondb9f2592013-01-23 16:10:49 -0800779
780 /* Take care to not read values that are not live. */
781 live = cc_op_live[s->cc_op] & ~USES_CC_SRCT;
Richard Henderson988c3eb2013-01-23 16:03:16 -0800782 dead = live ^ (USES_CC_DST | USES_CC_SRC | USES_CC_SRC2);
Richard Hendersondb9f2592013-01-23 16:10:49 -0800783 if (dead) {
784 zero = tcg_const_tl(0);
785 if (dead & USES_CC_DST) {
786 dst = zero;
787 }
788 if (dead & USES_CC_SRC) {
789 src1 = zero;
790 }
Richard Henderson988c3eb2013-01-23 16:03:16 -0800791 if (dead & USES_CC_SRC2) {
792 src2 = zero;
793 }
Richard Hendersondb9f2592013-01-23 16:10:49 -0800794 }
795
Richard Henderson773cdfc2013-01-23 12:43:12 -0800796 gen_update_cc_op(s);
Richard Henderson988c3eb2013-01-23 16:03:16 -0800797 gen_helper_cc_compute_all(cpu_cc_src, dst, src1, src2, cpu_cc_op);
Richard Hendersond229edc2013-01-23 13:03:26 -0800798 set_cc_op(s, CC_OP_EFLAGS);
Richard Hendersondb9f2592013-01-23 16:10:49 -0800799
800 if (dead) {
801 tcg_temp_free(zero);
802 }
bellard8e1c85e2008-05-21 19:16:45 +0000803}
804
Richard Hendersonbec93d72013-01-23 14:21:52 -0800805typedef struct CCPrepare {
806 TCGCond cond;
807 TCGv reg;
808 TCGv reg2;
809 target_ulong imm;
810 target_ulong mask;
811 bool use_reg2;
812 bool no_setcond;
813} CCPrepare;
814
Richard Henderson06847f12013-01-23 13:46:02 -0800815/* compute eflags.C to reg */
Richard Hendersonbec93d72013-01-23 14:21:52 -0800816static CCPrepare gen_prepare_eflags_c(DisasContext *s, TCGv reg)
Richard Henderson06847f12013-01-23 13:46:02 -0800817{
818 TCGv t0, t1;
Richard Hendersonbec93d72013-01-23 14:21:52 -0800819 int size, shift;
Richard Henderson06847f12013-01-23 13:46:02 -0800820
821 switch (s->cc_op) {
822 case CC_OP_SUBB ... CC_OP_SUBQ:
Richard Hendersona3251182013-01-23 15:43:03 -0800823 /* (DATA_TYPE)CC_SRCT < (DATA_TYPE)CC_SRC */
Richard Henderson06847f12013-01-23 13:46:02 -0800824 size = s->cc_op - CC_OP_SUBB;
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400825 t1 = gen_ext_tl(s->tmp0, cpu_cc_src, size, false);
Richard Henderson06847f12013-01-23 13:46:02 -0800826 /* If no temporary was used, be careful not to alias t1 and t0. */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400827 t0 = t1 == cpu_cc_src ? s->tmp0 : reg;
Emilio G. Cota93a3e102018-09-11 14:38:47 -0400828 tcg_gen_mov_tl(t0, s->cc_srcT);
Richard Henderson06847f12013-01-23 13:46:02 -0800829 gen_extu(size, t0);
830 goto add_sub;
831
832 case CC_OP_ADDB ... CC_OP_ADDQ:
833 /* (DATA_TYPE)CC_DST < (DATA_TYPE)CC_SRC */
834 size = s->cc_op - CC_OP_ADDB;
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400835 t1 = gen_ext_tl(s->tmp0, cpu_cc_src, size, false);
Richard Henderson06847f12013-01-23 13:46:02 -0800836 t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
837 add_sub:
Richard Hendersonbec93d72013-01-23 14:21:52 -0800838 return (CCPrepare) { .cond = TCG_COND_LTU, .reg = t0,
839 .reg2 = t1, .mask = -1, .use_reg2 = true };
Richard Henderson06847f12013-01-23 13:46:02 -0800840
Richard Henderson06847f12013-01-23 13:46:02 -0800841 case CC_OP_LOGICB ... CC_OP_LOGICQ:
Richard Henderson436ff2d2013-01-29 13:38:43 -0800842 case CC_OP_CLR:
Richard Henderson4885c3c2016-11-21 12:18:53 +0100843 case CC_OP_POPCNT:
Richard Hendersonbec93d72013-01-23 14:21:52 -0800844 return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
Richard Henderson06847f12013-01-23 13:46:02 -0800845
846 case CC_OP_INCB ... CC_OP_INCQ:
847 case CC_OP_DECB ... CC_OP_DECQ:
Richard Hendersonbec93d72013-01-23 14:21:52 -0800848 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
849 .mask = -1, .no_setcond = true };
Richard Henderson06847f12013-01-23 13:46:02 -0800850
851 case CC_OP_SHLB ... CC_OP_SHLQ:
852 /* (CC_SRC >> (DATA_BITS - 1)) & 1 */
853 size = s->cc_op - CC_OP_SHLB;
Richard Hendersonbec93d72013-01-23 14:21:52 -0800854 shift = (8 << size) - 1;
855 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
856 .mask = (target_ulong)1 << shift };
Richard Henderson06847f12013-01-23 13:46:02 -0800857
858 case CC_OP_MULB ... CC_OP_MULQ:
Richard Hendersonbec93d72013-01-23 14:21:52 -0800859 return (CCPrepare) { .cond = TCG_COND_NE,
860 .reg = cpu_cc_src, .mask = -1 };
Richard Henderson06847f12013-01-23 13:46:02 -0800861
Richard Hendersonbc4b43d2013-01-23 16:44:37 -0800862 case CC_OP_BMILGB ... CC_OP_BMILGQ:
863 size = s->cc_op - CC_OP_BMILGB;
864 t0 = gen_ext_tl(reg, cpu_cc_src, size, false);
865 return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 };
866
Richard Hendersoncd7f97c2013-01-23 18:17:33 -0800867 case CC_OP_ADCX:
868 case CC_OP_ADCOX:
869 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_dst,
870 .mask = -1, .no_setcond = true };
871
Richard Henderson06847f12013-01-23 13:46:02 -0800872 case CC_OP_EFLAGS:
873 case CC_OP_SARB ... CC_OP_SARQ:
874 /* CC_SRC & 1 */
Richard Hendersonbec93d72013-01-23 14:21:52 -0800875 return (CCPrepare) { .cond = TCG_COND_NE,
876 .reg = cpu_cc_src, .mask = CC_C };
Richard Henderson06847f12013-01-23 13:46:02 -0800877
878 default:
879 /* The need to compute only C from CC_OP_DYNAMIC is important
880 in efficiently implementing e.g. INC at the start of a TB. */
881 gen_update_cc_op(s);
Richard Henderson988c3eb2013-01-23 16:03:16 -0800882 gen_helper_cc_compute_c(reg, cpu_cc_dst, cpu_cc_src,
883 cpu_cc_src2, cpu_cc_op);
Richard Hendersonbec93d72013-01-23 14:21:52 -0800884 return (CCPrepare) { .cond = TCG_COND_NE, .reg = reg,
885 .mask = -1, .no_setcond = true };
Richard Henderson06847f12013-01-23 13:46:02 -0800886 }
887}
888
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200889/* compute eflags.P to reg */
Richard Hendersonbec93d72013-01-23 14:21:52 -0800890static CCPrepare gen_prepare_eflags_p(DisasContext *s, TCGv reg)
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200891{
Richard Hendersond229edc2013-01-23 13:03:26 -0800892 gen_compute_eflags(s);
Richard Hendersonbec93d72013-01-23 14:21:52 -0800893 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
894 .mask = CC_P };
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200895}
896
897/* compute eflags.S to reg */
Richard Hendersonbec93d72013-01-23 14:21:52 -0800898static CCPrepare gen_prepare_eflags_s(DisasContext *s, TCGv reg)
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200899{
Richard Henderson086c4072013-01-23 13:33:59 -0800900 switch (s->cc_op) {
901 case CC_OP_DYNAMIC:
902 gen_compute_eflags(s);
903 /* FALLTHRU */
904 case CC_OP_EFLAGS:
Richard Hendersoncd7f97c2013-01-23 18:17:33 -0800905 case CC_OP_ADCX:
906 case CC_OP_ADOX:
907 case CC_OP_ADCOX:
Richard Hendersonbec93d72013-01-23 14:21:52 -0800908 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
909 .mask = CC_S };
Richard Henderson436ff2d2013-01-29 13:38:43 -0800910 case CC_OP_CLR:
Richard Henderson4885c3c2016-11-21 12:18:53 +0100911 case CC_OP_POPCNT:
Richard Henderson436ff2d2013-01-29 13:38:43 -0800912 return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
Richard Henderson086c4072013-01-23 13:33:59 -0800913 default:
914 {
Tony Nguyen14776ab2019-08-24 04:10:58 +1000915 MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
Richard Henderson086c4072013-01-23 13:33:59 -0800916 TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, true);
Richard Hendersonbec93d72013-01-23 14:21:52 -0800917 return (CCPrepare) { .cond = TCG_COND_LT, .reg = t0, .mask = -1 };
Richard Henderson086c4072013-01-23 13:33:59 -0800918 }
Richard Henderson086c4072013-01-23 13:33:59 -0800919 }
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200920}
921
922/* compute eflags.O to reg */
Richard Hendersonbec93d72013-01-23 14:21:52 -0800923static CCPrepare gen_prepare_eflags_o(DisasContext *s, TCGv reg)
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200924{
Richard Hendersoncd7f97c2013-01-23 18:17:33 -0800925 switch (s->cc_op) {
926 case CC_OP_ADOX:
927 case CC_OP_ADCOX:
928 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src2,
929 .mask = -1, .no_setcond = true };
Richard Henderson436ff2d2013-01-29 13:38:43 -0800930 case CC_OP_CLR:
Richard Henderson4885c3c2016-11-21 12:18:53 +0100931 case CC_OP_POPCNT:
Richard Henderson436ff2d2013-01-29 13:38:43 -0800932 return (CCPrepare) { .cond = TCG_COND_NEVER, .mask = -1 };
Richard Hendersoncd7f97c2013-01-23 18:17:33 -0800933 default:
934 gen_compute_eflags(s);
935 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
936 .mask = CC_O };
937 }
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200938}
939
940/* compute eflags.Z to reg */
Richard Hendersonbec93d72013-01-23 14:21:52 -0800941static CCPrepare gen_prepare_eflags_z(DisasContext *s, TCGv reg)
Paolo Bonzini1608ecc2012-10-05 18:42:59 +0200942{
Richard Henderson086c4072013-01-23 13:33:59 -0800943 switch (s->cc_op) {
944 case CC_OP_DYNAMIC:
945 gen_compute_eflags(s);
946 /* FALLTHRU */
947 case CC_OP_EFLAGS:
Richard Hendersoncd7f97c2013-01-23 18:17:33 -0800948 case CC_OP_ADCX:
949 case CC_OP_ADOX:
950 case CC_OP_ADCOX:
Richard Hendersonbec93d72013-01-23 14:21:52 -0800951 return (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
952 .mask = CC_Z };
Richard Henderson436ff2d2013-01-29 13:38:43 -0800953 case CC_OP_CLR:
954 return (CCPrepare) { .cond = TCG_COND_ALWAYS, .mask = -1 };
Richard Henderson4885c3c2016-11-21 12:18:53 +0100955 case CC_OP_POPCNT:
956 return (CCPrepare) { .cond = TCG_COND_EQ, .reg = cpu_cc_src,
957 .mask = -1 };
Richard Henderson086c4072013-01-23 13:33:59 -0800958 default:
959 {
Tony Nguyen14776ab2019-08-24 04:10:58 +1000960 MemOp size = (s->cc_op - CC_OP_ADDB) & 3;
Richard Henderson086c4072013-01-23 13:33:59 -0800961 TCGv t0 = gen_ext_tl(reg, cpu_cc_dst, size, false);
Richard Hendersonbec93d72013-01-23 14:21:52 -0800962 return (CCPrepare) { .cond = TCG_COND_EQ, .reg = t0, .mask = -1 };
Richard Henderson086c4072013-01-23 13:33:59 -0800963 }
Richard Hendersonbec93d72013-01-23 14:21:52 -0800964 }
965}
966
Paolo Bonzinic3653952012-10-05 23:00:10 +0200967/* perform a conditional store into register 'reg' according to jump opcode
968 value 'b'. In the fast case, T0 is guaranted not to be used. */
Richard Henderson276e6b52013-01-23 14:33:45 -0800969static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg)
bellard8e1c85e2008-05-21 19:16:45 +0000970{
Richard Hendersond67dc9e2013-11-06 07:25:05 +1000971 int inv, jcc_op, cond;
Tony Nguyen14776ab2019-08-24 04:10:58 +1000972 MemOp size;
Richard Henderson276e6b52013-01-23 14:33:45 -0800973 CCPrepare cc;
Paolo Bonzinic3653952012-10-05 23:00:10 +0200974 TCGv t0;
975
976 inv = b & 1;
bellard8e1c85e2008-05-21 19:16:45 +0000977 jcc_op = (b >> 1) & 7;
Paolo Bonzinic3653952012-10-05 23:00:10 +0200978
979 switch (s->cc_op) {
Richard Henderson69d1aa32013-01-23 14:41:21 -0800980 case CC_OP_SUBB ... CC_OP_SUBQ:
981 /* We optimize relational operators for the cmp/jcc case. */
Paolo Bonzinic3653952012-10-05 23:00:10 +0200982 size = s->cc_op - CC_OP_SUBB;
983 switch (jcc_op) {
984 case JCC_BE:
Emilio G. Cota5022f282018-09-11 14:10:21 -0400985 tcg_gen_mov_tl(s->tmp4, s->cc_srcT);
986 gen_extu(size, s->tmp4);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -0400987 t0 = gen_ext_tl(s->tmp0, cpu_cc_src, size, false);
Emilio G. Cota5022f282018-09-11 14:10:21 -0400988 cc = (CCPrepare) { .cond = TCG_COND_LEU, .reg = s->tmp4,
Richard Henderson276e6b52013-01-23 14:33:45 -0800989 .reg2 = t0, .mask = -1, .use_reg2 = true };
Paolo Bonzinic3653952012-10-05 23:00:10 +0200990 break;
991
992 case JCC_L:
Richard Henderson276e6b52013-01-23 14:33:45 -0800993 cond = TCG_COND_LT;
Paolo Bonzinic3653952012-10-05 23:00:10 +0200994 goto fast_jcc_l;
995 case JCC_LE:
Richard Henderson276e6b52013-01-23 14:33:45 -0800996 cond = TCG_COND_LE;
Paolo Bonzinic3653952012-10-05 23:00:10 +0200997 fast_jcc_l:
Emilio G. Cota5022f282018-09-11 14:10:21 -0400998 tcg_gen_mov_tl(s->tmp4, s->cc_srcT);
999 gen_exts(size, s->tmp4);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001000 t0 = gen_ext_tl(s->tmp0, cpu_cc_src, size, true);
Emilio G. Cota5022f282018-09-11 14:10:21 -04001001 cc = (CCPrepare) { .cond = cond, .reg = s->tmp4,
Richard Henderson276e6b52013-01-23 14:33:45 -08001002 .reg2 = t0, .mask = -1, .use_reg2 = true };
Paolo Bonzinic3653952012-10-05 23:00:10 +02001003 break;
1004
1005 default:
bellard8e1c85e2008-05-21 19:16:45 +00001006 goto slow_jcc;
Paolo Bonzinic3653952012-10-05 23:00:10 +02001007 }
bellard8e1c85e2008-05-21 19:16:45 +00001008 break;
1009
bellard8e1c85e2008-05-21 19:16:45 +00001010 default:
1011 slow_jcc:
Richard Henderson69d1aa32013-01-23 14:41:21 -08001012 /* This actually generates good code for JC, JZ and JS. */
1013 switch (jcc_op) {
1014 case JCC_O:
1015 cc = gen_prepare_eflags_o(s, reg);
1016 break;
1017 case JCC_B:
1018 cc = gen_prepare_eflags_c(s, reg);
1019 break;
1020 case JCC_Z:
1021 cc = gen_prepare_eflags_z(s, reg);
1022 break;
1023 case JCC_BE:
1024 gen_compute_eflags(s);
1025 cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = cpu_cc_src,
1026 .mask = CC_Z | CC_C };
1027 break;
1028 case JCC_S:
1029 cc = gen_prepare_eflags_s(s, reg);
1030 break;
1031 case JCC_P:
1032 cc = gen_prepare_eflags_p(s, reg);
1033 break;
1034 case JCC_L:
1035 gen_compute_eflags(s);
Richard Henderson11f4e8f2017-10-19 20:27:27 -07001036 if (reg == cpu_cc_src) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001037 reg = s->tmp0;
Richard Henderson69d1aa32013-01-23 14:41:21 -08001038 }
1039 tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */
1040 tcg_gen_xor_tl(reg, reg, cpu_cc_src);
1041 cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = reg,
1042 .mask = CC_S };
1043 break;
1044 default:
1045 case JCC_LE:
1046 gen_compute_eflags(s);
Richard Henderson11f4e8f2017-10-19 20:27:27 -07001047 if (reg == cpu_cc_src) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001048 reg = s->tmp0;
Richard Henderson69d1aa32013-01-23 14:41:21 -08001049 }
1050 tcg_gen_shri_tl(reg, cpu_cc_src, 4); /* CC_O -> CC_S */
1051 tcg_gen_xor_tl(reg, reg, cpu_cc_src);
1052 cc = (CCPrepare) { .cond = TCG_COND_NE, .reg = reg,
1053 .mask = CC_S | CC_Z };
1054 break;
1055 }
Paolo Bonzinic3653952012-10-05 23:00:10 +02001056 break;
bellard8e1c85e2008-05-21 19:16:45 +00001057 }
Richard Henderson276e6b52013-01-23 14:33:45 -08001058
1059 if (inv) {
1060 cc.cond = tcg_invert_cond(cc.cond);
1061 }
1062 return cc;
bellard8e1c85e2008-05-21 19:16:45 +00001063}
1064
Paolo Bonzinicc8b6f52012-10-08 09:42:48 +02001065static void gen_setcc1(DisasContext *s, int b, TCGv reg)
1066{
1067 CCPrepare cc = gen_prepare_cc(s, b, reg);
1068
1069 if (cc.no_setcond) {
1070 if (cc.cond == TCG_COND_EQ) {
1071 tcg_gen_xori_tl(reg, cc.reg, 1);
1072 } else {
1073 tcg_gen_mov_tl(reg, cc.reg);
1074 }
1075 return;
1076 }
1077
1078 if (cc.cond == TCG_COND_NE && !cc.use_reg2 && cc.imm == 0 &&
1079 cc.mask != 0 && (cc.mask & (cc.mask - 1)) == 0) {
1080 tcg_gen_shri_tl(reg, cc.reg, ctztl(cc.mask));
1081 tcg_gen_andi_tl(reg, reg, 1);
1082 return;
1083 }
1084 if (cc.mask != -1) {
1085 tcg_gen_andi_tl(reg, cc.reg, cc.mask);
1086 cc.reg = reg;
1087 }
1088 if (cc.use_reg2) {
1089 tcg_gen_setcond_tl(cc.cond, reg, cc.reg, cc.reg2);
1090 } else {
1091 tcg_gen_setcondi_tl(cc.cond, reg, cc.reg, cc.imm);
1092 }
1093}
1094
1095static inline void gen_compute_eflags_c(DisasContext *s, TCGv reg)
1096{
1097 gen_setcc1(s, JCC_B << 1, reg);
1098}
Richard Henderson276e6b52013-01-23 14:33:45 -08001099
bellard8e1c85e2008-05-21 19:16:45 +00001100/* generate a conditional jump to label 'l1' according to jump opcode
1101 value 'b'. In the fast case, T0 is guaranted not to be used. */
Richard Henderson42a268c2015-02-13 12:51:55 -08001102static inline void gen_jcc1_noeob(DisasContext *s, int b, TCGLabel *l1)
bellard8e1c85e2008-05-21 19:16:45 +00001103{
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001104 CCPrepare cc = gen_prepare_cc(s, b, s->T0);
bellard8e1c85e2008-05-21 19:16:45 +00001105
Paolo Bonzini943131c2012-10-07 15:53:23 +02001106 if (cc.mask != -1) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001107 tcg_gen_andi_tl(s->T0, cc.reg, cc.mask);
1108 cc.reg = s->T0;
Paolo Bonzini943131c2012-10-07 15:53:23 +02001109 }
1110 if (cc.use_reg2) {
1111 tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1);
1112 } else {
1113 tcg_gen_brcondi_tl(cc.cond, cc.reg, cc.imm, l1);
bellard8e1c85e2008-05-21 19:16:45 +00001114 }
1115}
1116
Richard Hendersondc259202013-01-23 15:01:35 -08001117/* Generate a conditional jump to label 'l1' according to jump opcode
1118 value 'b'. In the fast case, T0 is guaranted not to be used.
1119 A translation block must end soon. */
Richard Henderson42a268c2015-02-13 12:51:55 -08001120static inline void gen_jcc1(DisasContext *s, int b, TCGLabel *l1)
Richard Hendersondc259202013-01-23 15:01:35 -08001121{
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001122 CCPrepare cc = gen_prepare_cc(s, b, s->T0);
Richard Hendersondc259202013-01-23 15:01:35 -08001123
1124 gen_update_cc_op(s);
1125 if (cc.mask != -1) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001126 tcg_gen_andi_tl(s->T0, cc.reg, cc.mask);
1127 cc.reg = s->T0;
Richard Hendersondc259202013-01-23 15:01:35 -08001128 }
1129 set_cc_op(s, CC_OP_DYNAMIC);
1130 if (cc.use_reg2) {
1131 tcg_gen_brcond_tl(cc.cond, cc.reg, cc.reg2, l1);
1132 } else {
1133 tcg_gen_brcondi_tl(cc.cond, cc.reg, cc.imm, l1);
1134 }
1135}
1136
bellard14ce26e2005-01-03 23:50:08 +00001137/* XXX: does not work with gdbstub "ice" single step - not a
1138 serious problem */
Richard Henderson42a268c2015-02-13 12:51:55 -08001139static TCGLabel *gen_jz_ecx_string(DisasContext *s, target_ulong next_eip)
bellard2c0262a2003-09-30 20:34:21 +00001140{
Richard Henderson42a268c2015-02-13 12:51:55 -08001141 TCGLabel *l1 = gen_new_label();
1142 TCGLabel *l2 = gen_new_label();
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001143 gen_op_jnz_ecx(s, s->aflag, l1);
bellard14ce26e2005-01-03 23:50:08 +00001144 gen_set_label(l2);
1145 gen_jmp_tb(s, next_eip, 1);
1146 gen_set_label(l1);
1147 return l2;
bellard2c0262a2003-09-30 20:34:21 +00001148}
1149
Tony Nguyen14776ab2019-08-24 04:10:58 +10001150static inline void gen_stos(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00001151{
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001152 gen_op_mov_v_reg(s, MO_32, s->T0, R_EAX);
bellard2c0262a2003-09-30 20:34:21 +00001153 gen_string_movl_A0_EDI(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001154 gen_op_st_v(s, ot, s->T0, s->A0);
1155 gen_op_movl_T0_Dshift(s, ot);
1156 gen_op_add_reg_T0(s, s->aflag, R_EDI);
bellard2c0262a2003-09-30 20:34:21 +00001157}
1158
Tony Nguyen14776ab2019-08-24 04:10:58 +10001159static inline void gen_lods(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00001160{
1161 gen_string_movl_A0_ESI(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001162 gen_op_ld_v(s, ot, s->T0, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001163 gen_op_mov_reg_v(s, ot, R_EAX, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001164 gen_op_movl_T0_Dshift(s, ot);
1165 gen_op_add_reg_T0(s, s->aflag, R_ESI);
bellard2c0262a2003-09-30 20:34:21 +00001166}
1167
Tony Nguyen14776ab2019-08-24 04:10:58 +10001168static inline void gen_scas(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00001169{
bellard2c0262a2003-09-30 20:34:21 +00001170 gen_string_movl_A0_EDI(s);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001171 gen_op_ld_v(s, ot, s->T1, s->A0);
Richard Henderson63633fe2013-01-23 14:51:34 -08001172 gen_op(s, OP_CMPL, ot, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001173 gen_op_movl_T0_Dshift(s, ot);
1174 gen_op_add_reg_T0(s, s->aflag, R_EDI);
bellard2c0262a2003-09-30 20:34:21 +00001175}
1176
Tony Nguyen14776ab2019-08-24 04:10:58 +10001177static inline void gen_cmps(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00001178{
bellard2c0262a2003-09-30 20:34:21 +00001179 gen_string_movl_A0_EDI(s);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001180 gen_op_ld_v(s, ot, s->T1, s->A0);
Richard Henderson63633fe2013-01-23 14:51:34 -08001181 gen_string_movl_A0_ESI(s);
1182 gen_op(s, OP_CMPL, ot, OR_TMP0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001183 gen_op_movl_T0_Dshift(s, ot);
1184 gen_op_add_reg_T0(s, s->aflag, R_ESI);
1185 gen_op_add_reg_T0(s, s->aflag, R_EDI);
bellard2c0262a2003-09-30 20:34:21 +00001186}
1187
Eduardo Habkost5223a942015-10-19 15:14:35 -02001188static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot)
1189{
1190 if (s->flags & HF_IOBPT_MASK) {
Claudio Fontana6d8d1a02021-03-22 14:27:49 +01001191#ifdef CONFIG_USER_ONLY
1192 /* user-mode cpu should not be in IOBPT mode */
1193 g_assert_not_reached();
1194#else
Eduardo Habkost5223a942015-10-19 15:14:35 -02001195 TCGv_i32 t_size = tcg_const_i32(1 << ot);
1196 TCGv t_next = tcg_const_tl(s->pc - s->cs_base);
1197
1198 gen_helper_bpt_io(cpu_env, t_port, t_size, t_next);
1199 tcg_temp_free_i32(t_size);
1200 tcg_temp_free(t_next);
Claudio Fontana6d8d1a02021-03-22 14:27:49 +01001201#endif /* CONFIG_USER_ONLY */
Eduardo Habkost5223a942015-10-19 15:14:35 -02001202 }
1203}
1204
Tony Nguyen14776ab2019-08-24 04:10:58 +10001205static inline void gen_ins(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00001206{
bellard2c0262a2003-09-30 20:34:21 +00001207 gen_string_movl_A0_EDI(s);
bellard6e0d8672008-05-18 19:28:26 +00001208 /* Note: we must do this dummy write first to be restartable in
1209 case of page fault. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001210 tcg_gen_movi_tl(s->T0, 0);
1211 gen_op_st_v(s, ot, s->T0, s->A0);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001212 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
1213 tcg_gen_andi_i32(s->tmp2_i32, s->tmp2_i32, 0xffff);
1214 gen_helper_in_func(ot, s->T0, s->tmp2_i32);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001215 gen_op_st_v(s, ot, s->T0, s->A0);
1216 gen_op_movl_T0_Dshift(s, ot);
1217 gen_op_add_reg_T0(s, s->aflag, R_EDI);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001218 gen_bpt_io(s, s->tmp2_i32, ot);
bellard2c0262a2003-09-30 20:34:21 +00001219}
1220
Tony Nguyen14776ab2019-08-24 04:10:58 +10001221static inline void gen_outs(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00001222{
1223 gen_string_movl_A0_ESI(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001224 gen_op_ld_v(s, ot, s->T0, s->A0);
bellardb8b6a502008-05-15 16:46:30 +00001225
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001226 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
1227 tcg_gen_andi_i32(s->tmp2_i32, s->tmp2_i32, 0xffff);
Emilio G. Cota4f824462018-09-11 14:17:56 -04001228 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T0);
1229 gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001230 gen_op_movl_T0_Dshift(s, ot);
1231 gen_op_add_reg_T0(s, s->aflag, R_ESI);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001232 gen_bpt_io(s, s->tmp2_i32, ot);
bellard2c0262a2003-09-30 20:34:21 +00001233}
1234
1235/* same method as Valgrind : we generate jumps to current or next
1236 instruction */
1237#define GEN_REPZ(op) \
Tony Nguyen14776ab2019-08-24 04:10:58 +10001238static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \
bellard14ce26e2005-01-03 23:50:08 +00001239 target_ulong cur_eip, target_ulong next_eip) \
bellard2c0262a2003-09-30 20:34:21 +00001240{ \
Richard Henderson42a268c2015-02-13 12:51:55 -08001241 TCGLabel *l2; \
bellard2c0262a2003-09-30 20:34:21 +00001242 gen_update_cc_op(s); \
bellard14ce26e2005-01-03 23:50:08 +00001243 l2 = gen_jz_ecx_string(s, next_eip); \
bellard2c0262a2003-09-30 20:34:21 +00001244 gen_ ## op(s, ot); \
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001245 gen_op_add_reg_im(s, s->aflag, R_ECX, -1); \
bellard2c0262a2003-09-30 20:34:21 +00001246 /* a loop would cause two single step exceptions if ECX = 1 \
1247 before rep string_insn */ \
Pavel Dovgalyukc4d45252014-12-05 12:11:13 +03001248 if (s->repz_opt) \
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001249 gen_op_jz_ecx(s, s->aflag, l2); \
bellard2c0262a2003-09-30 20:34:21 +00001250 gen_jmp(s, cur_eip); \
1251}
1252
1253#define GEN_REPZ2(op) \
Tony Nguyen14776ab2019-08-24 04:10:58 +10001254static inline void gen_repz_ ## op(DisasContext *s, MemOp ot, \
bellard14ce26e2005-01-03 23:50:08 +00001255 target_ulong cur_eip, \
1256 target_ulong next_eip, \
bellard2c0262a2003-09-30 20:34:21 +00001257 int nz) \
1258{ \
Richard Henderson42a268c2015-02-13 12:51:55 -08001259 TCGLabel *l2; \
bellard2c0262a2003-09-30 20:34:21 +00001260 gen_update_cc_op(s); \
bellard14ce26e2005-01-03 23:50:08 +00001261 l2 = gen_jz_ecx_string(s, next_eip); \
bellard2c0262a2003-09-30 20:34:21 +00001262 gen_ ## op(s, ot); \
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001263 gen_op_add_reg_im(s, s->aflag, R_ECX, -1); \
Richard Henderson773cdfc2013-01-23 12:43:12 -08001264 gen_update_cc_op(s); \
Paolo Bonzinib27fc132012-10-06 01:36:45 +02001265 gen_jcc1(s, (JCC_Z << 1) | (nz ^ 1), l2); \
Pavel Dovgalyukc4d45252014-12-05 12:11:13 +03001266 if (s->repz_opt) \
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001267 gen_op_jz_ecx(s, s->aflag, l2); \
bellard2c0262a2003-09-30 20:34:21 +00001268 gen_jmp(s, cur_eip); \
1269}
1270
1271GEN_REPZ(movs)
1272GEN_REPZ(stos)
1273GEN_REPZ(lods)
1274GEN_REPZ(ins)
1275GEN_REPZ(outs)
1276GEN_REPZ2(scas)
1277GEN_REPZ2(cmps)
1278
pbrooka7812ae2008-11-17 14:43:54 +00001279static void gen_helper_fp_arith_ST0_FT0(int op)
1280{
1281 switch (op) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001282 case 0:
1283 gen_helper_fadd_ST0_FT0(cpu_env);
1284 break;
1285 case 1:
1286 gen_helper_fmul_ST0_FT0(cpu_env);
1287 break;
1288 case 2:
1289 gen_helper_fcom_ST0_FT0(cpu_env);
1290 break;
1291 case 3:
1292 gen_helper_fcom_ST0_FT0(cpu_env);
1293 break;
1294 case 4:
1295 gen_helper_fsub_ST0_FT0(cpu_env);
1296 break;
1297 case 5:
1298 gen_helper_fsubr_ST0_FT0(cpu_env);
1299 break;
1300 case 6:
1301 gen_helper_fdiv_ST0_FT0(cpu_env);
1302 break;
1303 case 7:
1304 gen_helper_fdivr_ST0_FT0(cpu_env);
1305 break;
pbrooka7812ae2008-11-17 14:43:54 +00001306 }
1307}
bellard2c0262a2003-09-30 20:34:21 +00001308
1309/* NOTE the exception in "r" op ordering */
pbrooka7812ae2008-11-17 14:43:54 +00001310static void gen_helper_fp_arith_STN_ST0(int op, int opreg)
1311{
1312 TCGv_i32 tmp = tcg_const_i32(opreg);
1313 switch (op) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00001314 case 0:
1315 gen_helper_fadd_STN_ST0(cpu_env, tmp);
1316 break;
1317 case 1:
1318 gen_helper_fmul_STN_ST0(cpu_env, tmp);
1319 break;
1320 case 4:
1321 gen_helper_fsubr_STN_ST0(cpu_env, tmp);
1322 break;
1323 case 5:
1324 gen_helper_fsub_STN_ST0(cpu_env, tmp);
1325 break;
1326 case 6:
1327 gen_helper_fdivr_STN_ST0(cpu_env, tmp);
1328 break;
1329 case 7:
1330 gen_helper_fdiv_STN_ST0(cpu_env, tmp);
1331 break;
pbrooka7812ae2008-11-17 14:43:54 +00001332 }
1333}
bellard2c0262a2003-09-30 20:34:21 +00001334
Richard Hendersone84fcd72018-11-13 20:35:10 +01001335static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
1336{
1337 gen_update_cc_op(s);
1338 gen_jmp_im(s, cur_eip);
1339 gen_helper_raise_exception(cpu_env, tcg_const_i32(trapno));
1340 s->base.is_jmp = DISAS_NORETURN;
1341}
1342
1343/* Generate #UD for the current instruction. The assumption here is that
1344 the instruction is known, but it isn't allowed in the current cpu mode. */
1345static void gen_illegal_opcode(DisasContext *s)
1346{
1347 gen_exception(s, EXCP06_ILLOP, s->pc_start - s->cs_base);
1348}
1349
Richard Henderson6bd99582021-05-14 10:12:53 -05001350/* Generate #GP for the current instruction. */
1351static void gen_exception_gpf(DisasContext *s)
1352{
1353 gen_exception(s, EXCP0D_GPF, s->pc_start - s->cs_base);
1354}
1355
Richard Hendersonbc19f502021-05-14 10:12:54 -05001356/* Check for cpl == 0; if not, raise #GP and return false. */
1357static bool check_cpl0(DisasContext *s)
1358{
Richard Henderson01b9d8c2021-05-14 10:12:59 -05001359 if (CPL(s) == 0) {
Richard Hendersonbc19f502021-05-14 10:12:54 -05001360 return true;
1361 }
1362 gen_exception_gpf(s);
1363 return false;
1364}
1365
Richard Hendersonaa9f21b2021-05-14 10:12:56 -05001366/* If vm86, check for iopl == 3; if not, raise #GP and return false. */
1367static bool check_vm86_iopl(DisasContext *s)
1368{
Richard Hendersonf8a35842021-05-14 10:13:01 -05001369 if (!VM86(s) || IOPL(s) == 3) {
Richard Hendersonaa9f21b2021-05-14 10:12:56 -05001370 return true;
1371 }
1372 gen_exception_gpf(s);
1373 return false;
1374}
1375
Richard Hendersonca7874c2021-05-14 10:12:57 -05001376/* Check for iopl allowing access; if not, raise #GP and return false. */
1377static bool check_iopl(DisasContext *s)
1378{
Richard Hendersonf8a35842021-05-14 10:13:01 -05001379 if (VM86(s) ? IOPL(s) == 3 : CPL(s) <= IOPL(s)) {
Richard Hendersonca7874c2021-05-14 10:12:57 -05001380 return true;
1381 }
1382 gen_exception_gpf(s);
1383 return false;
1384}
1385
bellardcad3a372008-05-17 13:50:02 +00001386/* if d == OR_TMP0, it means memory operand (address in A0) */
Tony Nguyen14776ab2019-08-24 04:10:58 +10001387static void gen_op(DisasContext *s1, int op, MemOp ot, int d)
bellardcad3a372008-05-17 13:50:02 +00001388{
1389 if (d != OR_TMP0) {
Richard Hendersone84fcd72018-11-13 20:35:10 +01001390 if (s1->prefix & PREFIX_LOCK) {
1391 /* Lock prefix when destination is not memory. */
1392 gen_illegal_opcode(s1);
1393 return;
1394 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001395 gen_op_mov_v_reg(s1, ot, s1->T0, d);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001396 } else if (!(s1->prefix & PREFIX_LOCK)) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001397 gen_op_ld_v(s1, ot, s1->T0, s1->A0);
bellardcad3a372008-05-17 13:50:02 +00001398 }
1399 switch(op) {
1400 case OP_ADCL:
Emilio G. Cota5022f282018-09-11 14:10:21 -04001401 gen_compute_eflags_c(s1, s1->tmp4);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001402 if (s1->prefix & PREFIX_LOCK) {
Emilio G. Cota5022f282018-09-11 14:10:21 -04001403 tcg_gen_add_tl(s1->T0, s1->tmp4, s1->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001404 tcg_gen_atomic_add_fetch_tl(s1->T0, s1->A0, s1->T0,
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001405 s1->mem_index, ot | MO_LE);
1406 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001407 tcg_gen_add_tl(s1->T0, s1->T0, s1->T1);
Emilio G. Cota5022f282018-09-11 14:10:21 -04001408 tcg_gen_add_tl(s1->T0, s1->T0, s1->tmp4);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001409 gen_op_st_rm_T0_A0(s1, ot, d);
1410 }
Emilio G. Cota5022f282018-09-11 14:10:21 -04001411 gen_op_update3_cc(s1, s1->tmp4);
Richard Henderson988c3eb2013-01-23 16:03:16 -08001412 set_cc_op(s1, CC_OP_ADCB + ot);
bellardcad3a372008-05-17 13:50:02 +00001413 break;
1414 case OP_SBBL:
Emilio G. Cota5022f282018-09-11 14:10:21 -04001415 gen_compute_eflags_c(s1, s1->tmp4);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001416 if (s1->prefix & PREFIX_LOCK) {
Emilio G. Cota5022f282018-09-11 14:10:21 -04001417 tcg_gen_add_tl(s1->T0, s1->T1, s1->tmp4);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001418 tcg_gen_neg_tl(s1->T0, s1->T0);
1419 tcg_gen_atomic_add_fetch_tl(s1->T0, s1->A0, s1->T0,
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001420 s1->mem_index, ot | MO_LE);
1421 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001422 tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1);
Emilio G. Cota5022f282018-09-11 14:10:21 -04001423 tcg_gen_sub_tl(s1->T0, s1->T0, s1->tmp4);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001424 gen_op_st_rm_T0_A0(s1, ot, d);
1425 }
Emilio G. Cota5022f282018-09-11 14:10:21 -04001426 gen_op_update3_cc(s1, s1->tmp4);
Richard Henderson988c3eb2013-01-23 16:03:16 -08001427 set_cc_op(s1, CC_OP_SBBB + ot);
bellardcad3a372008-05-17 13:50:02 +00001428 break;
1429 case OP_ADDL:
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001430 if (s1->prefix & PREFIX_LOCK) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001431 tcg_gen_atomic_add_fetch_tl(s1->T0, s1->A0, s1->T1,
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001432 s1->mem_index, ot | MO_LE);
1433 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001434 tcg_gen_add_tl(s1->T0, s1->T0, s1->T1);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001435 gen_op_st_rm_T0_A0(s1, ot, d);
1436 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001437 gen_op_update2_cc(s1);
Richard Henderson3ca51d02013-01-23 12:30:52 -08001438 set_cc_op(s1, CC_OP_ADDB + ot);
bellardcad3a372008-05-17 13:50:02 +00001439 break;
1440 case OP_SUBL:
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001441 if (s1->prefix & PREFIX_LOCK) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001442 tcg_gen_neg_tl(s1->T0, s1->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001443 tcg_gen_atomic_fetch_add_tl(s1->cc_srcT, s1->A0, s1->T0,
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001444 s1->mem_index, ot | MO_LE);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001445 tcg_gen_sub_tl(s1->T0, s1->cc_srcT, s1->T1);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001446 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001447 tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001448 tcg_gen_sub_tl(s1->T0, s1->T0, s1->T1);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001449 gen_op_st_rm_T0_A0(s1, ot, d);
1450 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001451 gen_op_update2_cc(s1);
Richard Henderson3ca51d02013-01-23 12:30:52 -08001452 set_cc_op(s1, CC_OP_SUBB + ot);
bellardcad3a372008-05-17 13:50:02 +00001453 break;
1454 default:
1455 case OP_ANDL:
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001456 if (s1->prefix & PREFIX_LOCK) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001457 tcg_gen_atomic_and_fetch_tl(s1->T0, s1->A0, s1->T1,
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001458 s1->mem_index, ot | MO_LE);
1459 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001460 tcg_gen_and_tl(s1->T0, s1->T0, s1->T1);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001461 gen_op_st_rm_T0_A0(s1, ot, d);
1462 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001463 gen_op_update1_cc(s1);
Richard Henderson3ca51d02013-01-23 12:30:52 -08001464 set_cc_op(s1, CC_OP_LOGICB + ot);
bellardcad3a372008-05-17 13:50:02 +00001465 break;
1466 case OP_ORL:
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001467 if (s1->prefix & PREFIX_LOCK) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001468 tcg_gen_atomic_or_fetch_tl(s1->T0, s1->A0, s1->T1,
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001469 s1->mem_index, ot | MO_LE);
1470 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001471 tcg_gen_or_tl(s1->T0, s1->T0, s1->T1);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001472 gen_op_st_rm_T0_A0(s1, ot, d);
1473 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001474 gen_op_update1_cc(s1);
Richard Henderson3ca51d02013-01-23 12:30:52 -08001475 set_cc_op(s1, CC_OP_LOGICB + ot);
bellardcad3a372008-05-17 13:50:02 +00001476 break;
1477 case OP_XORL:
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001478 if (s1->prefix & PREFIX_LOCK) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001479 tcg_gen_atomic_xor_fetch_tl(s1->T0, s1->A0, s1->T1,
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001480 s1->mem_index, ot | MO_LE);
1481 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001482 tcg_gen_xor_tl(s1->T0, s1->T0, s1->T1);
Emilio G. Cotaa7cee522016-06-27 15:01:58 -04001483 gen_op_st_rm_T0_A0(s1, ot, d);
1484 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001485 gen_op_update1_cc(s1);
Richard Henderson3ca51d02013-01-23 12:30:52 -08001486 set_cc_op(s1, CC_OP_LOGICB + ot);
bellardcad3a372008-05-17 13:50:02 +00001487 break;
1488 case OP_CMPL:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001489 tcg_gen_mov_tl(cpu_cc_src, s1->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001490 tcg_gen_mov_tl(s1->cc_srcT, s1->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001491 tcg_gen_sub_tl(cpu_cc_dst, s1->T0, s1->T1);
Richard Henderson3ca51d02013-01-23 12:30:52 -08001492 set_cc_op(s1, CC_OP_SUBB + ot);
bellardcad3a372008-05-17 13:50:02 +00001493 break;
1494 }
bellardb6abf972008-05-17 12:44:31 +00001495}
1496
bellard2c0262a2003-09-30 20:34:21 +00001497/* if d == OR_TMP0, it means memory operand (address in A0) */
Tony Nguyen14776ab2019-08-24 04:10:58 +10001498static void gen_inc(DisasContext *s1, MemOp ot, int d, int c)
bellard2c0262a2003-09-30 20:34:21 +00001499{
Emilio G. Cota60e57342016-06-27 15:01:59 -04001500 if (s1->prefix & PREFIX_LOCK) {
Peter Maydell8cb2ca32019-03-28 10:47:50 +00001501 if (d != OR_TMP0) {
1502 /* Lock prefix when destination is not memory */
1503 gen_illegal_opcode(s1);
1504 return;
1505 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001506 tcg_gen_movi_tl(s1->T0, c > 0 ? 1 : -1);
1507 tcg_gen_atomic_add_fetch_tl(s1->T0, s1->A0, s1->T0,
Emilio G. Cota60e57342016-06-27 15:01:59 -04001508 s1->mem_index, ot | MO_LE);
Richard Henderson909be182013-11-02 10:30:24 -07001509 } else {
Emilio G. Cota60e57342016-06-27 15:01:59 -04001510 if (d != OR_TMP0) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001511 gen_op_mov_v_reg(s1, ot, s1->T0, d);
Emilio G. Cota60e57342016-06-27 15:01:59 -04001512 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001513 gen_op_ld_v(s1, ot, s1->T0, s1->A0);
Emilio G. Cota60e57342016-06-27 15:01:59 -04001514 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001515 tcg_gen_addi_tl(s1->T0, s1->T0, (c > 0 ? 1 : -1));
Emilio G. Cota60e57342016-06-27 15:01:59 -04001516 gen_op_st_rm_T0_A0(s1, ot, d);
Richard Henderson909be182013-11-02 10:30:24 -07001517 }
Emilio G. Cota60e57342016-06-27 15:01:59 -04001518
Paolo Bonzinicc8b6f52012-10-08 09:42:48 +02001519 gen_compute_eflags_c(s1, cpu_cc_src);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001520 tcg_gen_mov_tl(cpu_cc_dst, s1->T0);
Emilio G. Cota60e57342016-06-27 15:01:59 -04001521 set_cc_op(s1, (c > 0 ? CC_OP_INCB : CC_OP_DECB) + ot);
bellardb6abf972008-05-17 12:44:31 +00001522}
1523
Tony Nguyen14776ab2019-08-24 04:10:58 +10001524static void gen_shift_flags(DisasContext *s, MemOp ot, TCGv result,
Richard Hendersond67dc9e2013-11-06 07:25:05 +10001525 TCGv shm1, TCGv count, bool is_right)
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001526{
1527 TCGv_i32 z32, s32, oldop;
1528 TCGv z_tl;
1529
1530 /* Store the results into the CC variables. If we know that the
1531 variable must be dead, store unconditionally. Otherwise we'll
1532 need to not disrupt the current contents. */
1533 z_tl = tcg_const_tl(0);
1534 if (cc_op_live[s->cc_op] & USES_CC_DST) {
1535 tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_dst, count, z_tl,
1536 result, cpu_cc_dst);
1537 } else {
1538 tcg_gen_mov_tl(cpu_cc_dst, result);
1539 }
1540 if (cc_op_live[s->cc_op] & USES_CC_SRC) {
1541 tcg_gen_movcond_tl(TCG_COND_NE, cpu_cc_src, count, z_tl,
1542 shm1, cpu_cc_src);
1543 } else {
1544 tcg_gen_mov_tl(cpu_cc_src, shm1);
1545 }
1546 tcg_temp_free(z_tl);
1547
1548 /* Get the two potential CC_OP values into temporaries. */
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001549 tcg_gen_movi_i32(s->tmp2_i32, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001550 if (s->cc_op == CC_OP_DYNAMIC) {
1551 oldop = cpu_cc_op;
1552 } else {
Emilio G. Cota4f824462018-09-11 14:17:56 -04001553 tcg_gen_movi_i32(s->tmp3_i32, s->cc_op);
1554 oldop = s->tmp3_i32;
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001555 }
1556
1557 /* Conditionally store the CC_OP value. */
1558 z32 = tcg_const_i32(0);
1559 s32 = tcg_temp_new_i32();
1560 tcg_gen_trunc_tl_i32(s32, count);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001561 tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, s32, z32, s->tmp2_i32, oldop);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001562 tcg_temp_free_i32(z32);
1563 tcg_temp_free_i32(s32);
1564
1565 /* The CC_OP value is no longer predictable. */
1566 set_cc_op(s, CC_OP_DYNAMIC);
1567}
1568
Tony Nguyen14776ab2019-08-24 04:10:58 +10001569static void gen_shift_rm_T1(DisasContext *s, MemOp ot, int op1,
bellardb6abf972008-05-17 12:44:31 +00001570 int is_right, int is_arith)
1571{
Richard Henderson4ba99382013-11-02 09:54:47 -07001572 target_ulong mask = (ot == MO_64 ? 0x3f : 0x1f);
bellardb6abf972008-05-17 12:44:31 +00001573
1574 /* load */
Richard Henderson82786042011-09-08 09:23:11 +01001575 if (op1 == OR_TMP0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001576 gen_op_ld_v(s, ot, s->T0, s->A0);
Richard Henderson82786042011-09-08 09:23:11 +01001577 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001578 gen_op_mov_v_reg(s, ot, s->T0, op1);
Richard Henderson82786042011-09-08 09:23:11 +01001579 }
bellardb6abf972008-05-17 12:44:31 +00001580
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001581 tcg_gen_andi_tl(s->T1, s->T1, mask);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001582 tcg_gen_subi_tl(s->tmp0, s->T1, 1);
bellardb6abf972008-05-17 12:44:31 +00001583
1584 if (is_right) {
1585 if (is_arith) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001586 gen_exts(ot, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001587 tcg_gen_sar_tl(s->tmp0, s->T0, s->tmp0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001588 tcg_gen_sar_tl(s->T0, s->T0, s->T1);
bellardb6abf972008-05-17 12:44:31 +00001589 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001590 gen_extu(ot, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001591 tcg_gen_shr_tl(s->tmp0, s->T0, s->tmp0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001592 tcg_gen_shr_tl(s->T0, s->T0, s->T1);
bellardb6abf972008-05-17 12:44:31 +00001593 }
1594 } else {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001595 tcg_gen_shl_tl(s->tmp0, s->T0, s->tmp0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001596 tcg_gen_shl_tl(s->T0, s->T0, s->T1);
bellardb6abf972008-05-17 12:44:31 +00001597 }
1598
1599 /* store */
Richard Hendersond4faa3e2013-11-02 10:59:43 -07001600 gen_op_st_rm_T0_A0(s, ot, op1);
Richard Henderson82786042011-09-08 09:23:11 +01001601
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001602 gen_shift_flags(s, ot, s->T0, s->tmp0, s->T1, is_right);
bellardb6abf972008-05-17 12:44:31 +00001603}
1604
Tony Nguyen14776ab2019-08-24 04:10:58 +10001605static void gen_shift_rm_im(DisasContext *s, MemOp ot, int op1, int op2,
bellardc1c37962008-05-22 12:36:31 +00001606 int is_right, int is_arith)
1607{
Richard Henderson4ba99382013-11-02 09:54:47 -07001608 int mask = (ot == MO_64 ? 0x3f : 0x1f);
bellardc1c37962008-05-22 12:36:31 +00001609
1610 /* load */
1611 if (op1 == OR_TMP0)
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001612 gen_op_ld_v(s, ot, s->T0, s->A0);
bellardc1c37962008-05-22 12:36:31 +00001613 else
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001614 gen_op_mov_v_reg(s, ot, s->T0, op1);
bellardc1c37962008-05-22 12:36:31 +00001615
1616 op2 &= mask;
1617 if (op2 != 0) {
1618 if (is_right) {
1619 if (is_arith) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001620 gen_exts(ot, s->T0);
Emilio G. Cota5022f282018-09-11 14:10:21 -04001621 tcg_gen_sari_tl(s->tmp4, s->T0, op2 - 1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001622 tcg_gen_sari_tl(s->T0, s->T0, op2);
bellardc1c37962008-05-22 12:36:31 +00001623 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001624 gen_extu(ot, s->T0);
Emilio G. Cota5022f282018-09-11 14:10:21 -04001625 tcg_gen_shri_tl(s->tmp4, s->T0, op2 - 1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001626 tcg_gen_shri_tl(s->T0, s->T0, op2);
bellardc1c37962008-05-22 12:36:31 +00001627 }
1628 } else {
Emilio G. Cota5022f282018-09-11 14:10:21 -04001629 tcg_gen_shli_tl(s->tmp4, s->T0, op2 - 1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001630 tcg_gen_shli_tl(s->T0, s->T0, op2);
bellardc1c37962008-05-22 12:36:31 +00001631 }
1632 }
1633
1634 /* store */
Richard Hendersond4faa3e2013-11-02 10:59:43 -07001635 gen_op_st_rm_T0_A0(s, ot, op1);
1636
bellardc1c37962008-05-22 12:36:31 +00001637 /* update eflags if non zero shift */
1638 if (op2 != 0) {
Emilio G. Cota5022f282018-09-11 14:10:21 -04001639 tcg_gen_mov_tl(cpu_cc_src, s->tmp4);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001640 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
Richard Henderson3ca51d02013-01-23 12:30:52 -08001641 set_cc_op(s, (is_right ? CC_OP_SARB : CC_OP_SHLB) + ot);
bellardc1c37962008-05-22 12:36:31 +00001642 }
1643}
1644
Tony Nguyen14776ab2019-08-24 04:10:58 +10001645static void gen_rot_rm_T1(DisasContext *s, MemOp ot, int op1, int is_right)
bellardb6abf972008-05-17 12:44:31 +00001646{
Richard Henderson4ba99382013-11-02 09:54:47 -07001647 target_ulong mask = (ot == MO_64 ? 0x3f : 0x1f);
Richard Henderson34d80a52013-01-30 19:16:45 -08001648 TCGv_i32 t0, t1;
bellardb6abf972008-05-17 12:44:31 +00001649
1650 /* load */
bellard1e4840b2008-05-25 17:26:41 +00001651 if (op1 == OR_TMP0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001652 gen_op_ld_v(s, ot, s->T0, s->A0);
bellard1e4840b2008-05-25 17:26:41 +00001653 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001654 gen_op_mov_v_reg(s, ot, s->T0, op1);
bellard1e4840b2008-05-25 17:26:41 +00001655 }
bellardb6abf972008-05-17 12:44:31 +00001656
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001657 tcg_gen_andi_tl(s->T1, s->T1, mask);
bellard1e4840b2008-05-25 17:26:41 +00001658
Richard Henderson34d80a52013-01-30 19:16:45 -08001659 switch (ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07001660 case MO_8:
Richard Henderson34d80a52013-01-30 19:16:45 -08001661 /* Replicate the 8-bit input so that a 32-bit rotate works. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001662 tcg_gen_ext8u_tl(s->T0, s->T0);
1663 tcg_gen_muli_tl(s->T0, s->T0, 0x01010101);
Richard Henderson34d80a52013-01-30 19:16:45 -08001664 goto do_long;
Richard Henderson4ba99382013-11-02 09:54:47 -07001665 case MO_16:
Richard Henderson34d80a52013-01-30 19:16:45 -08001666 /* Replicate the 16-bit input so that a 32-bit rotate works. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001667 tcg_gen_deposit_tl(s->T0, s->T0, s->T0, 16, 16);
Richard Henderson34d80a52013-01-30 19:16:45 -08001668 goto do_long;
1669 do_long:
1670#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07001671 case MO_32:
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001672 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
Emilio G. Cota4f824462018-09-11 14:17:56 -04001673 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
Richard Henderson34d80a52013-01-30 19:16:45 -08001674 if (is_right) {
Emilio G. Cota4f824462018-09-11 14:17:56 -04001675 tcg_gen_rotr_i32(s->tmp2_i32, s->tmp2_i32, s->tmp3_i32);
Richard Henderson34d80a52013-01-30 19:16:45 -08001676 } else {
Emilio G. Cota4f824462018-09-11 14:17:56 -04001677 tcg_gen_rotl_i32(s->tmp2_i32, s->tmp2_i32, s->tmp3_i32);
Richard Henderson34d80a52013-01-30 19:16:45 -08001678 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001679 tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
Richard Henderson34d80a52013-01-30 19:16:45 -08001680 break;
1681#endif
1682 default:
1683 if (is_right) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001684 tcg_gen_rotr_tl(s->T0, s->T0, s->T1);
Richard Henderson34d80a52013-01-30 19:16:45 -08001685 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001686 tcg_gen_rotl_tl(s->T0, s->T0, s->T1);
Richard Henderson34d80a52013-01-30 19:16:45 -08001687 }
1688 break;
bellardb6abf972008-05-17 12:44:31 +00001689 }
bellardb6abf972008-05-17 12:44:31 +00001690
bellardb6abf972008-05-17 12:44:31 +00001691 /* store */
Richard Hendersond4faa3e2013-11-02 10:59:43 -07001692 gen_op_st_rm_T0_A0(s, ot, op1);
Richard Henderson34d80a52013-01-30 19:16:45 -08001693
1694 /* We'll need the flags computed into CC_SRC. */
Richard Hendersond229edc2013-01-23 13:03:26 -08001695 gen_compute_eflags(s);
bellardb6abf972008-05-17 12:44:31 +00001696
Richard Henderson34d80a52013-01-30 19:16:45 -08001697 /* The value that was "rotated out" is now present at the other end
1698 of the word. Compute C into CC_DST and O into CC_SRC2. Note that
1699 since we've computed the flags into CC_SRC, these variables are
1700 currently dead. */
bellardb6abf972008-05-17 12:44:31 +00001701 if (is_right) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001702 tcg_gen_shri_tl(cpu_cc_src2, s->T0, mask - 1);
1703 tcg_gen_shri_tl(cpu_cc_dst, s->T0, mask);
Pavel Dovgaluk089305a2013-04-15 10:59:15 +04001704 tcg_gen_andi_tl(cpu_cc_dst, cpu_cc_dst, 1);
Richard Henderson34d80a52013-01-30 19:16:45 -08001705 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001706 tcg_gen_shri_tl(cpu_cc_src2, s->T0, mask);
1707 tcg_gen_andi_tl(cpu_cc_dst, s->T0, 1);
bellardb6abf972008-05-17 12:44:31 +00001708 }
Richard Henderson34d80a52013-01-30 19:16:45 -08001709 tcg_gen_andi_tl(cpu_cc_src2, cpu_cc_src2, 1);
1710 tcg_gen_xor_tl(cpu_cc_src2, cpu_cc_src2, cpu_cc_dst);
Paolo Bonzini0ff6add2012-10-06 00:18:55 +02001711
Richard Henderson34d80a52013-01-30 19:16:45 -08001712 /* Now conditionally store the new CC_OP value. If the shift count
1713 is 0 we keep the CC_OP_EFLAGS setting so that only CC_SRC is live.
1714 Otherwise reuse CC_OP_ADCOX which have the C and O flags split out
1715 exactly as we computed above. */
1716 t0 = tcg_const_i32(0);
1717 t1 = tcg_temp_new_i32();
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001718 tcg_gen_trunc_tl_i32(t1, s->T1);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001719 tcg_gen_movi_i32(s->tmp2_i32, CC_OP_ADCOX);
Emilio G. Cota4f824462018-09-11 14:17:56 -04001720 tcg_gen_movi_i32(s->tmp3_i32, CC_OP_EFLAGS);
Richard Henderson34d80a52013-01-30 19:16:45 -08001721 tcg_gen_movcond_i32(TCG_COND_NE, cpu_cc_op, t1, t0,
Emilio G. Cota4f824462018-09-11 14:17:56 -04001722 s->tmp2_i32, s->tmp3_i32);
Richard Henderson34d80a52013-01-30 19:16:45 -08001723 tcg_temp_free_i32(t0);
1724 tcg_temp_free_i32(t1);
bellard1e4840b2008-05-25 17:26:41 +00001725
Richard Henderson34d80a52013-01-30 19:16:45 -08001726 /* The CC_OP value is no longer predictable. */
1727 set_cc_op(s, CC_OP_DYNAMIC);
bellardb6abf972008-05-17 12:44:31 +00001728}
1729
Tony Nguyen14776ab2019-08-24 04:10:58 +10001730static void gen_rot_rm_im(DisasContext *s, MemOp ot, int op1, int op2,
malc8cd63452009-04-02 22:54:35 +00001731 int is_right)
1732{
Richard Henderson4ba99382013-11-02 09:54:47 -07001733 int mask = (ot == MO_64 ? 0x3f : 0x1f);
Richard Henderson34d80a52013-01-30 19:16:45 -08001734 int shift;
malc8cd63452009-04-02 22:54:35 +00001735
1736 /* load */
1737 if (op1 == OR_TMP0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001738 gen_op_ld_v(s, ot, s->T0, s->A0);
malc8cd63452009-04-02 22:54:35 +00001739 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001740 gen_op_mov_v_reg(s, ot, s->T0, op1);
malc8cd63452009-04-02 22:54:35 +00001741 }
1742
malc8cd63452009-04-02 22:54:35 +00001743 op2 &= mask;
malc8cd63452009-04-02 22:54:35 +00001744 if (op2 != 0) {
Richard Henderson34d80a52013-01-30 19:16:45 -08001745 switch (ot) {
1746#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07001747 case MO_32:
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001748 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
Richard Henderson34d80a52013-01-30 19:16:45 -08001749 if (is_right) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001750 tcg_gen_rotri_i32(s->tmp2_i32, s->tmp2_i32, op2);
Richard Henderson34d80a52013-01-30 19:16:45 -08001751 } else {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001752 tcg_gen_rotli_i32(s->tmp2_i32, s->tmp2_i32, op2);
Richard Henderson34d80a52013-01-30 19:16:45 -08001753 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04001754 tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
Richard Henderson34d80a52013-01-30 19:16:45 -08001755 break;
1756#endif
1757 default:
1758 if (is_right) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001759 tcg_gen_rotri_tl(s->T0, s->T0, op2);
Richard Henderson34d80a52013-01-30 19:16:45 -08001760 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001761 tcg_gen_rotli_tl(s->T0, s->T0, op2);
Richard Henderson34d80a52013-01-30 19:16:45 -08001762 }
1763 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07001764 case MO_8:
Richard Henderson34d80a52013-01-30 19:16:45 -08001765 mask = 7;
1766 goto do_shifts;
Richard Henderson4ba99382013-11-02 09:54:47 -07001767 case MO_16:
Richard Henderson34d80a52013-01-30 19:16:45 -08001768 mask = 15;
1769 do_shifts:
1770 shift = op2 & mask;
1771 if (is_right) {
1772 shift = mask + 1 - shift;
1773 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001774 gen_extu(ot, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001775 tcg_gen_shli_tl(s->tmp0, s->T0, shift);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001776 tcg_gen_shri_tl(s->T0, s->T0, mask + 1 - shift);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001777 tcg_gen_or_tl(s->T0, s->T0, s->tmp0);
Richard Henderson34d80a52013-01-30 19:16:45 -08001778 break;
malc8cd63452009-04-02 22:54:35 +00001779 }
malc8cd63452009-04-02 22:54:35 +00001780 }
1781
1782 /* store */
Richard Hendersond4faa3e2013-11-02 10:59:43 -07001783 gen_op_st_rm_T0_A0(s, ot, op1);
malc8cd63452009-04-02 22:54:35 +00001784
1785 if (op2 != 0) {
Richard Henderson34d80a52013-01-30 19:16:45 -08001786 /* Compute the flags into CC_SRC. */
Richard Hendersond229edc2013-01-23 13:03:26 -08001787 gen_compute_eflags(s);
Paolo Bonzini0ff6add2012-10-06 00:18:55 +02001788
Richard Henderson34d80a52013-01-30 19:16:45 -08001789 /* The value that was "rotated out" is now present at the other end
1790 of the word. Compute C into CC_DST and O into CC_SRC2. Note that
1791 since we've computed the flags into CC_SRC, these variables are
1792 currently dead. */
malc8cd63452009-04-02 22:54:35 +00001793 if (is_right) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001794 tcg_gen_shri_tl(cpu_cc_src2, s->T0, mask - 1);
1795 tcg_gen_shri_tl(cpu_cc_dst, s->T0, mask);
Aurelien Jarno38ebb392013-05-09 19:36:41 +02001796 tcg_gen_andi_tl(cpu_cc_dst, cpu_cc_dst, 1);
Richard Henderson34d80a52013-01-30 19:16:45 -08001797 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001798 tcg_gen_shri_tl(cpu_cc_src2, s->T0, mask);
1799 tcg_gen_andi_tl(cpu_cc_dst, s->T0, 1);
malc8cd63452009-04-02 22:54:35 +00001800 }
Richard Henderson34d80a52013-01-30 19:16:45 -08001801 tcg_gen_andi_tl(cpu_cc_src2, cpu_cc_src2, 1);
1802 tcg_gen_xor_tl(cpu_cc_src2, cpu_cc_src2, cpu_cc_dst);
1803 set_cc_op(s, CC_OP_ADCOX);
malc8cd63452009-04-02 22:54:35 +00001804 }
malc8cd63452009-04-02 22:54:35 +00001805}
1806
bellardb6abf972008-05-17 12:44:31 +00001807/* XXX: add faster immediate = 1 case */
Tony Nguyen14776ab2019-08-24 04:10:58 +10001808static void gen_rotc_rm_T1(DisasContext *s, MemOp ot, int op1,
bellardb6abf972008-05-17 12:44:31 +00001809 int is_right)
1810{
Richard Hendersond229edc2013-01-23 13:03:26 -08001811 gen_compute_eflags(s);
Paolo Bonzinic7b3c872012-10-05 18:29:21 +02001812 assert(s->cc_op == CC_OP_EFLAGS);
bellardb6abf972008-05-17 12:44:31 +00001813
1814 /* load */
1815 if (op1 == OR_TMP0)
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001816 gen_op_ld_v(s, ot, s->T0, s->A0);
bellardb6abf972008-05-17 12:44:31 +00001817 else
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001818 gen_op_mov_v_reg(s, ot, s->T0, op1);
bellardb6abf972008-05-17 12:44:31 +00001819
pbrooka7812ae2008-11-17 14:43:54 +00001820 if (is_right) {
1821 switch (ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07001822 case MO_8:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001823 gen_helper_rcrb(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001824 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07001825 case MO_16:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001826 gen_helper_rcrw(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001827 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07001828 case MO_32:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001829 gen_helper_rcrl(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001830 break;
pbrooka7812ae2008-11-17 14:43:54 +00001831#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07001832 case MO_64:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001833 gen_helper_rcrq(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001834 break;
pbrooka7812ae2008-11-17 14:43:54 +00001835#endif
Richard Hendersond67dc9e2013-11-06 07:25:05 +10001836 default:
1837 tcg_abort();
pbrooka7812ae2008-11-17 14:43:54 +00001838 }
1839 } else {
1840 switch (ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07001841 case MO_8:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001842 gen_helper_rclb(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001843 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07001844 case MO_16:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001845 gen_helper_rclw(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001846 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07001847 case MO_32:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001848 gen_helper_rcll(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001849 break;
pbrooka7812ae2008-11-17 14:43:54 +00001850#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07001851 case MO_64:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001852 gen_helper_rclq(s->T0, cpu_env, s->T0, s->T1);
Blue Swirl79230572012-04-29 14:11:56 +00001853 break;
pbrooka7812ae2008-11-17 14:43:54 +00001854#endif
Richard Hendersond67dc9e2013-11-06 07:25:05 +10001855 default:
1856 tcg_abort();
pbrooka7812ae2008-11-17 14:43:54 +00001857 }
1858 }
bellardb6abf972008-05-17 12:44:31 +00001859 /* store */
Richard Hendersond4faa3e2013-11-02 10:59:43 -07001860 gen_op_st_rm_T0_A0(s, ot, op1);
bellardb6abf972008-05-17 12:44:31 +00001861}
1862
1863/* XXX: add faster immediate case */
Tony Nguyen14776ab2019-08-24 04:10:58 +10001864static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot, int op1,
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001865 bool is_right, TCGv count_in)
bellardb6abf972008-05-17 12:44:31 +00001866{
Richard Henderson4ba99382013-11-02 09:54:47 -07001867 target_ulong mask = (ot == MO_64 ? 63 : 31);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001868 TCGv count;
bellardb6abf972008-05-17 12:44:31 +00001869
1870 /* load */
bellard1e4840b2008-05-25 17:26:41 +00001871 if (op1 == OR_TMP0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001872 gen_op_ld_v(s, ot, s->T0, s->A0);
bellard1e4840b2008-05-25 17:26:41 +00001873 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001874 gen_op_mov_v_reg(s, ot, s->T0, op1);
bellard1e4840b2008-05-25 17:26:41 +00001875 }
bellardb6abf972008-05-17 12:44:31 +00001876
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001877 count = tcg_temp_new();
1878 tcg_gen_andi_tl(count, count_in, mask);
bellard1e4840b2008-05-25 17:26:41 +00001879
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001880 switch (ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07001881 case MO_16:
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001882 /* Note: we implement the Intel behaviour for shift count > 16.
1883 This means "shrdw C, B, A" shifts A:B:A >> C. Build the B:A
1884 portion by constructing it as a 32-bit value. */
bellardb6abf972008-05-17 12:44:31 +00001885 if (is_right) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001886 tcg_gen_deposit_tl(s->tmp0, s->T0, s->T1, 16, 16);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001887 tcg_gen_mov_tl(s->T1, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001888 tcg_gen_mov_tl(s->T0, s->tmp0);
bellardb6abf972008-05-17 12:44:31 +00001889 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001890 tcg_gen_deposit_tl(s->T1, s->T0, s->T1, 16, 16);
bellardb6abf972008-05-17 12:44:31 +00001891 }
Chen Qunbdddc1c2020-12-11 16:24:19 +01001892 /*
1893 * If TARGET_X86_64 defined then fall through into MO_32 case,
1894 * otherwise fall through default case.
1895 */
Richard Henderson4ba99382013-11-02 09:54:47 -07001896 case MO_32:
Chen Qunbdddc1c2020-12-11 16:24:19 +01001897#ifdef TARGET_X86_64
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001898 /* Concatenate the two 32-bit values and use a 64-bit shift. */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001899 tcg_gen_subi_tl(s->tmp0, count, 1);
bellardb6abf972008-05-17 12:44:31 +00001900 if (is_right) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001901 tcg_gen_concat_tl_i64(s->T0, s->T0, s->T1);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001902 tcg_gen_shr_i64(s->tmp0, s->T0, s->tmp0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001903 tcg_gen_shr_i64(s->T0, s->T0, count);
bellardb6abf972008-05-17 12:44:31 +00001904 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001905 tcg_gen_concat_tl_i64(s->T0, s->T1, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001906 tcg_gen_shl_i64(s->tmp0, s->T0, s->tmp0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001907 tcg_gen_shl_i64(s->T0, s->T0, count);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001908 tcg_gen_shri_i64(s->tmp0, s->tmp0, 32);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001909 tcg_gen_shri_i64(s->T0, s->T0, 32);
bellardb6abf972008-05-17 12:44:31 +00001910 }
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001911 break;
1912#endif
1913 default:
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001914 tcg_gen_subi_tl(s->tmp0, count, 1);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001915 if (is_right) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001916 tcg_gen_shr_tl(s->tmp0, s->T0, s->tmp0);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001917
Emilio G. Cota5022f282018-09-11 14:10:21 -04001918 tcg_gen_subfi_tl(s->tmp4, mask + 1, count);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001919 tcg_gen_shr_tl(s->T0, s->T0, count);
Emilio G. Cota5022f282018-09-11 14:10:21 -04001920 tcg_gen_shl_tl(s->T1, s->T1, s->tmp4);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001921 } else {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001922 tcg_gen_shl_tl(s->tmp0, s->T0, s->tmp0);
Richard Henderson4ba99382013-11-02 09:54:47 -07001923 if (ot == MO_16) {
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001924 /* Only needed if count > 16, for Intel behaviour. */
Emilio G. Cota5022f282018-09-11 14:10:21 -04001925 tcg_gen_subfi_tl(s->tmp4, 33, count);
1926 tcg_gen_shr_tl(s->tmp4, s->T1, s->tmp4);
1927 tcg_gen_or_tl(s->tmp0, s->tmp0, s->tmp4);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001928 }
1929
Emilio G. Cota5022f282018-09-11 14:10:21 -04001930 tcg_gen_subfi_tl(s->tmp4, mask + 1, count);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04001931 tcg_gen_shl_tl(s->T0, s->T0, count);
Emilio G. Cota5022f282018-09-11 14:10:21 -04001932 tcg_gen_shr_tl(s->T1, s->T1, s->tmp4);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001933 }
Emilio G. Cota5022f282018-09-11 14:10:21 -04001934 tcg_gen_movi_tl(s->tmp4, 0);
1935 tcg_gen_movcond_tl(TCG_COND_EQ, s->T1, count, s->tmp4,
1936 s->tmp4, s->T1);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001937 tcg_gen_or_tl(s->T0, s->T0, s->T1);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001938 break;
bellardb6abf972008-05-17 12:44:31 +00001939 }
bellardb6abf972008-05-17 12:44:31 +00001940
bellardb6abf972008-05-17 12:44:31 +00001941 /* store */
Richard Hendersond4faa3e2013-11-02 10:59:43 -07001942 gen_op_st_rm_T0_A0(s, ot, op1);
bellardb6abf972008-05-17 12:44:31 +00001943
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04001944 gen_shift_flags(s, ot, s->T0, s->tmp0, count, is_right);
Richard Hendersonf437d0a2013-02-19 21:06:31 -08001945 tcg_temp_free(count);
bellard2c0262a2003-09-30 20:34:21 +00001946}
1947
Tony Nguyen14776ab2019-08-24 04:10:58 +10001948static void gen_shift(DisasContext *s1, int op, MemOp ot, int d, int s)
bellard2c0262a2003-09-30 20:34:21 +00001949{
bellard2c0262a2003-09-30 20:34:21 +00001950 if (s != OR_TMP1)
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04001951 gen_op_mov_v_reg(s1, ot, s1->T1, s);
bellardb6abf972008-05-17 12:44:31 +00001952 switch(op) {
1953 case OP_ROL:
1954 gen_rot_rm_T1(s1, ot, d, 0);
1955 break;
1956 case OP_ROR:
1957 gen_rot_rm_T1(s1, ot, d, 1);
1958 break;
1959 case OP_SHL:
1960 case OP_SHL1:
1961 gen_shift_rm_T1(s1, ot, d, 0, 0);
1962 break;
1963 case OP_SHR:
1964 gen_shift_rm_T1(s1, ot, d, 1, 0);
1965 break;
1966 case OP_SAR:
1967 gen_shift_rm_T1(s1, ot, d, 1, 1);
1968 break;
1969 case OP_RCL:
1970 gen_rotc_rm_T1(s1, ot, d, 0);
1971 break;
1972 case OP_RCR:
1973 gen_rotc_rm_T1(s1, ot, d, 1);
1974 break;
1975 }
bellard2c0262a2003-09-30 20:34:21 +00001976}
1977
Tony Nguyen14776ab2019-08-24 04:10:58 +10001978static void gen_shifti(DisasContext *s1, int op, MemOp ot, int d, int c)
bellard2c0262a2003-09-30 20:34:21 +00001979{
bellardc1c37962008-05-22 12:36:31 +00001980 switch(op) {
malc8cd63452009-04-02 22:54:35 +00001981 case OP_ROL:
1982 gen_rot_rm_im(s1, ot, d, c, 0);
1983 break;
1984 case OP_ROR:
1985 gen_rot_rm_im(s1, ot, d, c, 1);
1986 break;
bellardc1c37962008-05-22 12:36:31 +00001987 case OP_SHL:
1988 case OP_SHL1:
1989 gen_shift_rm_im(s1, ot, d, c, 0, 0);
1990 break;
1991 case OP_SHR:
1992 gen_shift_rm_im(s1, ot, d, c, 1, 0);
1993 break;
1994 case OP_SAR:
1995 gen_shift_rm_im(s1, ot, d, c, 1, 1);
1996 break;
1997 default:
1998 /* currently not optimized */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04001999 tcg_gen_movi_tl(s1->T1, c);
bellardc1c37962008-05-22 12:36:31 +00002000 gen_shift(s1, op, ot, d, OR_TMP1);
2001 break;
2002 }
bellard2c0262a2003-09-30 20:34:21 +00002003}
2004
Paolo Bonzinib066c532017-03-22 11:57:10 +01002005#define X86_MAX_INSN_LENGTH 15
2006
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002007static uint64_t advance_pc(CPUX86State *env, DisasContext *s, int num_bytes)
2008{
2009 uint64_t pc = s->pc;
2010
2011 s->pc += num_bytes;
Paolo Bonzinib066c532017-03-22 11:57:10 +01002012 if (unlikely(s->pc - s->pc_start > X86_MAX_INSN_LENGTH)) {
2013 /* If the instruction's 16th byte is on a different page than the 1st, a
2014 * page fault on the second page wins over the general protection fault
2015 * caused by the instruction being too long.
2016 * This can happen even if the operand is only one byte long!
2017 */
2018 if (((s->pc - 1) ^ (pc - 1)) & TARGET_PAGE_MASK) {
2019 volatile uint8_t unused =
2020 cpu_ldub_code(env, (s->pc - 1) & TARGET_PAGE_MASK);
2021 (void) unused;
2022 }
2023 siglongjmp(s->jmpbuf, 1);
2024 }
2025
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002026 return pc;
2027}
2028
2029static inline uint8_t x86_ldub_code(CPUX86State *env, DisasContext *s)
2030{
Ilya Leoshkevich4e116892021-08-09 12:32:59 -10002031 return translator_ldub(env, &s->base, advance_pc(env, s, 1));
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002032}
2033
2034static inline int16_t x86_ldsw_code(CPUX86State *env, DisasContext *s)
2035{
Ilya Leoshkevich4e116892021-08-09 12:32:59 -10002036 return translator_ldsw(env, &s->base, advance_pc(env, s, 2));
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002037}
2038
2039static inline uint16_t x86_lduw_code(CPUX86State *env, DisasContext *s)
2040{
Ilya Leoshkevich4e116892021-08-09 12:32:59 -10002041 return translator_lduw(env, &s->base, advance_pc(env, s, 2));
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002042}
2043
2044static inline uint32_t x86_ldl_code(CPUX86State *env, DisasContext *s)
2045{
Ilya Leoshkevich4e116892021-08-09 12:32:59 -10002046 return translator_ldl(env, &s->base, advance_pc(env, s, 4));
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002047}
2048
2049#ifdef TARGET_X86_64
2050static inline uint64_t x86_ldq_code(CPUX86State *env, DisasContext *s)
2051{
Ilya Leoshkevich4e116892021-08-09 12:32:59 -10002052 return translator_ldq(env, &s->base, advance_pc(env, s, 8));
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002053}
2054#endif
2055
Richard Hendersona074ce42015-07-09 08:22:01 +01002056/* Decompose an address. */
2057
2058typedef struct AddressParts {
2059 int def_seg;
2060 int base;
2061 int index;
2062 int scale;
bellard14ce26e2005-01-03 23:50:08 +00002063 target_long disp;
Richard Hendersona074ce42015-07-09 08:22:01 +01002064} AddressParts;
2065
2066static AddressParts gen_lea_modrm_0(CPUX86State *env, DisasContext *s,
2067 int modrm)
2068{
2069 int def_seg, base, index, scale, mod, rm;
2070 target_long disp;
2071 bool havesib;
bellard2c0262a2003-09-30 20:34:21 +00002072
Richard Hendersond6a29142015-12-17 11:19:19 -08002073 def_seg = R_DS;
Richard Hendersona074ce42015-07-09 08:22:01 +01002074 index = -1;
2075 scale = 0;
2076 disp = 0;
2077
bellard2c0262a2003-09-30 20:34:21 +00002078 mod = (modrm >> 6) & 3;
2079 rm = modrm & 7;
Richard Hendersona074ce42015-07-09 08:22:01 +01002080 base = rm | REX_B(s);
2081
2082 if (mod == 3) {
2083 /* Normally filtered out earlier, but including this path
2084 simplifies multi-byte nop, as well as bndcl, bndcu, bndcn. */
2085 goto done;
2086 }
bellard2c0262a2003-09-30 20:34:21 +00002087
Richard Henderson1d71ddb2013-11-06 08:27:33 +10002088 switch (s->aflag) {
2089 case MO_64:
2090 case MO_32:
bellard2c0262a2003-09-30 20:34:21 +00002091 havesib = 0;
Richard Hendersona074ce42015-07-09 08:22:01 +01002092 if (rm == 4) {
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002093 int code = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00002094 scale = (code >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00002095 index = ((code >> 3) & 7) | REX_X(s);
Richard Henderson7865eec2013-11-12 11:16:56 +10002096 if (index == 4) {
2097 index = -1; /* no index */
2098 }
Richard Hendersona074ce42015-07-09 08:22:01 +01002099 base = (code & 7) | REX_B(s);
2100 havesib = 1;
bellard2c0262a2003-09-30 20:34:21 +00002101 }
2102
2103 switch (mod) {
2104 case 0:
bellard14ce26e2005-01-03 23:50:08 +00002105 if ((base & 7) == 5) {
bellard2c0262a2003-09-30 20:34:21 +00002106 base = -1;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002107 disp = (int32_t)x86_ldl_code(env, s);
bellard14ce26e2005-01-03 23:50:08 +00002108 if (CODE64(s) && !havesib) {
Richard Hendersona074ce42015-07-09 08:22:01 +01002109 base = -2;
bellard14ce26e2005-01-03 23:50:08 +00002110 disp += s->pc + s->rip_offset;
2111 }
bellard2c0262a2003-09-30 20:34:21 +00002112 }
2113 break;
2114 case 1:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002115 disp = (int8_t)x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00002116 break;
2117 default:
2118 case 2:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002119 disp = (int32_t)x86_ldl_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00002120 break;
2121 }
ths3b46e622007-09-17 08:09:54 +00002122
Richard Henderson7865eec2013-11-12 11:16:56 +10002123 /* For correct popl handling with esp. */
2124 if (base == R_ESP && s->popl_esp_hack) {
2125 disp += s->popl_esp_hack;
2126 }
Richard Hendersond6a29142015-12-17 11:19:19 -08002127 if (base == R_EBP || base == R_ESP) {
2128 def_seg = R_SS;
bellard2c0262a2003-09-30 20:34:21 +00002129 }
Richard Henderson1d71ddb2013-11-06 08:27:33 +10002130 break;
2131
2132 case MO_16:
Richard Hendersond6a29142015-12-17 11:19:19 -08002133 if (mod == 0) {
bellard2c0262a2003-09-30 20:34:21 +00002134 if (rm == 6) {
Richard Hendersona074ce42015-07-09 08:22:01 +01002135 base = -1;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002136 disp = x86_lduw_code(env, s);
Richard Hendersond6a29142015-12-17 11:19:19 -08002137 break;
bellard2c0262a2003-09-30 20:34:21 +00002138 }
Richard Hendersond6a29142015-12-17 11:19:19 -08002139 } else if (mod == 1) {
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002140 disp = (int8_t)x86_ldub_code(env, s);
Richard Hendersond6a29142015-12-17 11:19:19 -08002141 } else {
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002142 disp = (int16_t)x86_lduw_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00002143 }
Richard Henderson7effd622013-11-06 11:34:38 +10002144
Richard Henderson7effd622013-11-06 11:34:38 +10002145 switch (rm) {
bellard2c0262a2003-09-30 20:34:21 +00002146 case 0:
Richard Hendersona074ce42015-07-09 08:22:01 +01002147 base = R_EBX;
2148 index = R_ESI;
bellard2c0262a2003-09-30 20:34:21 +00002149 break;
2150 case 1:
Richard Hendersona074ce42015-07-09 08:22:01 +01002151 base = R_EBX;
2152 index = R_EDI;
bellard2c0262a2003-09-30 20:34:21 +00002153 break;
2154 case 2:
Richard Hendersona074ce42015-07-09 08:22:01 +01002155 base = R_EBP;
2156 index = R_ESI;
Richard Hendersond6a29142015-12-17 11:19:19 -08002157 def_seg = R_SS;
bellard2c0262a2003-09-30 20:34:21 +00002158 break;
2159 case 3:
Richard Hendersona074ce42015-07-09 08:22:01 +01002160 base = R_EBP;
2161 index = R_EDI;
Richard Hendersond6a29142015-12-17 11:19:19 -08002162 def_seg = R_SS;
bellard2c0262a2003-09-30 20:34:21 +00002163 break;
2164 case 4:
Richard Hendersona074ce42015-07-09 08:22:01 +01002165 base = R_ESI;
bellard2c0262a2003-09-30 20:34:21 +00002166 break;
2167 case 5:
Richard Hendersona074ce42015-07-09 08:22:01 +01002168 base = R_EDI;
bellard2c0262a2003-09-30 20:34:21 +00002169 break;
2170 case 6:
Richard Hendersona074ce42015-07-09 08:22:01 +01002171 base = R_EBP;
Richard Hendersond6a29142015-12-17 11:19:19 -08002172 def_seg = R_SS;
bellard2c0262a2003-09-30 20:34:21 +00002173 break;
2174 default:
2175 case 7:
Richard Hendersona074ce42015-07-09 08:22:01 +01002176 base = R_EBX;
bellard2c0262a2003-09-30 20:34:21 +00002177 break;
2178 }
Richard Henderson1d71ddb2013-11-06 08:27:33 +10002179 break;
2180
2181 default:
2182 tcg_abort();
bellard2c0262a2003-09-30 20:34:21 +00002183 }
Richard Hendersond6a29142015-12-17 11:19:19 -08002184
Richard Hendersona074ce42015-07-09 08:22:01 +01002185 done:
2186 return (AddressParts){ def_seg, base, index, scale, disp };
2187}
2188
2189/* Compute the address, with a minimum number of TCG ops. */
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002190static TCGv gen_lea_modrm_1(DisasContext *s, AddressParts a)
Richard Hendersona074ce42015-07-09 08:22:01 +01002191{
Richard Hendersonf7647182017-11-02 12:47:37 +01002192 TCGv ea = NULL;
Richard Hendersona074ce42015-07-09 08:22:01 +01002193
Richard Hendersona074ce42015-07-09 08:22:01 +01002194 if (a.index >= 0) {
2195 if (a.scale == 0) {
2196 ea = cpu_regs[a.index];
2197 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002198 tcg_gen_shli_tl(s->A0, cpu_regs[a.index], a.scale);
2199 ea = s->A0;
Richard Hendersona074ce42015-07-09 08:22:01 +01002200 }
2201 if (a.base >= 0) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002202 tcg_gen_add_tl(s->A0, ea, cpu_regs[a.base]);
2203 ea = s->A0;
Richard Hendersona074ce42015-07-09 08:22:01 +01002204 }
2205 } else if (a.base >= 0) {
2206 ea = cpu_regs[a.base];
2207 }
Richard Hendersonf7647182017-11-02 12:47:37 +01002208 if (!ea) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002209 tcg_gen_movi_tl(s->A0, a.disp);
2210 ea = s->A0;
Richard Hendersona074ce42015-07-09 08:22:01 +01002211 } else if (a.disp != 0) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002212 tcg_gen_addi_tl(s->A0, ea, a.disp);
2213 ea = s->A0;
Richard Hendersona074ce42015-07-09 08:22:01 +01002214 }
2215
2216 return ea;
2217}
2218
2219static void gen_lea_modrm(CPUX86State *env, DisasContext *s, int modrm)
2220{
2221 AddressParts a = gen_lea_modrm_0(env, s, modrm);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002222 TCGv ea = gen_lea_modrm_1(s, a);
Richard Hendersona074ce42015-07-09 08:22:01 +01002223 gen_lea_v_seg(s, s->aflag, ea, a.def_seg, s->override);
bellard2c0262a2003-09-30 20:34:21 +00002224}
2225
Blue Swirl0af10c82012-09-08 13:26:02 +00002226static void gen_nop_modrm(CPUX86State *env, DisasContext *s, int modrm)
bellarde17a36c2006-09-03 17:09:02 +00002227{
Richard Hendersona074ce42015-07-09 08:22:01 +01002228 (void)gen_lea_modrm_0(env, s, modrm);
bellarde17a36c2006-09-03 17:09:02 +00002229}
2230
Richard Henderson523e28d2015-07-06 19:37:00 +01002231/* Used for BNDCL, BNDCU, BNDCN. */
2232static void gen_bndck(CPUX86State *env, DisasContext *s, int modrm,
2233 TCGCond cond, TCGv_i64 bndv)
2234{
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002235 TCGv ea = gen_lea_modrm_1(s, gen_lea_modrm_0(env, s, modrm));
Richard Henderson523e28d2015-07-06 19:37:00 +01002236
Emilio G. Cota776678b2018-09-11 14:22:31 -04002237 tcg_gen_extu_tl_i64(s->tmp1_i64, ea);
Richard Henderson523e28d2015-07-06 19:37:00 +01002238 if (!CODE64(s)) {
Emilio G. Cota776678b2018-09-11 14:22:31 -04002239 tcg_gen_ext32u_i64(s->tmp1_i64, s->tmp1_i64);
Richard Henderson523e28d2015-07-06 19:37:00 +01002240 }
Emilio G. Cota776678b2018-09-11 14:22:31 -04002241 tcg_gen_setcond_i64(cond, s->tmp1_i64, s->tmp1_i64, bndv);
2242 tcg_gen_extrl_i64_i32(s->tmp2_i32, s->tmp1_i64);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04002243 gen_helper_bndck(cpu_env, s->tmp2_i32);
Richard Henderson523e28d2015-07-06 19:37:00 +01002244}
2245
bellard664e0f12005-01-08 18:58:29 +00002246/* used for LEA and MOV AX, mem */
2247static void gen_add_A0_ds_seg(DisasContext *s)
2248{
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002249 gen_lea_v_seg(s, s->aflag, s->A0, R_DS, s->override);
bellard664e0f12005-01-08 18:58:29 +00002250}
2251
balrog222a3332008-10-04 03:27:44 +00002252/* generate modrm memory load or store of 'reg'. TMP0 is used if reg ==
bellard2c0262a2003-09-30 20:34:21 +00002253 OR_TMP0 */
Blue Swirl0af10c82012-09-08 13:26:02 +00002254static void gen_ldst_modrm(CPUX86State *env, DisasContext *s, int modrm,
Tony Nguyen14776ab2019-08-24 04:10:58 +10002255 MemOp ot, int reg, int is_store)
bellard2c0262a2003-09-30 20:34:21 +00002256{
Richard Henderson4eeb3932013-11-02 08:55:59 -10002257 int mod, rm;
bellard2c0262a2003-09-30 20:34:21 +00002258
2259 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00002260 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00002261 if (mod == 3) {
2262 if (is_store) {
2263 if (reg != OR_TMP0)
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002264 gen_op_mov_v_reg(s, ot, s->T0, reg);
2265 gen_op_mov_reg_v(s, ot, rm, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00002266 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002267 gen_op_mov_v_reg(s, ot, s->T0, rm);
bellard2c0262a2003-09-30 20:34:21 +00002268 if (reg != OR_TMP0)
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002269 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00002270 }
2271 } else {
Richard Henderson4eeb3932013-11-02 08:55:59 -10002272 gen_lea_modrm(env, s, modrm);
bellard2c0262a2003-09-30 20:34:21 +00002273 if (is_store) {
2274 if (reg != OR_TMP0)
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002275 gen_op_mov_v_reg(s, ot, s->T0, reg);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002276 gen_op_st_v(s, ot, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00002277 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002278 gen_op_ld_v(s, ot, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00002279 if (reg != OR_TMP0)
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002280 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00002281 }
2282 }
2283}
2284
Tony Nguyen14776ab2019-08-24 04:10:58 +10002285static inline uint32_t insn_get(CPUX86State *env, DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00002286{
2287 uint32_t ret;
2288
Richard Hendersond67dc9e2013-11-06 07:25:05 +10002289 switch (ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07002290 case MO_8:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002291 ret = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00002292 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07002293 case MO_16:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002294 ret = x86_lduw_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00002295 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07002296 case MO_32:
Richard Hendersond67dc9e2013-11-06 07:25:05 +10002297#ifdef TARGET_X86_64
2298 case MO_64:
2299#endif
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02002300 ret = x86_ldl_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00002301 break;
Richard Hendersond67dc9e2013-11-06 07:25:05 +10002302 default:
2303 tcg_abort();
bellard2c0262a2003-09-30 20:34:21 +00002304 }
2305 return ret;
2306}
2307
Tony Nguyen14776ab2019-08-24 04:10:58 +10002308static inline int insn_const_size(MemOp ot)
bellard14ce26e2005-01-03 23:50:08 +00002309{
Richard Henderson4ba99382013-11-02 09:54:47 -07002310 if (ot <= MO_32) {
bellard14ce26e2005-01-03 23:50:08 +00002311 return 1 << ot;
Richard Henderson4ba99382013-11-02 09:54:47 -07002312 } else {
bellard14ce26e2005-01-03 23:50:08 +00002313 return 4;
Richard Henderson4ba99382013-11-02 09:54:47 -07002314 }
bellard14ce26e2005-01-03 23:50:08 +00002315}
2316
Richard Hendersonb4735342021-06-20 16:16:45 -07002317static void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
bellard6e256c92005-11-20 10:32:05 +00002318{
Sergey Fedorov90aa39a2016-04-09 01:00:23 +03002319 target_ulong pc = s->cs_base + eip;
bellard6e256c92005-11-20 10:32:05 +00002320
Richard Hendersonb4735342021-06-20 16:16:45 -07002321 if (translator_use_goto_tb(&s->base, pc)) {
bellard6e256c92005-11-20 10:32:05 +00002322 /* jump to same page: we can use a direct jump */
bellard57fec1f2008-02-01 10:50:11 +00002323 tcg_gen_goto_tb(tb_num);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002324 gen_jmp_im(s, eip);
Richard Henderson07ea28b2018-05-30 18:06:23 -07002325 tcg_gen_exit_tb(s->base.tb, tb_num);
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03002326 s->base.is_jmp = DISAS_NORETURN;
bellard6e256c92005-11-20 10:32:05 +00002327 } else {
Emilio G. Cotafe620892017-04-26 23:29:22 -04002328 /* jump to another page */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002329 gen_jmp_im(s, eip);
2330 gen_jr(s, s->tmp0);
bellard6e256c92005-11-20 10:32:05 +00002331 }
2332}
2333
ths5fafdf22007-09-16 21:08:06 +00002334static inline void gen_jcc(DisasContext *s, int b,
bellard14ce26e2005-01-03 23:50:08 +00002335 target_ulong val, target_ulong next_eip)
bellard2c0262a2003-09-30 20:34:21 +00002336{
Richard Henderson42a268c2015-02-13 12:51:55 -08002337 TCGLabel *l1, *l2;
bellard2c0262a2003-09-30 20:34:21 +00002338
bellard2c0262a2003-09-30 20:34:21 +00002339 if (s->jmp_opt) {
bellard14ce26e2005-01-03 23:50:08 +00002340 l1 = gen_new_label();
Paolo Bonzinib27fc132012-10-06 01:36:45 +02002341 gen_jcc1(s, b, l1);
Richard Hendersondc259202013-01-23 15:01:35 -08002342
bellard6e256c92005-11-20 10:32:05 +00002343 gen_goto_tb(s, 0, next_eip);
bellard14ce26e2005-01-03 23:50:08 +00002344
2345 gen_set_label(l1);
bellard6e256c92005-11-20 10:32:05 +00002346 gen_goto_tb(s, 1, val);
bellard2c0262a2003-09-30 20:34:21 +00002347 } else {
bellard14ce26e2005-01-03 23:50:08 +00002348 l1 = gen_new_label();
2349 l2 = gen_new_label();
Paolo Bonzinib27fc132012-10-06 01:36:45 +02002350 gen_jcc1(s, b, l1);
bellard8e1c85e2008-05-21 19:16:45 +00002351
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002352 gen_jmp_im(s, next_eip);
bellard8e1c85e2008-05-21 19:16:45 +00002353 tcg_gen_br(l2);
2354
bellard14ce26e2005-01-03 23:50:08 +00002355 gen_set_label(l1);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002356 gen_jmp_im(s, val);
bellard14ce26e2005-01-03 23:50:08 +00002357 gen_set_label(l2);
bellard2c0262a2003-09-30 20:34:21 +00002358 gen_eob(s);
2359 }
2360}
2361
Tony Nguyen14776ab2019-08-24 04:10:58 +10002362static void gen_cmovcc1(CPUX86State *env, DisasContext *s, MemOp ot, int b,
Paolo Bonzinif32d3782012-10-07 17:55:26 +02002363 int modrm, int reg)
2364{
Richard Henderson57eb0cc2013-01-16 11:00:14 -08002365 CCPrepare cc;
Paolo Bonzinif32d3782012-10-07 17:55:26 +02002366
Richard Henderson57eb0cc2013-01-16 11:00:14 -08002367 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
2368
Emilio G. Cotab48597b2018-09-11 14:50:46 -04002369 cc = gen_prepare_cc(s, b, s->T1);
Richard Henderson57eb0cc2013-01-16 11:00:14 -08002370 if (cc.mask != -1) {
2371 TCGv t0 = tcg_temp_new();
2372 tcg_gen_andi_tl(t0, cc.reg, cc.mask);
2373 cc.reg = t0;
2374 }
2375 if (!cc.use_reg2) {
2376 cc.reg2 = tcg_const_tl(cc.imm);
Paolo Bonzinif32d3782012-10-07 17:55:26 +02002377 }
2378
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002379 tcg_gen_movcond_tl(cc.cond, s->T0, cc.reg, cc.reg2,
2380 s->T0, cpu_regs[reg]);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002381 gen_op_mov_reg_v(s, ot, reg, s->T0);
Paolo Bonzinif32d3782012-10-07 17:55:26 +02002382
Richard Henderson57eb0cc2013-01-16 11:00:14 -08002383 if (cc.mask != -1) {
2384 tcg_temp_free(cc.reg);
2385 }
2386 if (!cc.use_reg2) {
2387 tcg_temp_free(cc.reg2);
2388 }
Paolo Bonzinif32d3782012-10-07 17:55:26 +02002389}
2390
Philippe Mathieu-Daudéc117e5b2021-01-10 00:34:27 +01002391static inline void gen_op_movl_T0_seg(DisasContext *s, X86Seg seg_reg)
bellard3bd7da92008-05-21 16:34:06 +00002392{
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002393 tcg_gen_ld32u_tl(s->T0, cpu_env,
bellard3bd7da92008-05-21 16:34:06 +00002394 offsetof(CPUX86State,segs[seg_reg].selector));
2395}
2396
Philippe Mathieu-Daudéc117e5b2021-01-10 00:34:27 +01002397static inline void gen_op_movl_seg_T0_vm(DisasContext *s, X86Seg seg_reg)
bellard3bd7da92008-05-21 16:34:06 +00002398{
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002399 tcg_gen_ext16u_tl(s->T0, s->T0);
2400 tcg_gen_st32_tl(s->T0, cpu_env,
bellard3bd7da92008-05-21 16:34:06 +00002401 offsetof(CPUX86State,segs[seg_reg].selector));
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002402 tcg_gen_shli_tl(cpu_seg_base[seg_reg], s->T0, 4);
bellard3bd7da92008-05-21 16:34:06 +00002403}
2404
bellard2c0262a2003-09-30 20:34:21 +00002405/* move T0 to seg_reg and compute if the CPU state may change. Never
2406 call this function with seg_reg == R_CS */
Philippe Mathieu-Daudéc117e5b2021-01-10 00:34:27 +01002407static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg)
bellard2c0262a2003-09-30 20:34:21 +00002408{
Richard Hendersonf8a35842021-05-14 10:13:01 -05002409 if (PE(s) && !VM86(s)) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04002410 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
2411 gen_helper_load_seg(cpu_env, tcg_const_i32(seg_reg), s->tmp2_i32);
bellarddc196a52004-06-13 13:26:14 +00002412 /* abort translation because the addseg value may change or
2413 because ss32 may change. For R_SS, translation must always
2414 stop as a special handling must be done to disable hardware
2415 interrupts for the next instruction */
Richard Henderson9996dcf2021-05-14 10:13:02 -05002416 if (seg_reg == R_SS || (CODE32(s) && seg_reg < R_FS)) {
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03002417 s->base.is_jmp = DISAS_TOO_MANY;
Richard Henderson1e39d972017-07-14 07:54:07 -10002418 }
bellard3415a4d2004-01-04 15:21:33 +00002419 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002420 gen_op_movl_seg_T0_vm(s, seg_reg);
Richard Henderson1e39d972017-07-14 07:54:07 -10002421 if (seg_reg == R_SS) {
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03002422 s->base.is_jmp = DISAS_TOO_MANY;
Richard Henderson1e39d972017-07-14 07:54:07 -10002423 }
bellard3415a4d2004-01-04 15:21:33 +00002424 }
bellard2c0262a2003-09-30 20:34:21 +00002425}
2426
Richard Hendersonb53605d2021-05-14 10:13:29 -05002427static void gen_svm_check_intercept(DisasContext *s, uint32_t type)
ths0573fbf2007-09-23 15:28:04 +00002428{
bellard872929a2008-05-28 16:16:54 +00002429 /* no SVM activated; fast case */
Richard Hendersonb322b3a2021-05-14 10:13:23 -05002430 if (likely(!GUEST(s))) {
bellard872929a2008-05-28 16:16:54 +00002431 return;
Richard Hendersonb322b3a2021-05-14 10:13:23 -05002432 }
Richard Hendersond051ea02021-05-14 10:13:28 -05002433 gen_helper_svm_check_intercept(cpu_env, tcg_constant_i32(type));
ths0573fbf2007-09-23 15:28:04 +00002434}
2435
bellard2c0262a2003-09-30 20:34:21 +00002436static inline void gen_stack_update(DisasContext *s, int addend)
2437{
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002438 gen_op_add_reg_im(s, mo_stacksize(s), R_ESP, addend);
bellard2c0262a2003-09-30 20:34:21 +00002439}
2440
Richard Henderson432baff2013-11-06 13:19:04 +10002441/* Generate a push. It depends on ss32, addseg and dflag. */
2442static void gen_push_v(DisasContext *s, TCGv val)
bellard4f319162004-01-04 17:35:00 +00002443{
Tony Nguyen14776ab2019-08-24 04:10:58 +10002444 MemOp d_ot = mo_pushpop(s, s->dflag);
2445 MemOp a_ot = mo_stacksize(s);
Richard Henderson432baff2013-11-06 13:19:04 +10002446 int size = 1 << d_ot;
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002447 TCGv new_esp = s->A0;
bellard4f319162004-01-04 17:35:00 +00002448
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002449 tcg_gen_subi_tl(s->A0, cpu_regs[R_ESP], size);
ths3b46e622007-09-17 08:09:54 +00002450
Richard Henderson77ebcad2015-12-17 11:19:20 -08002451 if (!CODE64(s)) {
Richard Hendersonbeedb932021-05-14 10:13:06 -05002452 if (ADDSEG(s)) {
Emilio G. Cota5022f282018-09-11 14:10:21 -04002453 new_esp = s->tmp4;
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002454 tcg_gen_mov_tl(new_esp, s->A0);
Richard Henderson432baff2013-11-06 13:19:04 +10002455 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002456 gen_lea_v_seg(s, a_ot, s->A0, R_SS, -1);
bellard4f319162004-01-04 17:35:00 +00002457 }
Richard Henderson432baff2013-11-06 13:19:04 +10002458
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002459 gen_op_st_v(s, d_ot, val, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002460 gen_op_mov_reg_v(s, a_ot, R_ESP, new_esp);
bellard4f319162004-01-04 17:35:00 +00002461}
2462
2463/* two step pop is necessary for precise exceptions */
Tony Nguyen14776ab2019-08-24 04:10:58 +10002464static MemOp gen_pop_T0(DisasContext *s)
bellard4f319162004-01-04 17:35:00 +00002465{
Tony Nguyen14776ab2019-08-24 04:10:58 +10002466 MemOp d_ot = mo_pushpop(s, s->dflag);
Richard Henderson8e31d232013-11-06 13:57:45 +10002467
Richard Henderson77ebcad2015-12-17 11:19:20 -08002468 gen_lea_v_seg(s, mo_stacksize(s), cpu_regs[R_ESP], R_SS, -1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002469 gen_op_ld_v(s, d_ot, s->T0, s->A0);
Richard Henderson8e31d232013-11-06 13:57:45 +10002470
Richard Henderson8e31d232013-11-06 13:57:45 +10002471 return d_ot;
bellard4f319162004-01-04 17:35:00 +00002472}
2473
Tony Nguyen14776ab2019-08-24 04:10:58 +10002474static inline void gen_pop_update(DisasContext *s, MemOp ot)
bellard2c0262a2003-09-30 20:34:21 +00002475{
Richard Henderson8e31d232013-11-06 13:57:45 +10002476 gen_stack_update(s, 1 << ot);
bellard2c0262a2003-09-30 20:34:21 +00002477}
2478
Richard Henderson77ebcad2015-12-17 11:19:20 -08002479static inline void gen_stack_A0(DisasContext *s)
bellard2c0262a2003-09-30 20:34:21 +00002480{
Richard Hendersonb40a47a2021-05-14 10:13:03 -05002481 gen_lea_v_seg(s, SS32(s) ? MO_32 : MO_16, cpu_regs[R_ESP], R_SS, -1);
bellard2c0262a2003-09-30 20:34:21 +00002482}
2483
bellard2c0262a2003-09-30 20:34:21 +00002484static void gen_pusha(DisasContext *s)
2485{
Richard Hendersonb40a47a2021-05-14 10:13:03 -05002486 MemOp s_ot = SS32(s) ? MO_32 : MO_16;
Tony Nguyen14776ab2019-08-24 04:10:58 +10002487 MemOp d_ot = s->dflag;
Richard Hendersond37ea0c2015-12-17 11:19:22 -08002488 int size = 1 << d_ot;
bellard2c0262a2003-09-30 20:34:21 +00002489 int i;
Richard Hendersond37ea0c2015-12-17 11:19:22 -08002490
2491 for (i = 0; i < 8; i++) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002492 tcg_gen_addi_tl(s->A0, cpu_regs[R_ESP], (i - 8) * size);
2493 gen_lea_v_seg(s, s_ot, s->A0, R_SS, -1);
2494 gen_op_st_v(s, d_ot, cpu_regs[7 - i], s->A0);
bellard2c0262a2003-09-30 20:34:21 +00002495 }
Richard Hendersond37ea0c2015-12-17 11:19:22 -08002496
2497 gen_stack_update(s, -8 * size);
bellard2c0262a2003-09-30 20:34:21 +00002498}
2499
bellard2c0262a2003-09-30 20:34:21 +00002500static void gen_popa(DisasContext *s)
2501{
Richard Hendersonb40a47a2021-05-14 10:13:03 -05002502 MemOp s_ot = SS32(s) ? MO_32 : MO_16;
Tony Nguyen14776ab2019-08-24 04:10:58 +10002503 MemOp d_ot = s->dflag;
Richard Hendersond37ea0c2015-12-17 11:19:22 -08002504 int size = 1 << d_ot;
bellard2c0262a2003-09-30 20:34:21 +00002505 int i;
Richard Hendersond37ea0c2015-12-17 11:19:22 -08002506
2507 for (i = 0; i < 8; i++) {
bellard2c0262a2003-09-30 20:34:21 +00002508 /* ESP is not reloaded */
Richard Hendersond37ea0c2015-12-17 11:19:22 -08002509 if (7 - i == R_ESP) {
2510 continue;
bellard2c0262a2003-09-30 20:34:21 +00002511 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002512 tcg_gen_addi_tl(s->A0, cpu_regs[R_ESP], i * size);
2513 gen_lea_v_seg(s, s_ot, s->A0, R_SS, -1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002514 gen_op_ld_v(s, d_ot, s->T0, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002515 gen_op_mov_reg_v(s, d_ot, 7 - i, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00002516 }
Richard Hendersond37ea0c2015-12-17 11:19:22 -08002517
2518 gen_stack_update(s, 8 * size);
bellard2c0262a2003-09-30 20:34:21 +00002519}
2520
bellard2c0262a2003-09-30 20:34:21 +00002521static void gen_enter(DisasContext *s, int esp_addend, int level)
2522{
Tony Nguyen14776ab2019-08-24 04:10:58 +10002523 MemOp d_ot = mo_pushpop(s, s->dflag);
Richard Hendersonb40a47a2021-05-14 10:13:03 -05002524 MemOp a_ot = CODE64(s) ? MO_64 : SS32(s) ? MO_32 : MO_16;
Richard Henderson743e3982015-12-17 11:19:23 -08002525 int size = 1 << d_ot;
bellard2c0262a2003-09-30 20:34:21 +00002526
Richard Henderson743e3982015-12-17 11:19:23 -08002527 /* Push BP; compute FrameTemp into T1. */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04002528 tcg_gen_subi_tl(s->T1, cpu_regs[R_ESP], size);
2529 gen_lea_v_seg(s, a_ot, s->T1, R_SS, -1);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002530 gen_op_st_v(s, d_ot, cpu_regs[R_EBP], s->A0);
bellard2c0262a2003-09-30 20:34:21 +00002531
Richard Henderson743e3982015-12-17 11:19:23 -08002532 level &= 31;
2533 if (level != 0) {
2534 int i;
2535
2536 /* Copy level-1 pointers from the previous frame. */
2537 for (i = 1; i < level; ++i) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002538 tcg_gen_subi_tl(s->A0, cpu_regs[R_EBP], size * i);
2539 gen_lea_v_seg(s, a_ot, s->A0, R_SS, -1);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002540 gen_op_ld_v(s, d_ot, s->tmp0, s->A0);
Richard Henderson743e3982015-12-17 11:19:23 -08002541
Emilio G. Cotab48597b2018-09-11 14:50:46 -04002542 tcg_gen_subi_tl(s->A0, s->T1, size * i);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002543 gen_lea_v_seg(s, a_ot, s->A0, R_SS, -1);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002544 gen_op_st_v(s, d_ot, s->tmp0, s->A0);
bellard8f091a52005-07-23 17:41:26 +00002545 }
Richard Henderson743e3982015-12-17 11:19:23 -08002546
2547 /* Push the current FrameTemp as the last level. */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04002548 tcg_gen_subi_tl(s->A0, s->T1, size * level);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04002549 gen_lea_v_seg(s, a_ot, s->A0, R_SS, -1);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04002550 gen_op_st_v(s, d_ot, s->T1, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00002551 }
Richard Henderson743e3982015-12-17 11:19:23 -08002552
2553 /* Copy the FrameTemp value to EBP. */
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002554 gen_op_mov_reg_v(s, a_ot, R_EBP, s->T1);
Richard Henderson743e3982015-12-17 11:19:23 -08002555
2556 /* Compute the final value of ESP. */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04002557 tcg_gen_subi_tl(s->T1, s->T1, esp_addend + size * level);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002558 gen_op_mov_reg_v(s, a_ot, R_ESP, s->T1);
bellard2c0262a2003-09-30 20:34:21 +00002559}
2560
Richard Henderson2045f042015-12-17 11:19:24 -08002561static void gen_leave(DisasContext *s)
2562{
Tony Nguyen14776ab2019-08-24 04:10:58 +10002563 MemOp d_ot = mo_pushpop(s, s->dflag);
2564 MemOp a_ot = mo_stacksize(s);
Richard Henderson2045f042015-12-17 11:19:24 -08002565
2566 gen_lea_v_seg(s, a_ot, cpu_regs[R_EBP], R_SS, -1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04002567 gen_op_ld_v(s, d_ot, s->T0, s->A0);
Richard Henderson2045f042015-12-17 11:19:24 -08002568
Emilio G. Cotab48597b2018-09-11 14:50:46 -04002569 tcg_gen_addi_tl(s->T1, cpu_regs[R_EBP], 1 << d_ot);
Richard Henderson2045f042015-12-17 11:19:24 -08002570
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04002571 gen_op_mov_reg_v(s, d_ot, R_EBP, s->T0);
2572 gen_op_mov_reg_v(s, a_ot, R_ESP, s->T1);
Richard Henderson2045f042015-12-17 11:19:24 -08002573}
2574
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08002575/* Similarly, except that the assumption here is that we don't decode
2576 the instruction at all -- either a missing opcode, an unimplemented
2577 feature, or just a bogus instruction stream. */
2578static void gen_unknown_opcode(CPUX86State *env, DisasContext *s)
2579{
2580 gen_illegal_opcode(s);
2581
2582 if (qemu_loglevel_mask(LOG_UNIMP)) {
Robert Foleyfc59d2d2019-11-18 16:15:26 -05002583 FILE *logfile = qemu_log_lock();
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08002584 target_ulong pc = s->pc_start, end = s->pc;
Robert Foleyfc59d2d2019-11-18 16:15:26 -05002585
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08002586 qemu_log("ILLOPC: " TARGET_FMT_lx ":", pc);
2587 for (; pc < end; ++pc) {
2588 qemu_log(" %02x", cpu_ldub_code(env, pc));
2589 }
2590 qemu_log("\n");
Robert Foleyfc59d2d2019-11-18 16:15:26 -05002591 qemu_log_unlock(logfile);
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08002592 }
2593}
2594
bellard2c0262a2003-09-30 20:34:21 +00002595/* an interrupt is different from an exception because of the
blueswir17f75ffd2007-05-27 19:39:27 +00002596 privilege checks */
ths5fafdf22007-09-16 21:08:06 +00002597static void gen_interrupt(DisasContext *s, int intno,
bellard14ce26e2005-01-03 23:50:08 +00002598 target_ulong cur_eip, target_ulong next_eip)
bellard2c0262a2003-09-30 20:34:21 +00002599{
Richard Henderson773cdfc2013-01-23 12:43:12 -08002600 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002601 gen_jmp_im(s, cur_eip);
Blue Swirl77b2bc22012-04-28 19:35:10 +00002602 gen_helper_raise_interrupt(cpu_env, tcg_const_i32(intno),
pbrooka7812ae2008-11-17 14:43:54 +00002603 tcg_const_i32(next_eip - cur_eip));
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03002604 s->base.is_jmp = DISAS_NORETURN;
bellard2c0262a2003-09-30 20:34:21 +00002605}
2606
Richard Henderson7f0b7142015-07-06 17:29:59 +01002607static void gen_set_hflag(DisasContext *s, uint32_t mask)
2608{
2609 if ((s->flags & mask) == 0) {
2610 TCGv_i32 t = tcg_temp_new_i32();
2611 tcg_gen_ld_i32(t, cpu_env, offsetof(CPUX86State, hflags));
2612 tcg_gen_ori_i32(t, t, mask);
2613 tcg_gen_st_i32(t, cpu_env, offsetof(CPUX86State, hflags));
2614 tcg_temp_free_i32(t);
2615 s->flags |= mask;
2616 }
2617}
2618
2619static void gen_reset_hflag(DisasContext *s, uint32_t mask)
2620{
2621 if (s->flags & mask) {
2622 TCGv_i32 t = tcg_temp_new_i32();
2623 tcg_gen_ld_i32(t, cpu_env, offsetof(CPUX86State, hflags));
2624 tcg_gen_andi_i32(t, t, ~mask);
2625 tcg_gen_st_i32(t, cpu_env, offsetof(CPUX86State, hflags));
2626 tcg_temp_free_i32(t);
2627 s->flags &= ~mask;
2628 }
2629}
2630
Richard Henderson7d117ce2015-07-07 14:38:58 +01002631/* Clear BND registers during legacy branches. */
2632static void gen_bnd_jmp(DisasContext *s)
2633{
Paolo Bonzini8b33e822016-03-01 16:12:25 +01002634 /* Clear the registers only if BND prefix is missing, MPX is enabled,
2635 and if the BNDREGs are known to be in use (non-zero) already.
2636 The helper itself will check BNDPRESERVE at runtime. */
Richard Henderson7d117ce2015-07-07 14:38:58 +01002637 if ((s->prefix & PREFIX_REPNZ) == 0
Paolo Bonzini8b33e822016-03-01 16:12:25 +01002638 && (s->flags & HF_MPX_EN_MASK) != 0
2639 && (s->flags & HF_MPX_IU_MASK) != 0) {
Richard Henderson7d117ce2015-07-07 14:38:58 +01002640 gen_helper_bnd_jmp(cpu_env);
2641 }
2642}
2643
Richard Hendersonf083d922016-03-02 21:16:51 -08002644/* Generate an end of block. Trace exception is also generated if needed.
Doug Evansc52ab082016-12-06 23:06:30 +00002645 If INHIBIT, set HF_INHIBIT_IRQ_MASK if it isn't already set.
2646 If RECHECK_TF, emit a rechecking helper for #DB, ignoring the state of
2647 S->TF. This is used by the syscall/sysret insns. */
Emilio G. Cota1ebb1af2017-04-26 23:29:21 -04002648static void
Emilio G. Cota7f116362017-07-11 17:06:48 -04002649do_gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf, bool jr)
bellard2c0262a2003-09-30 20:34:21 +00002650{
Richard Henderson773cdfc2013-01-23 12:43:12 -08002651 gen_update_cc_op(s);
Richard Hendersonf083d922016-03-02 21:16:51 -08002652
2653 /* If several instructions disable interrupts, only the first does it. */
2654 if (inhibit && !(s->flags & HF_INHIBIT_IRQ_MASK)) {
2655 gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
2656 } else {
2657 gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
2658 }
2659
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03002660 if (s->base.tb->flags & HF_RF_MASK) {
Blue Swirlf0967a12012-04-29 12:45:34 +00002661 gen_helper_reset_rf(cpu_env);
Jan Kiszkaa2397802009-05-10 22:30:53 +02002662 }
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03002663 if (s->base.singlestep_enabled) {
Blue Swirl4a7443b2012-04-29 18:42:47 +00002664 gen_helper_debug(cpu_env);
Doug Evansc52ab082016-12-06 23:06:30 +00002665 } else if (recheck_tf) {
2666 gen_helper_rechecking_single_step(cpu_env);
Richard Henderson07ea28b2018-05-30 18:06:23 -07002667 tcg_gen_exit_tb(NULL, 0);
Richard Hendersonc1de1a12021-05-14 10:13:17 -05002668 } else if (s->flags & HF_TF_MASK) {
Blue Swirl4a7443b2012-04-29 18:42:47 +00002669 gen_helper_single_step(cpu_env);
Emilio G. Cota7f116362017-07-11 17:06:48 -04002670 } else if (jr) {
2671 tcg_gen_lookup_and_goto_ptr();
bellard2c0262a2003-09-30 20:34:21 +00002672 } else {
Richard Henderson07ea28b2018-05-30 18:06:23 -07002673 tcg_gen_exit_tb(NULL, 0);
bellard2c0262a2003-09-30 20:34:21 +00002674 }
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03002675 s->base.is_jmp = DISAS_NORETURN;
bellard2c0262a2003-09-30 20:34:21 +00002676}
2677
Emilio G. Cota1ebb1af2017-04-26 23:29:21 -04002678static inline void
2679gen_eob_worker(DisasContext *s, bool inhibit, bool recheck_tf)
2680{
Emilio G. Cota7f116362017-07-11 17:06:48 -04002681 do_gen_eob_worker(s, inhibit, recheck_tf, false);
Emilio G. Cota1ebb1af2017-04-26 23:29:21 -04002682}
2683
Doug Evansc52ab082016-12-06 23:06:30 +00002684/* End of block.
2685 If INHIBIT, set HF_INHIBIT_IRQ_MASK if it isn't already set. */
2686static void gen_eob_inhibit_irq(DisasContext *s, bool inhibit)
2687{
2688 gen_eob_worker(s, inhibit, false);
2689}
2690
Richard Hendersonf083d922016-03-02 21:16:51 -08002691/* End of block, resetting the inhibit irq flag. */
2692static void gen_eob(DisasContext *s)
2693{
Doug Evansc52ab082016-12-06 23:06:30 +00002694 gen_eob_worker(s, false, false);
Richard Hendersonf083d922016-03-02 21:16:51 -08002695}
2696
Emilio G. Cota1ebb1af2017-04-26 23:29:21 -04002697/* Jump to register */
2698static void gen_jr(DisasContext *s, TCGv dest)
2699{
Emilio G. Cota7f116362017-07-11 17:06:48 -04002700 do_gen_eob_worker(s, false, false, true);
Emilio G. Cota1ebb1af2017-04-26 23:29:21 -04002701}
2702
bellard2c0262a2003-09-30 20:34:21 +00002703/* generate a jump to eip. No segment change must happen before as a
2704 direct call to the next block may occur */
bellard14ce26e2005-01-03 23:50:08 +00002705static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
bellard2c0262a2003-09-30 20:34:21 +00002706{
Richard Hendersona3251182013-01-23 15:43:03 -08002707 gen_update_cc_op(s);
2708 set_cc_op(s, CC_OP_DYNAMIC);
bellard2c0262a2003-09-30 20:34:21 +00002709 if (s->jmp_opt) {
bellard6e256c92005-11-20 10:32:05 +00002710 gen_goto_tb(s, tb_num, eip);
bellard2c0262a2003-09-30 20:34:21 +00002711 } else {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002712 gen_jmp_im(s, eip);
bellard2c0262a2003-09-30 20:34:21 +00002713 gen_eob(s);
2714 }
2715}
2716
bellard14ce26e2005-01-03 23:50:08 +00002717static void gen_jmp(DisasContext *s, target_ulong eip)
2718{
2719 gen_jmp_tb(s, eip, 0);
2720}
2721
Richard Henderson323d1872013-10-30 22:04:05 -07002722static inline void gen_ldq_env_A0(DisasContext *s, int offset)
bellard8686c492008-05-12 13:55:27 +00002723{
Emilio G. Cota776678b2018-09-11 14:22:31 -04002724 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEQ);
2725 tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset);
bellard8686c492008-05-12 13:55:27 +00002726}
bellard664e0f12005-01-08 18:58:29 +00002727
Richard Henderson323d1872013-10-30 22:04:05 -07002728static inline void gen_stq_env_A0(DisasContext *s, int offset)
bellard8686c492008-05-12 13:55:27 +00002729{
Emilio G. Cota776678b2018-09-11 14:22:31 -04002730 tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset);
2731 tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, s->mem_index, MO_LEQ);
bellard8686c492008-05-12 13:55:27 +00002732}
bellard664e0f12005-01-08 18:58:29 +00002733
Richard Henderson323d1872013-10-30 22:04:05 -07002734static inline void gen_ldo_env_A0(DisasContext *s, int offset)
bellard8686c492008-05-12 13:55:27 +00002735{
Richard Henderson5c42a7c2013-10-30 22:20:42 -07002736 int mem_index = s->mem_index;
Emilio G. Cota776678b2018-09-11 14:22:31 -04002737 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0, mem_index, MO_LEQ);
2738 tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(0)));
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002739 tcg_gen_addi_tl(s->tmp0, s->A0, 8);
Emilio G. Cota776678b2018-09-11 14:22:31 -04002740 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEQ);
2741 tcg_gen_st_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(1)));
bellard8686c492008-05-12 13:55:27 +00002742}
bellard14ce26e2005-01-03 23:50:08 +00002743
Richard Henderson323d1872013-10-30 22:04:05 -07002744static inline void gen_sto_env_A0(DisasContext *s, int offset)
bellard8686c492008-05-12 13:55:27 +00002745{
Richard Henderson5c42a7c2013-10-30 22:20:42 -07002746 int mem_index = s->mem_index;
Emilio G. Cota776678b2018-09-11 14:22:31 -04002747 tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(0)));
2748 tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0, mem_index, MO_LEQ);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04002749 tcg_gen_addi_tl(s->tmp0, s->A0, 8);
Emilio G. Cota776678b2018-09-11 14:22:31 -04002750 tcg_gen_ld_i64(s->tmp1_i64, cpu_env, offset + offsetof(ZMMReg, ZMM_Q(1)));
2751 tcg_gen_qemu_st_i64(s->tmp1_i64, s->tmp0, mem_index, MO_LEQ);
bellard8686c492008-05-12 13:55:27 +00002752}
bellard14ce26e2005-01-03 23:50:08 +00002753
Emilio G. Cota776678b2018-09-11 14:22:31 -04002754static inline void gen_op_movo(DisasContext *s, int d_offset, int s_offset)
bellard5af45182008-05-12 16:47:36 +00002755{
Emilio G. Cota776678b2018-09-11 14:22:31 -04002756 tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset + offsetof(ZMMReg, ZMM_Q(0)));
2757 tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset + offsetof(ZMMReg, ZMM_Q(0)));
2758 tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset + offsetof(ZMMReg, ZMM_Q(1)));
2759 tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset + offsetof(ZMMReg, ZMM_Q(1)));
bellard5af45182008-05-12 16:47:36 +00002760}
bellard664e0f12005-01-08 18:58:29 +00002761
Emilio G. Cota776678b2018-09-11 14:22:31 -04002762static inline void gen_op_movq(DisasContext *s, int d_offset, int s_offset)
bellard5af45182008-05-12 16:47:36 +00002763{
Emilio G. Cota776678b2018-09-11 14:22:31 -04002764 tcg_gen_ld_i64(s->tmp1_i64, cpu_env, s_offset);
2765 tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset);
bellard5af45182008-05-12 16:47:36 +00002766}
bellard664e0f12005-01-08 18:58:29 +00002767
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04002768static inline void gen_op_movl(DisasContext *s, int d_offset, int s_offset)
bellard5af45182008-05-12 16:47:36 +00002769{
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04002770 tcg_gen_ld_i32(s->tmp2_i32, cpu_env, s_offset);
2771 tcg_gen_st_i32(s->tmp2_i32, cpu_env, d_offset);
bellard5af45182008-05-12 16:47:36 +00002772}
2773
Emilio G. Cota776678b2018-09-11 14:22:31 -04002774static inline void gen_op_movq_env_0(DisasContext *s, int d_offset)
bellard5af45182008-05-12 16:47:36 +00002775{
Emilio G. Cota776678b2018-09-11 14:22:31 -04002776 tcg_gen_movi_i64(s->tmp1_i64, 0);
2777 tcg_gen_st_i64(s->tmp1_i64, cpu_env, d_offset);
bellard5af45182008-05-12 16:47:36 +00002778}
2779
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002780typedef void (*SSEFunc_i_ep)(TCGv_i32 val, TCGv_ptr env, TCGv_ptr reg);
2781typedef void (*SSEFunc_l_ep)(TCGv_i64 val, TCGv_ptr env, TCGv_ptr reg);
2782typedef void (*SSEFunc_0_epi)(TCGv_ptr env, TCGv_ptr reg, TCGv_i32 val);
2783typedef void (*SSEFunc_0_epl)(TCGv_ptr env, TCGv_ptr reg, TCGv_i64 val);
2784typedef void (*SSEFunc_0_epp)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b);
2785typedef void (*SSEFunc_0_eppi)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
2786 TCGv_i32 val);
Blue Swirlc4baa052012-05-13 18:53:07 +00002787typedef void (*SSEFunc_0_ppi)(TCGv_ptr reg_a, TCGv_ptr reg_b, TCGv_i32 val);
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002788typedef void (*SSEFunc_0_eppt)(TCGv_ptr env, TCGv_ptr reg_a, TCGv_ptr reg_b,
2789 TCGv val);
Blue Swirlc4baa052012-05-13 18:53:07 +00002790
bellard5af45182008-05-12 16:47:36 +00002791#define SSE_SPECIAL ((void *)1)
2792#define SSE_DUMMY ((void *)2)
2793
pbrooka7812ae2008-11-17 14:43:54 +00002794#define MMX_OP2(x) { gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm }
2795#define SSE_FOP(x) { gen_helper_ ## x ## ps, gen_helper_ ## x ## pd, \
2796 gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, }
bellard5af45182008-05-12 16:47:36 +00002797
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002798static const SSEFunc_0_epp sse_op_table1[256][4] = {
aurel32a35f3ec2008-04-08 19:51:29 +00002799 /* 3DNow! extensions */
2800 [0x0e] = { SSE_DUMMY }, /* femms */
2801 [0x0f] = { SSE_DUMMY }, /* pf... */
bellard664e0f12005-01-08 18:58:29 +00002802 /* pure SSE operations */
2803 [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
2804 [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
bellard465e9832006-04-23 21:54:01 +00002805 [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */
bellard664e0f12005-01-08 18:58:29 +00002806 [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */
pbrooka7812ae2008-11-17 14:43:54 +00002807 [0x14] = { gen_helper_punpckldq_xmm, gen_helper_punpcklqdq_xmm },
2808 [0x15] = { gen_helper_punpckhdq_xmm, gen_helper_punpckhqdq_xmm },
bellard664e0f12005-01-08 18:58:29 +00002809 [0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd, movshdup */
2810 [0x17] = { SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd */
2811
2812 [0x28] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */
2813 [0x29] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */
2814 [0x2a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */
Andre Przywarad9f4bb22009-09-19 00:30:48 +02002815 [0x2b] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movntps, movntpd, movntss, movntsd */
bellard664e0f12005-01-08 18:58:29 +00002816 [0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */
2817 [0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */
pbrooka7812ae2008-11-17 14:43:54 +00002818 [0x2e] = { gen_helper_ucomiss, gen_helper_ucomisd },
2819 [0x2f] = { gen_helper_comiss, gen_helper_comisd },
bellard664e0f12005-01-08 18:58:29 +00002820 [0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */
2821 [0x51] = SSE_FOP(sqrt),
pbrooka7812ae2008-11-17 14:43:54 +00002822 [0x52] = { gen_helper_rsqrtps, NULL, gen_helper_rsqrtss, NULL },
2823 [0x53] = { gen_helper_rcpps, NULL, gen_helper_rcpss, NULL },
2824 [0x54] = { gen_helper_pand_xmm, gen_helper_pand_xmm }, /* andps, andpd */
2825 [0x55] = { gen_helper_pandn_xmm, gen_helper_pandn_xmm }, /* andnps, andnpd */
2826 [0x56] = { gen_helper_por_xmm, gen_helper_por_xmm }, /* orps, orpd */
2827 [0x57] = { gen_helper_pxor_xmm, gen_helper_pxor_xmm }, /* xorps, xorpd */
bellard664e0f12005-01-08 18:58:29 +00002828 [0x58] = SSE_FOP(add),
2829 [0x59] = SSE_FOP(mul),
pbrooka7812ae2008-11-17 14:43:54 +00002830 [0x5a] = { gen_helper_cvtps2pd, gen_helper_cvtpd2ps,
2831 gen_helper_cvtss2sd, gen_helper_cvtsd2ss },
2832 [0x5b] = { gen_helper_cvtdq2ps, gen_helper_cvtps2dq, gen_helper_cvttps2dq },
bellard664e0f12005-01-08 18:58:29 +00002833 [0x5c] = SSE_FOP(sub),
2834 [0x5d] = SSE_FOP(min),
2835 [0x5e] = SSE_FOP(div),
2836 [0x5f] = SSE_FOP(max),
2837
2838 [0xc2] = SSE_FOP(cmpeq),
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002839 [0xc6] = { (SSEFunc_0_epp)gen_helper_shufps,
2840 (SSEFunc_0_epp)gen_helper_shufpd }, /* XXX: casts */
bellard664e0f12005-01-08 18:58:29 +00002841
Richard Henderson7073fba2013-01-23 16:17:10 -08002842 /* SSSE3, SSE4, MOVBE, CRC32, BMI1, BMI2, ADX. */
2843 [0x38] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
2844 [0x3a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
balrog4242b1b2008-09-25 18:01:46 +00002845
bellard664e0f12005-01-08 18:58:29 +00002846 /* MMX ops and their SSE extensions */
2847 [0x60] = MMX_OP2(punpcklbw),
2848 [0x61] = MMX_OP2(punpcklwd),
2849 [0x62] = MMX_OP2(punpckldq),
2850 [0x63] = MMX_OP2(packsswb),
2851 [0x64] = MMX_OP2(pcmpgtb),
2852 [0x65] = MMX_OP2(pcmpgtw),
2853 [0x66] = MMX_OP2(pcmpgtl),
2854 [0x67] = MMX_OP2(packuswb),
2855 [0x68] = MMX_OP2(punpckhbw),
2856 [0x69] = MMX_OP2(punpckhwd),
2857 [0x6a] = MMX_OP2(punpckhdq),
2858 [0x6b] = MMX_OP2(packssdw),
pbrooka7812ae2008-11-17 14:43:54 +00002859 [0x6c] = { NULL, gen_helper_punpcklqdq_xmm },
2860 [0x6d] = { NULL, gen_helper_punpckhqdq_xmm },
bellard664e0f12005-01-08 18:58:29 +00002861 [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */
2862 [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002863 [0x70] = { (SSEFunc_0_epp)gen_helper_pshufw_mmx,
2864 (SSEFunc_0_epp)gen_helper_pshufd_xmm,
2865 (SSEFunc_0_epp)gen_helper_pshufhw_xmm,
2866 (SSEFunc_0_epp)gen_helper_pshuflw_xmm }, /* XXX: casts */
bellard664e0f12005-01-08 18:58:29 +00002867 [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
2868 [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
2869 [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */
2870 [0x74] = MMX_OP2(pcmpeqb),
2871 [0x75] = MMX_OP2(pcmpeqw),
2872 [0x76] = MMX_OP2(pcmpeql),
aurel32a35f3ec2008-04-08 19:51:29 +00002873 [0x77] = { SSE_DUMMY }, /* emms */
Andre Przywarad9f4bb22009-09-19 00:30:48 +02002874 [0x78] = { NULL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* extrq_i, insertq_i */
2875 [0x79] = { NULL, gen_helper_extrq_r, NULL, gen_helper_insertq_r },
pbrooka7812ae2008-11-17 14:43:54 +00002876 [0x7c] = { NULL, gen_helper_haddpd, NULL, gen_helper_haddps },
2877 [0x7d] = { NULL, gen_helper_hsubpd, NULL, gen_helper_hsubps },
bellard664e0f12005-01-08 18:58:29 +00002878 [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */
2879 [0x7f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, movdqu */
2880 [0xc4] = { SSE_SPECIAL, SSE_SPECIAL }, /* pinsrw */
2881 [0xc5] = { SSE_SPECIAL, SSE_SPECIAL }, /* pextrw */
pbrooka7812ae2008-11-17 14:43:54 +00002882 [0xd0] = { NULL, gen_helper_addsubpd, NULL, gen_helper_addsubps },
bellard664e0f12005-01-08 18:58:29 +00002883 [0xd1] = MMX_OP2(psrlw),
2884 [0xd2] = MMX_OP2(psrld),
2885 [0xd3] = MMX_OP2(psrlq),
2886 [0xd4] = MMX_OP2(paddq),
2887 [0xd5] = MMX_OP2(pmullw),
2888 [0xd6] = { NULL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
2889 [0xd7] = { SSE_SPECIAL, SSE_SPECIAL }, /* pmovmskb */
2890 [0xd8] = MMX_OP2(psubusb),
2891 [0xd9] = MMX_OP2(psubusw),
2892 [0xda] = MMX_OP2(pminub),
2893 [0xdb] = MMX_OP2(pand),
2894 [0xdc] = MMX_OP2(paddusb),
2895 [0xdd] = MMX_OP2(paddusw),
2896 [0xde] = MMX_OP2(pmaxub),
2897 [0xdf] = MMX_OP2(pandn),
2898 [0xe0] = MMX_OP2(pavgb),
2899 [0xe1] = MMX_OP2(psraw),
2900 [0xe2] = MMX_OP2(psrad),
2901 [0xe3] = MMX_OP2(pavgw),
2902 [0xe4] = MMX_OP2(pmulhuw),
2903 [0xe5] = MMX_OP2(pmulhw),
pbrooka7812ae2008-11-17 14:43:54 +00002904 [0xe6] = { NULL, gen_helper_cvttpd2dq, gen_helper_cvtdq2pd, gen_helper_cvtpd2dq },
bellard664e0f12005-01-08 18:58:29 +00002905 [0xe7] = { SSE_SPECIAL , SSE_SPECIAL }, /* movntq, movntq */
2906 [0xe8] = MMX_OP2(psubsb),
2907 [0xe9] = MMX_OP2(psubsw),
2908 [0xea] = MMX_OP2(pminsw),
2909 [0xeb] = MMX_OP2(por),
2910 [0xec] = MMX_OP2(paddsb),
2911 [0xed] = MMX_OP2(paddsw),
2912 [0xee] = MMX_OP2(pmaxsw),
2913 [0xef] = MMX_OP2(pxor),
bellard465e9832006-04-23 21:54:01 +00002914 [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */
bellard664e0f12005-01-08 18:58:29 +00002915 [0xf1] = MMX_OP2(psllw),
2916 [0xf2] = MMX_OP2(pslld),
2917 [0xf3] = MMX_OP2(psllq),
2918 [0xf4] = MMX_OP2(pmuludq),
2919 [0xf5] = MMX_OP2(pmaddwd),
2920 [0xf6] = MMX_OP2(psadbw),
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002921 [0xf7] = { (SSEFunc_0_epp)gen_helper_maskmov_mmx,
2922 (SSEFunc_0_epp)gen_helper_maskmov_xmm }, /* XXX: casts */
bellard664e0f12005-01-08 18:58:29 +00002923 [0xf8] = MMX_OP2(psubb),
2924 [0xf9] = MMX_OP2(psubw),
2925 [0xfa] = MMX_OP2(psubl),
2926 [0xfb] = MMX_OP2(psubq),
2927 [0xfc] = MMX_OP2(paddb),
2928 [0xfd] = MMX_OP2(paddw),
2929 [0xfe] = MMX_OP2(paddl),
2930};
2931
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002932static const SSEFunc_0_epp sse_op_table2[3 * 8][2] = {
bellard664e0f12005-01-08 18:58:29 +00002933 [0 + 2] = MMX_OP2(psrlw),
2934 [0 + 4] = MMX_OP2(psraw),
2935 [0 + 6] = MMX_OP2(psllw),
2936 [8 + 2] = MMX_OP2(psrld),
2937 [8 + 4] = MMX_OP2(psrad),
2938 [8 + 6] = MMX_OP2(pslld),
2939 [16 + 2] = MMX_OP2(psrlq),
pbrooka7812ae2008-11-17 14:43:54 +00002940 [16 + 3] = { NULL, gen_helper_psrldq_xmm },
bellard664e0f12005-01-08 18:58:29 +00002941 [16 + 6] = MMX_OP2(psllq),
pbrooka7812ae2008-11-17 14:43:54 +00002942 [16 + 7] = { NULL, gen_helper_pslldq_xmm },
bellard664e0f12005-01-08 18:58:29 +00002943};
2944
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002945static const SSEFunc_0_epi sse_op_table3ai[] = {
pbrooka7812ae2008-11-17 14:43:54 +00002946 gen_helper_cvtsi2ss,
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002947 gen_helper_cvtsi2sd
Blue Swirlc4baa052012-05-13 18:53:07 +00002948};
ths3b46e622007-09-17 08:09:54 +00002949
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002950#ifdef TARGET_X86_64
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002951static const SSEFunc_0_epl sse_op_table3aq[] = {
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002952 gen_helper_cvtsq2ss,
2953 gen_helper_cvtsq2sd
2954};
2955#endif
2956
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002957static const SSEFunc_i_ep sse_op_table3bi[] = {
pbrooka7812ae2008-11-17 14:43:54 +00002958 gen_helper_cvttss2si,
pbrooka7812ae2008-11-17 14:43:54 +00002959 gen_helper_cvtss2si,
Peter Maydellbedc2ac2012-07-05 22:29:00 +01002960 gen_helper_cvttsd2si,
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002961 gen_helper_cvtsd2si
bellard664e0f12005-01-08 18:58:29 +00002962};
ths3b46e622007-09-17 08:09:54 +00002963
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002964#ifdef TARGET_X86_64
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002965static const SSEFunc_l_ep sse_op_table3bq[] = {
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002966 gen_helper_cvttss2sq,
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002967 gen_helper_cvtss2sq,
Peter Maydellbedc2ac2012-07-05 22:29:00 +01002968 gen_helper_cvttsd2sq,
Stefan Weil11f8cdb2012-06-29 22:38:20 +02002969 gen_helper_cvtsd2sq
2970};
2971#endif
2972
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002973static const SSEFunc_0_epp sse_op_table4[8][4] = {
bellard664e0f12005-01-08 18:58:29 +00002974 SSE_FOP(cmpeq),
2975 SSE_FOP(cmplt),
2976 SSE_FOP(cmple),
2977 SSE_FOP(cmpunord),
2978 SSE_FOP(cmpneq),
2979 SSE_FOP(cmpnlt),
2980 SSE_FOP(cmpnle),
2981 SSE_FOP(cmpord),
2982};
ths3b46e622007-09-17 08:09:54 +00002983
Blue Swirld3eb5ea2012-04-28 21:28:09 +00002984static const SSEFunc_0_epp sse_op_table5[256] = {
pbrooka7812ae2008-11-17 14:43:54 +00002985 [0x0c] = gen_helper_pi2fw,
2986 [0x0d] = gen_helper_pi2fd,
2987 [0x1c] = gen_helper_pf2iw,
2988 [0x1d] = gen_helper_pf2id,
2989 [0x8a] = gen_helper_pfnacc,
2990 [0x8e] = gen_helper_pfpnacc,
2991 [0x90] = gen_helper_pfcmpge,
2992 [0x94] = gen_helper_pfmin,
2993 [0x96] = gen_helper_pfrcp,
2994 [0x97] = gen_helper_pfrsqrt,
2995 [0x9a] = gen_helper_pfsub,
2996 [0x9e] = gen_helper_pfadd,
2997 [0xa0] = gen_helper_pfcmpgt,
2998 [0xa4] = gen_helper_pfmax,
2999 [0xa6] = gen_helper_movq, /* pfrcpit1; no need to actually increase precision */
3000 [0xa7] = gen_helper_movq, /* pfrsqit1 */
3001 [0xaa] = gen_helper_pfsubr,
3002 [0xae] = gen_helper_pfacc,
3003 [0xb0] = gen_helper_pfcmpeq,
3004 [0xb4] = gen_helper_pfmul,
3005 [0xb6] = gen_helper_movq, /* pfrcpit2 */
3006 [0xb7] = gen_helper_pmulhrw_mmx,
3007 [0xbb] = gen_helper_pswapd,
3008 [0xbf] = gen_helper_pavgb_mmx /* pavgusb */
aurel32a35f3ec2008-04-08 19:51:29 +00003009};
3010
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003011struct SSEOpHelper_epp {
3012 SSEFunc_0_epp op[2];
Blue Swirlc4baa052012-05-13 18:53:07 +00003013 uint32_t ext_mask;
balrog222a3332008-10-04 03:27:44 +00003014};
Blue Swirlc4baa052012-05-13 18:53:07 +00003015
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003016struct SSEOpHelper_eppi {
3017 SSEFunc_0_eppi op[2];
Blue Swirlc4baa052012-05-13 18:53:07 +00003018 uint32_t ext_mask;
3019};
3020
balrog222a3332008-10-04 03:27:44 +00003021#define SSSE3_OP(x) { MMX_OP2(x), CPUID_EXT_SSSE3 }
pbrooka7812ae2008-11-17 14:43:54 +00003022#define SSE41_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE41 }
3023#define SSE42_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE42 }
balrog222a3332008-10-04 03:27:44 +00003024#define SSE41_SPECIAL { { NULL, SSE_SPECIAL }, CPUID_EXT_SSE41 }
Aurelien Jarnoe71827b2013-03-31 12:58:30 +02003025#define PCLMULQDQ_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, \
3026 CPUID_EXT_PCLMULQDQ }
Aurelien Jarnod6400452013-03-31 12:58:31 +02003027#define AESNI_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_AES }
Blue Swirlc4baa052012-05-13 18:53:07 +00003028
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003029static const struct SSEOpHelper_epp sse_op_table6[256] = {
balrog222a3332008-10-04 03:27:44 +00003030 [0x00] = SSSE3_OP(pshufb),
3031 [0x01] = SSSE3_OP(phaddw),
3032 [0x02] = SSSE3_OP(phaddd),
3033 [0x03] = SSSE3_OP(phaddsw),
3034 [0x04] = SSSE3_OP(pmaddubsw),
3035 [0x05] = SSSE3_OP(phsubw),
3036 [0x06] = SSSE3_OP(phsubd),
3037 [0x07] = SSSE3_OP(phsubsw),
3038 [0x08] = SSSE3_OP(psignb),
3039 [0x09] = SSSE3_OP(psignw),
3040 [0x0a] = SSSE3_OP(psignd),
3041 [0x0b] = SSSE3_OP(pmulhrsw),
3042 [0x10] = SSE41_OP(pblendvb),
3043 [0x14] = SSE41_OP(blendvps),
3044 [0x15] = SSE41_OP(blendvpd),
3045 [0x17] = SSE41_OP(ptest),
3046 [0x1c] = SSSE3_OP(pabsb),
3047 [0x1d] = SSSE3_OP(pabsw),
3048 [0x1e] = SSSE3_OP(pabsd),
3049 [0x20] = SSE41_OP(pmovsxbw),
3050 [0x21] = SSE41_OP(pmovsxbd),
3051 [0x22] = SSE41_OP(pmovsxbq),
3052 [0x23] = SSE41_OP(pmovsxwd),
3053 [0x24] = SSE41_OP(pmovsxwq),
3054 [0x25] = SSE41_OP(pmovsxdq),
3055 [0x28] = SSE41_OP(pmuldq),
3056 [0x29] = SSE41_OP(pcmpeqq),
3057 [0x2a] = SSE41_SPECIAL, /* movntqda */
3058 [0x2b] = SSE41_OP(packusdw),
3059 [0x30] = SSE41_OP(pmovzxbw),
3060 [0x31] = SSE41_OP(pmovzxbd),
3061 [0x32] = SSE41_OP(pmovzxbq),
3062 [0x33] = SSE41_OP(pmovzxwd),
3063 [0x34] = SSE41_OP(pmovzxwq),
3064 [0x35] = SSE41_OP(pmovzxdq),
3065 [0x37] = SSE42_OP(pcmpgtq),
3066 [0x38] = SSE41_OP(pminsb),
3067 [0x39] = SSE41_OP(pminsd),
3068 [0x3a] = SSE41_OP(pminuw),
3069 [0x3b] = SSE41_OP(pminud),
3070 [0x3c] = SSE41_OP(pmaxsb),
3071 [0x3d] = SSE41_OP(pmaxsd),
3072 [0x3e] = SSE41_OP(pmaxuw),
3073 [0x3f] = SSE41_OP(pmaxud),
3074 [0x40] = SSE41_OP(pmulld),
3075 [0x41] = SSE41_OP(phminposuw),
Aurelien Jarnod6400452013-03-31 12:58:31 +02003076 [0xdb] = AESNI_OP(aesimc),
3077 [0xdc] = AESNI_OP(aesenc),
3078 [0xdd] = AESNI_OP(aesenclast),
3079 [0xde] = AESNI_OP(aesdec),
3080 [0xdf] = AESNI_OP(aesdeclast),
balrog4242b1b2008-09-25 18:01:46 +00003081};
3082
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003083static const struct SSEOpHelper_eppi sse_op_table7[256] = {
balrog222a3332008-10-04 03:27:44 +00003084 [0x08] = SSE41_OP(roundps),
3085 [0x09] = SSE41_OP(roundpd),
3086 [0x0a] = SSE41_OP(roundss),
3087 [0x0b] = SSE41_OP(roundsd),
3088 [0x0c] = SSE41_OP(blendps),
3089 [0x0d] = SSE41_OP(blendpd),
3090 [0x0e] = SSE41_OP(pblendw),
3091 [0x0f] = SSSE3_OP(palignr),
3092 [0x14] = SSE41_SPECIAL, /* pextrb */
3093 [0x15] = SSE41_SPECIAL, /* pextrw */
3094 [0x16] = SSE41_SPECIAL, /* pextrd/pextrq */
3095 [0x17] = SSE41_SPECIAL, /* extractps */
3096 [0x20] = SSE41_SPECIAL, /* pinsrb */
3097 [0x21] = SSE41_SPECIAL, /* insertps */
3098 [0x22] = SSE41_SPECIAL, /* pinsrd/pinsrq */
3099 [0x40] = SSE41_OP(dpps),
3100 [0x41] = SSE41_OP(dppd),
3101 [0x42] = SSE41_OP(mpsadbw),
Aurelien Jarnoe71827b2013-03-31 12:58:30 +02003102 [0x44] = PCLMULQDQ_OP(pclmulqdq),
balrog222a3332008-10-04 03:27:44 +00003103 [0x60] = SSE42_OP(pcmpestrm),
3104 [0x61] = SSE42_OP(pcmpestri),
3105 [0x62] = SSE42_OP(pcmpistrm),
3106 [0x63] = SSE42_OP(pcmpistri),
Aurelien Jarnod6400452013-03-31 12:58:31 +02003107 [0xdf] = AESNI_OP(aeskeygenassist),
balrog4242b1b2008-09-25 18:01:46 +00003108};
3109
Blue Swirl0af10c82012-09-08 13:26:02 +00003110static void gen_sse(CPUX86State *env, DisasContext *s, int b,
Richard Hendersonbbdb4232021-05-14 10:13:09 -05003111 target_ulong pc_start)
bellard664e0f12005-01-08 18:58:29 +00003112{
Richard Hendersond67dc9e2013-11-06 07:25:05 +10003113 int b1, op1_offset, op2_offset, is_xmm, val;
Richard Henderson4eeb3932013-11-02 08:55:59 -10003114 int modrm, mod, rm, reg;
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003115 SSEFunc_0_epp sse_fn_epp;
3116 SSEFunc_0_eppi sse_fn_eppi;
Blue Swirlc4baa052012-05-13 18:53:07 +00003117 SSEFunc_0_ppi sse_fn_ppi;
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003118 SSEFunc_0_eppt sse_fn_eppt;
Tony Nguyen14776ab2019-08-24 04:10:58 +10003119 MemOp ot;
bellard664e0f12005-01-08 18:58:29 +00003120
3121 b &= 0xff;
ths5fafdf22007-09-16 21:08:06 +00003122 if (s->prefix & PREFIX_DATA)
bellard664e0f12005-01-08 18:58:29 +00003123 b1 = 1;
ths5fafdf22007-09-16 21:08:06 +00003124 else if (s->prefix & PREFIX_REPZ)
bellard664e0f12005-01-08 18:58:29 +00003125 b1 = 2;
ths5fafdf22007-09-16 21:08:06 +00003126 else if (s->prefix & PREFIX_REPNZ)
bellard664e0f12005-01-08 18:58:29 +00003127 b1 = 3;
3128 else
3129 b1 = 0;
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003130 sse_fn_epp = sse_op_table1[b][b1];
3131 if (!sse_fn_epp) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003132 goto unknown_op;
Blue Swirlc4baa052012-05-13 18:53:07 +00003133 }
aurel32a35f3ec2008-04-08 19:51:29 +00003134 if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
bellard664e0f12005-01-08 18:58:29 +00003135 is_xmm = 1;
3136 } else {
3137 if (b1 == 0) {
3138 /* MMX case */
3139 is_xmm = 0;
3140 } else {
3141 is_xmm = 1;
3142 }
3143 }
3144 /* simple MMX/SSE operation */
3145 if (s->flags & HF_TS_MASK) {
3146 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
3147 return;
3148 }
3149 if (s->flags & HF_EM_MASK) {
3150 illegal_op:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003151 gen_illegal_opcode(s);
bellard664e0f12005-01-08 18:58:29 +00003152 return;
3153 }
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003154 if (is_xmm
3155 && !(s->flags & HF_OSFXSR_MASK)
David Greenaway51909242021-01-14 17:39:58 +11003156 && (b != 0x38 && b != 0x3a)) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003157 goto unknown_op;
3158 }
aurel32e771eda2008-04-09 06:41:37 +00003159 if (b == 0x0e) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003160 if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
3161 /* If we were fully decoding this we might use illegal_op. */
3162 goto unknown_op;
3163 }
aurel32e771eda2008-04-09 06:41:37 +00003164 /* femms */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003165 gen_helper_emms(cpu_env);
aurel32e771eda2008-04-09 06:41:37 +00003166 return;
3167 }
3168 if (b == 0x77) {
3169 /* emms */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003170 gen_helper_emms(cpu_env);
bellard664e0f12005-01-08 18:58:29 +00003171 return;
3172 }
3173 /* prepare MMX state (XXX: optimize by storing fptt and fptags in
3174 the static cpu state) */
3175 if (!is_xmm) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003176 gen_helper_enter_mmx(cpu_env);
bellard664e0f12005-01-08 18:58:29 +00003177 }
3178
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02003179 modrm = x86_ldub_code(env, s);
bellard664e0f12005-01-08 18:58:29 +00003180 reg = ((modrm >> 3) & 7);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05003181 if (is_xmm) {
3182 reg |= REX_R(s);
3183 }
bellard664e0f12005-01-08 18:58:29 +00003184 mod = (modrm >> 6) & 3;
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003185 if (sse_fn_epp == SSE_SPECIAL) {
bellard664e0f12005-01-08 18:58:29 +00003186 b |= (b1 << 8);
3187 switch(b) {
3188 case 0x0e7: /* movntq */
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003189 if (mod == 3) {
bellard664e0f12005-01-08 18:58:29 +00003190 goto illegal_op;
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003191 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10003192 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003193 gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx));
bellard664e0f12005-01-08 18:58:29 +00003194 break;
3195 case 0x1e7: /* movntdq */
3196 case 0x02b: /* movntps */
3197 case 0x12b: /* movntps */
TeLeMan2e21e742010-03-12 19:38:06 +08003198 if (mod == 3)
3199 goto illegal_op;
Richard Henderson4eeb3932013-11-02 08:55:59 -10003200 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003201 gen_sto_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
TeLeMan2e21e742010-03-12 19:38:06 +08003202 break;
bellard465e9832006-04-23 21:54:01 +00003203 case 0x3f0: /* lddqu */
3204 if (mod == 3)
bellard664e0f12005-01-08 18:58:29 +00003205 goto illegal_op;
Richard Henderson4eeb3932013-11-02 08:55:59 -10003206 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003207 gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
bellard664e0f12005-01-08 18:58:29 +00003208 break;
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003209 case 0x22b: /* movntss */
3210 case 0x32b: /* movntsd */
3211 if (mod == 3)
3212 goto illegal_op;
Richard Henderson4eeb3932013-11-02 08:55:59 -10003213 gen_lea_modrm(env, s, modrm);
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003214 if (b1 & 1) {
Paolo Bonzini07958082015-01-07 17:36:27 +01003215 gen_stq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003216 xmm_regs[reg].ZMM_Q(0)));
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003217 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003218 tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003219 xmm_regs[reg].ZMM_L(0)));
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003220 gen_op_st_v(s, MO_32, s->T0, s->A0);
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003221 }
3222 break;
bellard664e0f12005-01-08 18:58:29 +00003223 case 0x6e: /* movd mm, ea */
bellarddabd98d2007-01-16 19:28:58 +00003224#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003225 if (s->dflag == MO_64) {
Richard Henderson4ba99382013-11-02 09:54:47 -07003226 gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003227 tcg_gen_st_tl(s->T0, cpu_env,
3228 offsetof(CPUX86State, fpregs[reg].mmx));
ths5fafdf22007-09-16 21:08:06 +00003229 } else
bellarddabd98d2007-01-16 19:28:58 +00003230#endif
3231 {
Richard Henderson4ba99382013-11-02 09:54:47 -07003232 gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 0);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003233 tcg_gen_addi_ptr(s->ptr0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003234 offsetof(CPUX86State,fpregs[reg].mmx));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003235 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
3236 gen_helper_movl_mm_T0_mmx(s->ptr0, s->tmp2_i32);
bellarddabd98d2007-01-16 19:28:58 +00003237 }
bellard664e0f12005-01-08 18:58:29 +00003238 break;
3239 case 0x16e: /* movd xmm, ea */
bellarddabd98d2007-01-16 19:28:58 +00003240#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003241 if (s->dflag == MO_64) {
Richard Henderson4ba99382013-11-02 09:54:47 -07003242 gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 0);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003243 tcg_gen_addi_ptr(s->ptr0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003244 offsetof(CPUX86State,xmm_regs[reg]));
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003245 gen_helper_movq_mm_T0_xmm(s->ptr0, s->T0);
ths5fafdf22007-09-16 21:08:06 +00003246 } else
bellarddabd98d2007-01-16 19:28:58 +00003247#endif
3248 {
Richard Henderson4ba99382013-11-02 09:54:47 -07003249 gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 0);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003250 tcg_gen_addi_ptr(s->ptr0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003251 offsetof(CPUX86State,xmm_regs[reg]));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003252 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
3253 gen_helper_movl_mm_T0_xmm(s->ptr0, s->tmp2_i32);
bellarddabd98d2007-01-16 19:28:58 +00003254 }
bellard664e0f12005-01-08 18:58:29 +00003255 break;
3256 case 0x6f: /* movq mm, ea */
3257 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003258 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003259 gen_ldq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx));
bellard664e0f12005-01-08 18:58:29 +00003260 } else {
3261 rm = (modrm & 7);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003262 tcg_gen_ld_i64(s->tmp1_i64, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003263 offsetof(CPUX86State,fpregs[rm].mmx));
Emilio G. Cota776678b2018-09-11 14:22:31 -04003264 tcg_gen_st_i64(s->tmp1_i64, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003265 offsetof(CPUX86State,fpregs[reg].mmx));
bellard664e0f12005-01-08 18:58:29 +00003266 }
3267 break;
3268 case 0x010: /* movups */
3269 case 0x110: /* movupd */
3270 case 0x028: /* movaps */
3271 case 0x128: /* movapd */
3272 case 0x16f: /* movdqa xmm, ea */
3273 case 0x26f: /* movdqu xmm, ea */
3274 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003275 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003276 gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
bellard664e0f12005-01-08 18:58:29 +00003277 } else {
3278 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003279 gen_op_movo(s, offsetof(CPUX86State, xmm_regs[reg]),
bellard664e0f12005-01-08 18:58:29 +00003280 offsetof(CPUX86State,xmm_regs[rm]));
3281 }
3282 break;
3283 case 0x210: /* movss xmm, ea */
3284 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003285 gen_lea_modrm(env, s, modrm);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003286 gen_op_ld_v(s, MO_32, s->T0, s->A0);
3287 tcg_gen_st32_tl(s->T0, cpu_env,
3288 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)));
3289 tcg_gen_movi_tl(s->T0, 0);
3290 tcg_gen_st32_tl(s->T0, cpu_env,
3291 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1)));
3292 tcg_gen_st32_tl(s->T0, cpu_env,
3293 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2)));
3294 tcg_gen_st32_tl(s->T0, cpu_env,
3295 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3)));
bellard664e0f12005-01-08 18:58:29 +00003296 } else {
3297 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003298 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003299 offsetof(CPUX86State,xmm_regs[rm].ZMM_L(0)));
bellard664e0f12005-01-08 18:58:29 +00003300 }
3301 break;
3302 case 0x310: /* movsd xmm, ea */
3303 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003304 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003305 gen_ldq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003306 xmm_regs[reg].ZMM_Q(0)));
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003307 tcg_gen_movi_tl(s->T0, 0);
3308 tcg_gen_st32_tl(s->T0, cpu_env,
3309 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2)));
3310 tcg_gen_st32_tl(s->T0, cpu_env,
3311 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3)));
bellard664e0f12005-01-08 18:58:29 +00003312 } else {
3313 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003314 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003315 offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003316 }
3317 break;
3318 case 0x012: /* movlps */
3319 case 0x112: /* movlpd */
3320 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003321 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003322 gen_ldq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003323 xmm_regs[reg].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003324 } else {
3325 /* movhlps */
3326 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003327 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003328 offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(1)));
bellard664e0f12005-01-08 18:58:29 +00003329 }
3330 break;
bellard465e9832006-04-23 21:54:01 +00003331 case 0x212: /* movsldup */
3332 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003333 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003334 gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
bellard465e9832006-04-23 21:54:01 +00003335 } else {
3336 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003337 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003338 offsetof(CPUX86State,xmm_regs[rm].ZMM_L(0)));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003339 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003340 offsetof(CPUX86State,xmm_regs[rm].ZMM_L(2)));
bellard465e9832006-04-23 21:54:01 +00003341 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003342 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003343 offsetof(CPUX86State,xmm_regs[reg].ZMM_L(0)));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003344 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003345 offsetof(CPUX86State,xmm_regs[reg].ZMM_L(2)));
bellard465e9832006-04-23 21:54:01 +00003346 break;
3347 case 0x312: /* movddup */
3348 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003349 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003350 gen_ldq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003351 xmm_regs[reg].ZMM_Q(0)));
bellard465e9832006-04-23 21:54:01 +00003352 } else {
3353 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003354 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003355 offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0)));
bellard465e9832006-04-23 21:54:01 +00003356 }
Emilio G. Cota776678b2018-09-11 14:22:31 -04003357 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003358 offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0)));
bellard465e9832006-04-23 21:54:01 +00003359 break;
bellard664e0f12005-01-08 18:58:29 +00003360 case 0x016: /* movhps */
3361 case 0x116: /* movhpd */
3362 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003363 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003364 gen_ldq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003365 xmm_regs[reg].ZMM_Q(1)));
bellard664e0f12005-01-08 18:58:29 +00003366 } else {
3367 /* movlhps */
3368 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003369 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003370 offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003371 }
3372 break;
3373 case 0x216: /* movshdup */
3374 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003375 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003376 gen_ldo_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
bellard664e0f12005-01-08 18:58:29 +00003377 } else {
3378 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003379 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(1)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003380 offsetof(CPUX86State,xmm_regs[rm].ZMM_L(1)));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003381 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(3)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003382 offsetof(CPUX86State,xmm_regs[rm].ZMM_L(3)));
bellard664e0f12005-01-08 18:58:29 +00003383 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003384 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003385 offsetof(CPUX86State,xmm_regs[reg].ZMM_L(1)));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003386 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_L(2)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003387 offsetof(CPUX86State,xmm_regs[reg].ZMM_L(3)));
bellard664e0f12005-01-08 18:58:29 +00003388 break;
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003389 case 0x178:
3390 case 0x378:
3391 {
3392 int bit_index, field_length;
3393
3394 if (b1 == 1 && reg != 0)
3395 goto illegal_op;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02003396 field_length = x86_ldub_code(env, s) & 0x3F;
3397 bit_index = x86_ldub_code(env, s) & 0x3F;
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003398 tcg_gen_addi_ptr(s->ptr0, cpu_env,
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003399 offsetof(CPUX86State,xmm_regs[reg]));
3400 if (b1 == 1)
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003401 gen_helper_extrq_i(cpu_env, s->ptr0,
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003402 tcg_const_i32(bit_index),
3403 tcg_const_i32(field_length));
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003404 else
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003405 gen_helper_insertq_i(cpu_env, s->ptr0,
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003406 tcg_const_i32(bit_index),
3407 tcg_const_i32(field_length));
Andre Przywarad9f4bb22009-09-19 00:30:48 +02003408 }
3409 break;
bellard664e0f12005-01-08 18:58:29 +00003410 case 0x7e: /* movd ea, mm */
bellarddabd98d2007-01-16 19:28:58 +00003411#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003412 if (s->dflag == MO_64) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003413 tcg_gen_ld_i64(s->T0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003414 offsetof(CPUX86State,fpregs[reg].mmx));
Richard Henderson4ba99382013-11-02 09:54:47 -07003415 gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 1);
ths5fafdf22007-09-16 21:08:06 +00003416 } else
bellarddabd98d2007-01-16 19:28:58 +00003417#endif
3418 {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003419 tcg_gen_ld32u_tl(s->T0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003420 offsetof(CPUX86State,fpregs[reg].mmx.MMX_L(0)));
Richard Henderson4ba99382013-11-02 09:54:47 -07003421 gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 1);
bellarddabd98d2007-01-16 19:28:58 +00003422 }
bellard664e0f12005-01-08 18:58:29 +00003423 break;
3424 case 0x17e: /* movd ea, xmm */
bellarddabd98d2007-01-16 19:28:58 +00003425#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003426 if (s->dflag == MO_64) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003427 tcg_gen_ld_i64(s->T0, cpu_env,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003428 offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0)));
Richard Henderson4ba99382013-11-02 09:54:47 -07003429 gen_ldst_modrm(env, s, modrm, MO_64, OR_TMP0, 1);
ths5fafdf22007-09-16 21:08:06 +00003430 } else
bellarddabd98d2007-01-16 19:28:58 +00003431#endif
3432 {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003433 tcg_gen_ld32u_tl(s->T0, cpu_env,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003434 offsetof(CPUX86State,xmm_regs[reg].ZMM_L(0)));
Richard Henderson4ba99382013-11-02 09:54:47 -07003435 gen_ldst_modrm(env, s, modrm, MO_32, OR_TMP0, 1);
bellarddabd98d2007-01-16 19:28:58 +00003436 }
bellard664e0f12005-01-08 18:58:29 +00003437 break;
3438 case 0x27e: /* movq xmm, ea */
3439 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003440 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003441 gen_ldq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003442 xmm_regs[reg].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003443 } else {
3444 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003445 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003446 offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003447 }
Emilio G. Cota776678b2018-09-11 14:22:31 -04003448 gen_op_movq_env_0(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1)));
bellard664e0f12005-01-08 18:58:29 +00003449 break;
3450 case 0x7f: /* movq ea, mm */
3451 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003452 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003453 gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx));
bellard664e0f12005-01-08 18:58:29 +00003454 } else {
3455 rm = (modrm & 7);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003456 gen_op_movq(s, offsetof(CPUX86State, fpregs[rm].mmx),
bellard664e0f12005-01-08 18:58:29 +00003457 offsetof(CPUX86State,fpregs[reg].mmx));
3458 }
3459 break;
3460 case 0x011: /* movups */
3461 case 0x111: /* movupd */
3462 case 0x029: /* movaps */
3463 case 0x129: /* movapd */
3464 case 0x17f: /* movdqa ea, xmm */
3465 case 0x27f: /* movdqu ea, xmm */
3466 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003467 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003468 gen_sto_env_A0(s, offsetof(CPUX86State, xmm_regs[reg]));
bellard664e0f12005-01-08 18:58:29 +00003469 } else {
3470 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003471 gen_op_movo(s, offsetof(CPUX86State, xmm_regs[rm]),
bellard664e0f12005-01-08 18:58:29 +00003472 offsetof(CPUX86State,xmm_regs[reg]));
3473 }
3474 break;
3475 case 0x211: /* movss ea, xmm */
3476 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003477 gen_lea_modrm(env, s, modrm);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003478 tcg_gen_ld32u_tl(s->T0, cpu_env,
3479 offsetof(CPUX86State, xmm_regs[reg].ZMM_L(0)));
3480 gen_op_st_v(s, MO_32, s->T0, s->A0);
bellard664e0f12005-01-08 18:58:29 +00003481 } else {
3482 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003483 gen_op_movl(s, offsetof(CPUX86State, xmm_regs[rm].ZMM_L(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003484 offsetof(CPUX86State,xmm_regs[reg].ZMM_L(0)));
bellard664e0f12005-01-08 18:58:29 +00003485 }
3486 break;
3487 case 0x311: /* movsd ea, xmm */
3488 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003489 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003490 gen_stq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003491 xmm_regs[reg].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003492 } else {
3493 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003494 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003495 offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003496 }
3497 break;
3498 case 0x013: /* movlps */
3499 case 0x113: /* movlpd */
3500 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003501 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003502 gen_stq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003503 xmm_regs[reg].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003504 } else {
3505 goto illegal_op;
3506 }
3507 break;
3508 case 0x017: /* movhps */
3509 case 0x117: /* movhpd */
3510 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003511 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003512 gen_stq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003513 xmm_regs[reg].ZMM_Q(1)));
bellard664e0f12005-01-08 18:58:29 +00003514 } else {
3515 goto illegal_op;
3516 }
3517 break;
3518 case 0x71: /* shift mm, im */
3519 case 0x72:
3520 case 0x73:
3521 case 0x171: /* shift xmm, im */
3522 case 0x172:
3523 case 0x173:
Andi Kleenc045af22010-06-27 00:06:11 +02003524 if (b1 >= 2) {
Paolo Bonzini7d374352018-12-13 23:37:37 +01003525 goto unknown_op;
Andi Kleenc045af22010-06-27 00:06:11 +02003526 }
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02003527 val = x86_ldub_code(env, s);
bellard664e0f12005-01-08 18:58:29 +00003528 if (is_xmm) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003529 tcg_gen_movi_tl(s->T0, val);
3530 tcg_gen_st32_tl(s->T0, cpu_env,
3531 offsetof(CPUX86State, xmm_t0.ZMM_L(0)));
3532 tcg_gen_movi_tl(s->T0, 0);
3533 tcg_gen_st32_tl(s->T0, cpu_env,
3534 offsetof(CPUX86State, xmm_t0.ZMM_L(1)));
bellard664e0f12005-01-08 18:58:29 +00003535 op1_offset = offsetof(CPUX86State,xmm_t0);
3536 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003537 tcg_gen_movi_tl(s->T0, val);
3538 tcg_gen_st32_tl(s->T0, cpu_env,
3539 offsetof(CPUX86State, mmx_t0.MMX_L(0)));
3540 tcg_gen_movi_tl(s->T0, 0);
3541 tcg_gen_st32_tl(s->T0, cpu_env,
3542 offsetof(CPUX86State, mmx_t0.MMX_L(1)));
bellard664e0f12005-01-08 18:58:29 +00003543 op1_offset = offsetof(CPUX86State,mmx_t0);
3544 }
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003545 sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 +
3546 (((modrm >> 3)) & 7)][b1];
3547 if (!sse_fn_epp) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003548 goto unknown_op;
Blue Swirlc4baa052012-05-13 18:53:07 +00003549 }
bellard664e0f12005-01-08 18:58:29 +00003550 if (is_xmm) {
3551 rm = (modrm & 7) | REX_B(s);
3552 op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
3553 } else {
3554 rm = (modrm & 7);
3555 op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
3556 }
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003557 tcg_gen_addi_ptr(s->ptr0, cpu_env, op2_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04003558 tcg_gen_addi_ptr(s->ptr1, cpu_env, op1_offset);
3559 sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00003560 break;
3561 case 0x050: /* movmskps */
bellard664e0f12005-01-08 18:58:29 +00003562 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003563 tcg_gen_addi_ptr(s->ptr0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003564 offsetof(CPUX86State,xmm_regs[rm]));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003565 gen_helper_movmskps(s->tmp2_i32, cpu_env, s->ptr0);
3566 tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32);
bellard664e0f12005-01-08 18:58:29 +00003567 break;
3568 case 0x150: /* movmskpd */
bellard664e0f12005-01-08 18:58:29 +00003569 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003570 tcg_gen_addi_ptr(s->ptr0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003571 offsetof(CPUX86State,xmm_regs[rm]));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003572 gen_helper_movmskpd(s->tmp2_i32, cpu_env, s->ptr0);
3573 tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32);
bellard664e0f12005-01-08 18:58:29 +00003574 break;
3575 case 0x02a: /* cvtpi2ps */
3576 case 0x12a: /* cvtpi2pd */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003577 gen_helper_enter_mmx(cpu_env);
bellard664e0f12005-01-08 18:58:29 +00003578 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003579 gen_lea_modrm(env, s, modrm);
bellard664e0f12005-01-08 18:58:29 +00003580 op2_offset = offsetof(CPUX86State,mmx_t0);
Richard Henderson323d1872013-10-30 22:04:05 -07003581 gen_ldq_env_A0(s, op2_offset);
bellard664e0f12005-01-08 18:58:29 +00003582 } else {
3583 rm = (modrm & 7);
3584 op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
3585 }
3586 op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003587 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04003588 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
bellard664e0f12005-01-08 18:58:29 +00003589 switch(b >> 8) {
3590 case 0x0:
Emilio G. Cota6387e832018-09-11 14:14:06 -04003591 gen_helper_cvtpi2ps(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00003592 break;
3593 default:
3594 case 0x1:
Emilio G. Cota6387e832018-09-11 14:14:06 -04003595 gen_helper_cvtpi2pd(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00003596 break;
3597 }
3598 break;
3599 case 0x22a: /* cvtsi2ss */
3600 case 0x32a: /* cvtsi2sd */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003601 ot = mo_64_32(s->dflag);
Blue Swirl0af10c82012-09-08 13:26:02 +00003602 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
bellard664e0f12005-01-08 18:58:29 +00003603 op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003604 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Richard Henderson4ba99382013-11-02 09:54:47 -07003605 if (ot == MO_32) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003606 SSEFunc_0_epi sse_fn_epi = sse_op_table3ai[(b >> 8) & 1];
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003607 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
3608 sse_fn_epi(cpu_env, s->ptr0, s->tmp2_i32);
bellard28e10712008-07-07 20:25:41 +00003609 } else {
Stefan Weil11f8cdb2012-06-29 22:38:20 +02003610#ifdef TARGET_X86_64
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003611 SSEFunc_0_epl sse_fn_epl = sse_op_table3aq[(b >> 8) & 1];
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003612 sse_fn_epl(cpu_env, s->ptr0, s->T0);
Stefan Weil11f8cdb2012-06-29 22:38:20 +02003613#else
3614 goto illegal_op;
3615#endif
bellard28e10712008-07-07 20:25:41 +00003616 }
bellard664e0f12005-01-08 18:58:29 +00003617 break;
3618 case 0x02c: /* cvttps2pi */
3619 case 0x12c: /* cvttpd2pi */
3620 case 0x02d: /* cvtps2pi */
3621 case 0x12d: /* cvtpd2pi */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003622 gen_helper_enter_mmx(cpu_env);
bellard664e0f12005-01-08 18:58:29 +00003623 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003624 gen_lea_modrm(env, s, modrm);
bellard664e0f12005-01-08 18:58:29 +00003625 op2_offset = offsetof(CPUX86State,xmm_t0);
Richard Henderson323d1872013-10-30 22:04:05 -07003626 gen_ldo_env_A0(s, op2_offset);
bellard664e0f12005-01-08 18:58:29 +00003627 } else {
3628 rm = (modrm & 7) | REX_B(s);
3629 op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
3630 }
3631 op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003632 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04003633 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
bellard664e0f12005-01-08 18:58:29 +00003634 switch(b) {
3635 case 0x02c:
Emilio G. Cota6387e832018-09-11 14:14:06 -04003636 gen_helper_cvttps2pi(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00003637 break;
3638 case 0x12c:
Emilio G. Cota6387e832018-09-11 14:14:06 -04003639 gen_helper_cvttpd2pi(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00003640 break;
3641 case 0x02d:
Emilio G. Cota6387e832018-09-11 14:14:06 -04003642 gen_helper_cvtps2pi(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00003643 break;
3644 case 0x12d:
Emilio G. Cota6387e832018-09-11 14:14:06 -04003645 gen_helper_cvtpd2pi(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00003646 break;
3647 }
3648 break;
3649 case 0x22c: /* cvttss2si */
3650 case 0x32c: /* cvttsd2si */
3651 case 0x22d: /* cvtss2si */
3652 case 0x32d: /* cvtsd2si */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003653 ot = mo_64_32(s->dflag);
bellard31313212005-03-03 01:14:55 +00003654 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003655 gen_lea_modrm(env, s, modrm);
bellard31313212005-03-03 01:14:55 +00003656 if ((b >> 8) & 1) {
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003657 gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.ZMM_Q(0)));
bellard31313212005-03-03 01:14:55 +00003658 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003659 gen_op_ld_v(s, MO_32, s->T0, s->A0);
3660 tcg_gen_st32_tl(s->T0, cpu_env,
3661 offsetof(CPUX86State, xmm_t0.ZMM_L(0)));
bellard31313212005-03-03 01:14:55 +00003662 }
3663 op2_offset = offsetof(CPUX86State,xmm_t0);
3664 } else {
3665 rm = (modrm & 7) | REX_B(s);
3666 op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
3667 }
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003668 tcg_gen_addi_ptr(s->ptr0, cpu_env, op2_offset);
Richard Henderson4ba99382013-11-02 09:54:47 -07003669 if (ot == MO_32) {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003670 SSEFunc_i_ep sse_fn_i_ep =
Peter Maydellbedc2ac2012-07-05 22:29:00 +01003671 sse_op_table3bi[((b >> 7) & 2) | (b & 1)];
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003672 sse_fn_i_ep(s->tmp2_i32, cpu_env, s->ptr0);
3673 tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
bellard5af45182008-05-12 16:47:36 +00003674 } else {
Stefan Weil11f8cdb2012-06-29 22:38:20 +02003675#ifdef TARGET_X86_64
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003676 SSEFunc_l_ep sse_fn_l_ep =
Peter Maydellbedc2ac2012-07-05 22:29:00 +01003677 sse_op_table3bq[((b >> 7) & 2) | (b & 1)];
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003678 sse_fn_l_ep(s->T0, cpu_env, s->ptr0);
Stefan Weil11f8cdb2012-06-29 22:38:20 +02003679#else
3680 goto illegal_op;
3681#endif
bellard5af45182008-05-12 16:47:36 +00003682 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04003683 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard664e0f12005-01-08 18:58:29 +00003684 break;
3685 case 0xc4: /* pinsrw */
ths5fafdf22007-09-16 21:08:06 +00003686 case 0x1c4:
bellardd1e42c52006-06-14 14:29:34 +00003687 s->rip_offset = 1;
Richard Henderson4ba99382013-11-02 09:54:47 -07003688 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02003689 val = x86_ldub_code(env, s);
bellard664e0f12005-01-08 18:58:29 +00003690 if (b1) {
3691 val &= 7;
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003692 tcg_gen_st16_tl(s->T0, cpu_env,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003693 offsetof(CPUX86State,xmm_regs[reg].ZMM_W(val)));
bellard664e0f12005-01-08 18:58:29 +00003694 } else {
3695 val &= 3;
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003696 tcg_gen_st16_tl(s->T0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003697 offsetof(CPUX86State,fpregs[reg].mmx.MMX_W(val)));
bellard664e0f12005-01-08 18:58:29 +00003698 }
3699 break;
3700 case 0xc5: /* pextrw */
ths5fafdf22007-09-16 21:08:06 +00003701 case 0x1c5:
bellard664e0f12005-01-08 18:58:29 +00003702 if (mod != 3)
3703 goto illegal_op;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003704 ot = mo_64_32(s->dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02003705 val = x86_ldub_code(env, s);
bellard664e0f12005-01-08 18:58:29 +00003706 if (b1) {
3707 val &= 7;
3708 rm = (modrm & 7) | REX_B(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003709 tcg_gen_ld16u_tl(s->T0, cpu_env,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003710 offsetof(CPUX86State,xmm_regs[rm].ZMM_W(val)));
bellard664e0f12005-01-08 18:58:29 +00003711 } else {
3712 val &= 3;
3713 rm = (modrm & 7);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003714 tcg_gen_ld16u_tl(s->T0, cpu_env,
bellard5af45182008-05-12 16:47:36 +00003715 offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val)));
bellard664e0f12005-01-08 18:58:29 +00003716 }
Richard Hendersonbbdb4232021-05-14 10:13:09 -05003717 reg = ((modrm >> 3) & 7) | REX_R(s);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04003718 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard664e0f12005-01-08 18:58:29 +00003719 break;
3720 case 0x1d6: /* movq ea, xmm */
3721 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10003722 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003723 gen_stq_env_A0(s, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003724 xmm_regs[reg].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003725 } else {
3726 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003727 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(0)),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003728 offsetof(CPUX86State,xmm_regs[reg].ZMM_Q(0)));
Emilio G. Cota776678b2018-09-11 14:22:31 -04003729 gen_op_movq_env_0(s,
3730 offsetof(CPUX86State, xmm_regs[rm].ZMM_Q(1)));
bellard664e0f12005-01-08 18:58:29 +00003731 }
3732 break;
3733 case 0x2d6: /* movq2dq */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003734 gen_helper_enter_mmx(cpu_env);
bellard480c1cd2006-06-24 14:03:10 +00003735 rm = (modrm & 7);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003736 gen_op_movq(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(0)),
bellard480c1cd2006-06-24 14:03:10 +00003737 offsetof(CPUX86State,fpregs[rm].mmx));
Emilio G. Cota776678b2018-09-11 14:22:31 -04003738 gen_op_movq_env_0(s, offsetof(CPUX86State, xmm_regs[reg].ZMM_Q(1)));
bellard664e0f12005-01-08 18:58:29 +00003739 break;
3740 case 0x3d6: /* movdq2q */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003741 gen_helper_enter_mmx(cpu_env);
bellard480c1cd2006-06-24 14:03:10 +00003742 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota776678b2018-09-11 14:22:31 -04003743 gen_op_movq(s, offsetof(CPUX86State, fpregs[reg & 7].mmx),
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003744 offsetof(CPUX86State,xmm_regs[rm].ZMM_Q(0)));
bellard664e0f12005-01-08 18:58:29 +00003745 break;
3746 case 0xd7: /* pmovmskb */
3747 case 0x1d7:
3748 if (mod != 3)
3749 goto illegal_op;
3750 if (b1) {
3751 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003752 tcg_gen_addi_ptr(s->ptr0, cpu_env,
3753 offsetof(CPUX86State, xmm_regs[rm]));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003754 gen_helper_pmovmskb_xmm(s->tmp2_i32, cpu_env, s->ptr0);
bellard664e0f12005-01-08 18:58:29 +00003755 } else {
3756 rm = (modrm & 7);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003757 tcg_gen_addi_ptr(s->ptr0, cpu_env,
3758 offsetof(CPUX86State, fpregs[rm].mmx));
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003759 gen_helper_pmovmskb_mmx(s->tmp2_i32, cpu_env, s->ptr0);
bellard664e0f12005-01-08 18:58:29 +00003760 }
Richard Hendersonbbdb4232021-05-14 10:13:09 -05003761 reg = ((modrm >> 3) & 7) | REX_R(s);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003762 tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32);
bellard664e0f12005-01-08 18:58:29 +00003763 break;
Richard Henderson111994e2013-01-10 12:06:59 -08003764
balrog4242b1b2008-09-25 18:01:46 +00003765 case 0x138:
balrog000cacf2008-10-04 11:33:52 +00003766 case 0x038:
balrog4242b1b2008-09-25 18:01:46 +00003767 b = modrm;
Richard Henderson111994e2013-01-10 12:06:59 -08003768 if ((b & 0xf0) == 0xf0) {
3769 goto do_0f_38_fx;
3770 }
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02003771 modrm = x86_ldub_code(env, s);
balrog4242b1b2008-09-25 18:01:46 +00003772 rm = modrm & 7;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05003773 reg = ((modrm >> 3) & 7) | REX_R(s);
balrog4242b1b2008-09-25 18:01:46 +00003774 mod = (modrm >> 6) & 3;
Andi Kleenc045af22010-06-27 00:06:11 +02003775 if (b1 >= 2) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003776 goto unknown_op;
Andi Kleenc045af22010-06-27 00:06:11 +02003777 }
balrog4242b1b2008-09-25 18:01:46 +00003778
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003779 sse_fn_epp = sse_op_table6[b].op[b1];
3780 if (!sse_fn_epp) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003781 goto unknown_op;
Blue Swirlc4baa052012-05-13 18:53:07 +00003782 }
balrog222a3332008-10-04 03:27:44 +00003783 if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask))
3784 goto illegal_op;
balrog4242b1b2008-09-25 18:01:46 +00003785
3786 if (b1) {
3787 op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
3788 if (mod == 3) {
3789 op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]);
3790 } else {
3791 op2_offset = offsetof(CPUX86State,xmm_t0);
Richard Henderson4eeb3932013-11-02 08:55:59 -10003792 gen_lea_modrm(env, s, modrm);
balrog222a3332008-10-04 03:27:44 +00003793 switch (b) {
3794 case 0x20: case 0x30: /* pmovsxbw, pmovzxbw */
3795 case 0x23: case 0x33: /* pmovsxwd, pmovzxwd */
3796 case 0x25: case 0x35: /* pmovsxdq, pmovzxdq */
Richard Henderson323d1872013-10-30 22:04:05 -07003797 gen_ldq_env_A0(s, op2_offset +
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003798 offsetof(ZMMReg, ZMM_Q(0)));
balrog222a3332008-10-04 03:27:44 +00003799 break;
3800 case 0x21: case 0x31: /* pmovsxbd, pmovzxbd */
3801 case 0x24: case 0x34: /* pmovsxwq, pmovzxwq */
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003802 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
Richard Henderson3c5f4112013-11-02 09:30:34 -07003803 s->mem_index, MO_LEUL);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003804 tcg_gen_st_i32(s->tmp2_i32, cpu_env, op2_offset +
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003805 offsetof(ZMMReg, ZMM_L(0)));
balrog222a3332008-10-04 03:27:44 +00003806 break;
3807 case 0x22: case 0x32: /* pmovsxbq, pmovzxbq */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04003808 tcg_gen_qemu_ld_tl(s->tmp0, s->A0,
Richard Henderson3c5f4112013-11-02 09:30:34 -07003809 s->mem_index, MO_LEUW);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04003810 tcg_gen_st16_tl(s->tmp0, cpu_env, op2_offset +
Eduardo Habkost19cbd872015-11-26 17:14:32 -02003811 offsetof(ZMMReg, ZMM_W(0)));
balrog222a3332008-10-04 03:27:44 +00003812 break;
3813 case 0x2a: /* movntqda */
Richard Henderson323d1872013-10-30 22:04:05 -07003814 gen_ldo_env_A0(s, op1_offset);
balrog222a3332008-10-04 03:27:44 +00003815 return;
3816 default:
Richard Henderson323d1872013-10-30 22:04:05 -07003817 gen_ldo_env_A0(s, op2_offset);
balrog222a3332008-10-04 03:27:44 +00003818 }
balrog4242b1b2008-09-25 18:01:46 +00003819 }
3820 } else {
3821 op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
3822 if (mod == 3) {
3823 op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
3824 } else {
3825 op2_offset = offsetof(CPUX86State,mmx_t0);
Richard Henderson4eeb3932013-11-02 08:55:59 -10003826 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07003827 gen_ldq_env_A0(s, op2_offset);
balrog4242b1b2008-09-25 18:01:46 +00003828 }
3829 }
Blue Swirld3eb5ea2012-04-28 21:28:09 +00003830 if (sse_fn_epp == SSE_SPECIAL) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08003831 goto unknown_op;
Blue Swirlc4baa052012-05-13 18:53:07 +00003832 }
balrog222a3332008-10-04 03:27:44 +00003833
Emilio G. Cota2ee26462018-09-11 14:11:35 -04003834 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04003835 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
3836 sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
balrog222a3332008-10-04 03:27:44 +00003837
Richard Henderson3ca51d02013-01-23 12:30:52 -08003838 if (b == 0x17) {
3839 set_cc_op(s, CC_OP_EFLAGS);
3840 }
balrog222a3332008-10-04 03:27:44 +00003841 break;
Richard Henderson111994e2013-01-10 12:06:59 -08003842
3843 case 0x238:
3844 case 0x338:
3845 do_0f_38_fx:
3846 /* Various integer extensions at 0f 38 f[0-f]. */
3847 b = modrm | (b1 << 8);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02003848 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05003849 reg = ((modrm >> 3) & 7) | REX_R(s);
balrog222a3332008-10-04 03:27:44 +00003850
Richard Henderson111994e2013-01-10 12:06:59 -08003851 switch (b) {
3852 case 0x3f0: /* crc32 Gd,Eb */
3853 case 0x3f1: /* crc32 Gd,Ey */
3854 do_crc32:
3855 if (!(s->cpuid_ext_features & CPUID_EXT_SSE42)) {
3856 goto illegal_op;
3857 }
3858 if ((b & 0xff) == 0xf0) {
Richard Henderson4ba99382013-11-02 09:54:47 -07003859 ot = MO_8;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003860 } else if (s->dflag != MO_64) {
Richard Henderson4ba99382013-11-02 09:54:47 -07003861 ot = (s->prefix & PREFIX_DATA ? MO_16 : MO_32);
Richard Henderson111994e2013-01-10 12:06:59 -08003862 } else {
Richard Henderson4ba99382013-11-02 09:54:47 -07003863 ot = MO_64;
Richard Henderson111994e2013-01-10 12:06:59 -08003864 }
3865
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003866 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[reg]);
Richard Henderson111994e2013-01-10 12:06:59 -08003867 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003868 gen_helper_crc32(s->T0, s->tmp2_i32,
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003869 s->T0, tcg_const_i32(8 << ot));
Richard Henderson111994e2013-01-10 12:06:59 -08003870
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003871 ot = mo_64_32(s->dflag);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04003872 gen_op_mov_reg_v(s, ot, reg, s->T0);
Richard Henderson111994e2013-01-10 12:06:59 -08003873 break;
3874
3875 case 0x1f0: /* crc32 or movbe */
3876 case 0x1f1:
3877 /* For these insns, the f3 prefix is supposed to have priority
3878 over the 66 prefix, but that's not what we implement above
3879 setting b1. */
3880 if (s->prefix & PREFIX_REPNZ) {
3881 goto do_crc32;
3882 }
3883 /* FALLTHRU */
3884 case 0x0f0: /* movbe Gy,My */
3885 case 0x0f1: /* movbe My,Gy */
3886 if (!(s->cpuid_ext_features & CPUID_EXT_MOVBE)) {
3887 goto illegal_op;
3888 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003889 if (s->dflag != MO_64) {
Richard Henderson4ba99382013-11-02 09:54:47 -07003890 ot = (s->prefix & PREFIX_DATA ? MO_16 : MO_32);
Richard Henderson111994e2013-01-10 12:06:59 -08003891 } else {
Richard Henderson4ba99382013-11-02 09:54:47 -07003892 ot = MO_64;
Richard Henderson111994e2013-01-10 12:06:59 -08003893 }
3894
Richard Henderson3655a192013-11-02 09:22:04 -10003895 gen_lea_modrm(env, s, modrm);
Richard Henderson111994e2013-01-10 12:06:59 -08003896 if ((b & 1) == 0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003897 tcg_gen_qemu_ld_tl(s->T0, s->A0,
Richard Henderson3655a192013-11-02 09:22:04 -10003898 s->mem_index, ot | MO_BE);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04003899 gen_op_mov_reg_v(s, ot, reg, s->T0);
Richard Henderson111994e2013-01-10 12:06:59 -08003900 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04003901 tcg_gen_qemu_st_tl(cpu_regs[reg], s->A0,
Richard Henderson3655a192013-11-02 09:22:04 -10003902 s->mem_index, ot | MO_BE);
Richard Henderson111994e2013-01-10 12:06:59 -08003903 }
3904 break;
3905
Richard Henderson7073fba2013-01-23 16:17:10 -08003906 case 0x0f2: /* andn Gy, By, Ey */
3907 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)
3908 || !(s->prefix & PREFIX_VEX)
3909 || s->vex_l != 0) {
3910 goto illegal_op;
3911 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003912 ot = mo_64_32(s->dflag);
Richard Henderson7073fba2013-01-23 16:17:10 -08003913 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003914 tcg_gen_andc_tl(s->T0, s->T0, cpu_regs[s->vex_v]);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04003915 gen_op_mov_reg_v(s, ot, reg, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003916 gen_op_update1_cc(s);
Richard Henderson7073fba2013-01-23 16:17:10 -08003917 set_cc_op(s, CC_OP_LOGICB + ot);
3918 break;
3919
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003920 case 0x0f7: /* bextr Gy, Ey, By */
3921 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)
3922 || !(s->prefix & PREFIX_VEX)
3923 || s->vex_l != 0) {
3924 goto illegal_op;
3925 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003926 ot = mo_64_32(s->dflag);
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003927 {
3928 TCGv bound, zero;
3929
3930 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
3931 /* Extract START, and shift the operand.
3932 Shifts larger than operand size get zeros. */
Emilio G. Cota6b672b52018-09-11 14:41:57 -04003933 tcg_gen_ext8u_tl(s->A0, cpu_regs[s->vex_v]);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003934 tcg_gen_shr_tl(s->T0, s->T0, s->A0);
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003935
Richard Henderson4ba99382013-11-02 09:54:47 -07003936 bound = tcg_const_tl(ot == MO_64 ? 63 : 31);
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003937 zero = tcg_const_tl(0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003938 tcg_gen_movcond_tl(TCG_COND_LEU, s->T0, s->A0, bound,
3939 s->T0, zero);
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003940 tcg_temp_free(zero);
3941
3942 /* Extract the LEN into a mask. Lengths larger than
3943 operand size get all ones. */
Emilio G. Cota6b672b52018-09-11 14:41:57 -04003944 tcg_gen_extract_tl(s->A0, cpu_regs[s->vex_v], 8, 8);
3945 tcg_gen_movcond_tl(TCG_COND_LEU, s->A0, s->A0, bound,
3946 s->A0, bound);
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003947 tcg_temp_free(bound);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04003948 tcg_gen_movi_tl(s->T1, 1);
3949 tcg_gen_shl_tl(s->T1, s->T1, s->A0);
3950 tcg_gen_subi_tl(s->T1, s->T1, 1);
3951 tcg_gen_and_tl(s->T0, s->T0, s->T1);
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003952
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04003953 gen_op_mov_reg_v(s, ot, reg, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003954 gen_op_update1_cc(s);
Richard Hendersonc7ab7562013-01-23 16:21:33 -08003955 set_cc_op(s, CC_OP_LOGICB + ot);
3956 }
3957 break;
3958
Richard Henderson02ea1e62013-01-23 17:01:10 -08003959 case 0x0f5: /* bzhi Gy, Ey, By */
3960 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
3961 || !(s->prefix & PREFIX_VEX)
3962 || s->vex_l != 0) {
3963 goto illegal_op;
3964 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003965 ot = mo_64_32(s->dflag);
Richard Henderson02ea1e62013-01-23 17:01:10 -08003966 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04003967 tcg_gen_ext8u_tl(s->T1, cpu_regs[s->vex_v]);
Richard Henderson02ea1e62013-01-23 17:01:10 -08003968 {
Richard Henderson4ba99382013-11-02 09:54:47 -07003969 TCGv bound = tcg_const_tl(ot == MO_64 ? 63 : 31);
Richard Henderson02ea1e62013-01-23 17:01:10 -08003970 /* Note that since we're using BMILG (in order to get O
3971 cleared) we need to store the inverse into C. */
3972 tcg_gen_setcond_tl(TCG_COND_LT, cpu_cc_src,
Emilio G. Cotab48597b2018-09-11 14:50:46 -04003973 s->T1, bound);
3974 tcg_gen_movcond_tl(TCG_COND_GT, s->T1, s->T1,
3975 bound, bound, s->T1);
Richard Henderson02ea1e62013-01-23 17:01:10 -08003976 tcg_temp_free(bound);
3977 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04003978 tcg_gen_movi_tl(s->A0, -1);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04003979 tcg_gen_shl_tl(s->A0, s->A0, s->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003980 tcg_gen_andc_tl(s->T0, s->T0, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04003981 gen_op_mov_reg_v(s, ot, reg, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04003982 gen_op_update1_cc(s);
Richard Henderson02ea1e62013-01-23 17:01:10 -08003983 set_cc_op(s, CC_OP_BMILGB + ot);
3984 break;
3985
Richard Henderson5f1f4b12013-01-23 18:06:18 -08003986 case 0x3f6: /* mulx By, Gy, rdx, Ey */
3987 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
3988 || !(s->prefix & PREFIX_VEX)
3989 || s->vex_l != 0) {
3990 goto illegal_op;
3991 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10003992 ot = mo_64_32(s->dflag);
Richard Henderson5f1f4b12013-01-23 18:06:18 -08003993 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
3994 switch (ot) {
Richard Henderson5f1f4b12013-01-23 18:06:18 -08003995 default:
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04003996 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
Emilio G. Cota4f824462018-09-11 14:17:56 -04003997 tcg_gen_trunc_tl_i32(s->tmp3_i32, cpu_regs[R_EDX]);
3998 tcg_gen_mulu2_i32(s->tmp2_i32, s->tmp3_i32,
3999 s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004000 tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], s->tmp2_i32);
Emilio G. Cota4f824462018-09-11 14:17:56 -04004001 tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp3_i32);
Richard Henderson5f1f4b12013-01-23 18:06:18 -08004002 break;
4003#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07004004 case MO_64:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004005 tcg_gen_mulu2_i64(s->T0, s->T1,
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004006 s->T0, cpu_regs[R_EDX]);
4007 tcg_gen_mov_i64(cpu_regs[s->vex_v], s->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004008 tcg_gen_mov_i64(cpu_regs[reg], s->T1);
Richard Henderson5f1f4b12013-01-23 18:06:18 -08004009 break;
4010#endif
4011 }
4012 break;
4013
Richard Henderson0592f742013-01-23 18:09:43 -08004014 case 0x3f5: /* pdep Gy, By, Ey */
4015 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
4016 || !(s->prefix & PREFIX_VEX)
4017 || s->vex_l != 0) {
4018 goto illegal_op;
4019 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004020 ot = mo_64_32(s->dflag);
Richard Henderson0592f742013-01-23 18:09:43 -08004021 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Paolo Bonzini75b208c2020-11-23 07:17:47 -05004022 /* Note that by zero-extending the source operand, we
Richard Henderson0592f742013-01-23 18:09:43 -08004023 automatically handle zero-extending the result. */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004024 if (ot == MO_64) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004025 tcg_gen_mov_tl(s->T1, cpu_regs[s->vex_v]);
Richard Henderson0592f742013-01-23 18:09:43 -08004026 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004027 tcg_gen_ext32u_tl(s->T1, cpu_regs[s->vex_v]);
Richard Henderson0592f742013-01-23 18:09:43 -08004028 }
Paolo Bonzini75b208c2020-11-23 07:17:47 -05004029 gen_helper_pdep(cpu_regs[reg], s->T1, s->T0);
Richard Henderson0592f742013-01-23 18:09:43 -08004030 break;
4031
4032 case 0x2f5: /* pext Gy, By, Ey */
4033 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
4034 || !(s->prefix & PREFIX_VEX)
4035 || s->vex_l != 0) {
4036 goto illegal_op;
4037 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004038 ot = mo_64_32(s->dflag);
Richard Henderson0592f742013-01-23 18:09:43 -08004039 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Paolo Bonzini75b208c2020-11-23 07:17:47 -05004040 /* Note that by zero-extending the source operand, we
Richard Henderson0592f742013-01-23 18:09:43 -08004041 automatically handle zero-extending the result. */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004042 if (ot == MO_64) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004043 tcg_gen_mov_tl(s->T1, cpu_regs[s->vex_v]);
Richard Henderson0592f742013-01-23 18:09:43 -08004044 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004045 tcg_gen_ext32u_tl(s->T1, cpu_regs[s->vex_v]);
Richard Henderson0592f742013-01-23 18:09:43 -08004046 }
Paolo Bonzini75b208c2020-11-23 07:17:47 -05004047 gen_helper_pext(cpu_regs[reg], s->T1, s->T0);
Richard Henderson0592f742013-01-23 18:09:43 -08004048 break;
4049
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004050 case 0x1f6: /* adcx Gy, Ey */
4051 case 0x2f6: /* adox Gy, Ey */
4052 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_ADX)) {
4053 goto illegal_op;
4054 } else {
Richard Henderson76f13132013-02-19 23:52:00 -08004055 TCGv carry_in, carry_out, zero;
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004056 int end_op;
4057
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004058 ot = mo_64_32(s->dflag);
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004059 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
4060
4061 /* Re-use the carry-out from a previous round. */
Richard Hendersonf7647182017-11-02 12:47:37 +01004062 carry_in = NULL;
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004063 carry_out = (b == 0x1f6 ? cpu_cc_dst : cpu_cc_src2);
4064 switch (s->cc_op) {
4065 case CC_OP_ADCX:
4066 if (b == 0x1f6) {
4067 carry_in = cpu_cc_dst;
4068 end_op = CC_OP_ADCX;
4069 } else {
4070 end_op = CC_OP_ADCOX;
4071 }
4072 break;
4073 case CC_OP_ADOX:
4074 if (b == 0x1f6) {
4075 end_op = CC_OP_ADCOX;
4076 } else {
4077 carry_in = cpu_cc_src2;
4078 end_op = CC_OP_ADOX;
4079 }
4080 break;
4081 case CC_OP_ADCOX:
4082 end_op = CC_OP_ADCOX;
4083 carry_in = carry_out;
4084 break;
4085 default:
Richard Hendersonc53de1a2013-03-19 09:40:53 -07004086 end_op = (b == 0x1f6 ? CC_OP_ADCX : CC_OP_ADOX);
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004087 break;
4088 }
4089 /* If we can't reuse carry-out, get it out of EFLAGS. */
Richard Hendersonf7647182017-11-02 12:47:37 +01004090 if (!carry_in) {
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004091 if (s->cc_op != CC_OP_ADCX && s->cc_op != CC_OP_ADOX) {
4092 gen_compute_eflags(s);
4093 }
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04004094 carry_in = s->tmp0;
Richard Henderson04fc2f12016-10-15 11:54:17 -05004095 tcg_gen_extract_tl(carry_in, cpu_cc_src,
4096 ctz32(b == 0x1f6 ? CC_C : CC_O), 1);
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004097 }
4098
4099 switch (ot) {
4100#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07004101 case MO_32:
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004102 /* If we know TL is 64-bit, and we want a 32-bit
4103 result, just do everything in 64-bit arithmetic. */
4104 tcg_gen_ext32u_i64(cpu_regs[reg], cpu_regs[reg]);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004105 tcg_gen_ext32u_i64(s->T0, s->T0);
4106 tcg_gen_add_i64(s->T0, s->T0, cpu_regs[reg]);
4107 tcg_gen_add_i64(s->T0, s->T0, carry_in);
4108 tcg_gen_ext32u_i64(cpu_regs[reg], s->T0);
4109 tcg_gen_shri_i64(carry_out, s->T0, 32);
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004110 break;
4111#endif
4112 default:
4113 /* Otherwise compute the carry-out in two steps. */
Richard Henderson76f13132013-02-19 23:52:00 -08004114 zero = tcg_const_tl(0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004115 tcg_gen_add2_tl(s->T0, carry_out,
4116 s->T0, zero,
Richard Henderson76f13132013-02-19 23:52:00 -08004117 carry_in, zero);
4118 tcg_gen_add2_tl(cpu_regs[reg], carry_out,
4119 cpu_regs[reg], carry_out,
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004120 s->T0, zero);
Richard Henderson76f13132013-02-19 23:52:00 -08004121 tcg_temp_free(zero);
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004122 break;
4123 }
Richard Hendersoncd7f97c2013-01-23 18:17:33 -08004124 set_cc_op(s, end_op);
4125 }
4126 break;
4127
Richard Henderson4a554892013-01-23 18:12:13 -08004128 case 0x1f7: /* shlx Gy, Ey, By */
4129 case 0x2f7: /* sarx Gy, Ey, By */
4130 case 0x3f7: /* shrx Gy, Ey, By */
4131 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
4132 || !(s->prefix & PREFIX_VEX)
4133 || s->vex_l != 0) {
4134 goto illegal_op;
4135 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004136 ot = mo_64_32(s->dflag);
Richard Henderson4a554892013-01-23 18:12:13 -08004137 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Richard Henderson4ba99382013-11-02 09:54:47 -07004138 if (ot == MO_64) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004139 tcg_gen_andi_tl(s->T1, cpu_regs[s->vex_v], 63);
Richard Henderson4a554892013-01-23 18:12:13 -08004140 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004141 tcg_gen_andi_tl(s->T1, cpu_regs[s->vex_v], 31);
Richard Henderson4a554892013-01-23 18:12:13 -08004142 }
4143 if (b == 0x1f7) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004144 tcg_gen_shl_tl(s->T0, s->T0, s->T1);
Richard Henderson4a554892013-01-23 18:12:13 -08004145 } else if (b == 0x2f7) {
Richard Henderson4ba99382013-11-02 09:54:47 -07004146 if (ot != MO_64) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004147 tcg_gen_ext32s_tl(s->T0, s->T0);
Richard Henderson4a554892013-01-23 18:12:13 -08004148 }
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004149 tcg_gen_sar_tl(s->T0, s->T0, s->T1);
Richard Henderson4a554892013-01-23 18:12:13 -08004150 } else {
Richard Henderson4ba99382013-11-02 09:54:47 -07004151 if (ot != MO_64) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004152 tcg_gen_ext32u_tl(s->T0, s->T0);
Richard Henderson4a554892013-01-23 18:12:13 -08004153 }
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004154 tcg_gen_shr_tl(s->T0, s->T0, s->T1);
Richard Henderson4a554892013-01-23 18:12:13 -08004155 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004156 gen_op_mov_reg_v(s, ot, reg, s->T0);
Richard Henderson4a554892013-01-23 18:12:13 -08004157 break;
4158
Richard Hendersonbc4b43d2013-01-23 16:44:37 -08004159 case 0x0f3:
4160 case 0x1f3:
4161 case 0x2f3:
4162 case 0x3f3: /* Group 17 */
4163 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)
4164 || !(s->prefix & PREFIX_VEX)
4165 || s->vex_l != 0) {
4166 goto illegal_op;
4167 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004168 ot = mo_64_32(s->dflag);
Richard Hendersonbc4b43d2013-01-23 16:44:37 -08004169 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
4170
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004171 tcg_gen_mov_tl(cpu_cc_src, s->T0);
Richard Hendersonbc4b43d2013-01-23 16:44:37 -08004172 switch (reg & 7) {
4173 case 1: /* blsr By,Ey */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004174 tcg_gen_subi_tl(s->T1, s->T0, 1);
4175 tcg_gen_and_tl(s->T0, s->T0, s->T1);
Richard Henderson13672382017-07-12 09:29:02 -10004176 break;
4177 case 2: /* blsmsk By,Ey */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004178 tcg_gen_subi_tl(s->T1, s->T0, 1);
4179 tcg_gen_xor_tl(s->T0, s->T0, s->T1);
Richard Henderson13672382017-07-12 09:29:02 -10004180 break;
4181 case 3: /* blsi By, Ey */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004182 tcg_gen_neg_tl(s->T1, s->T0);
4183 tcg_gen_and_tl(s->T0, s->T0, s->T1);
Richard Hendersonbc4b43d2013-01-23 16:44:37 -08004184 break;
Richard Hendersonbc4b43d2013-01-23 16:44:37 -08004185 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004186 goto unknown_op;
Richard Hendersonbc4b43d2013-01-23 16:44:37 -08004187 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004188 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004189 gen_op_mov_reg_v(s, ot, s->vex_v, s->T0);
Richard Henderson13672382017-07-12 09:29:02 -10004190 set_cc_op(s, CC_OP_BMILGB + ot);
Richard Hendersonbc4b43d2013-01-23 16:44:37 -08004191 break;
4192
Richard Henderson111994e2013-01-10 12:06:59 -08004193 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004194 goto unknown_op;
Richard Henderson111994e2013-01-10 12:06:59 -08004195 }
balrog4242b1b2008-09-25 18:01:46 +00004196 break;
Richard Henderson111994e2013-01-10 12:06:59 -08004197
balrog4242b1b2008-09-25 18:01:46 +00004198 case 0x03a:
4199 case 0x13a:
balrog4242b1b2008-09-25 18:01:46 +00004200 b = modrm;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004201 modrm = x86_ldub_code(env, s);
balrog4242b1b2008-09-25 18:01:46 +00004202 rm = modrm & 7;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004203 reg = ((modrm >> 3) & 7) | REX_R(s);
balrog4242b1b2008-09-25 18:01:46 +00004204 mod = (modrm >> 6) & 3;
Andi Kleenc045af22010-06-27 00:06:11 +02004205 if (b1 >= 2) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004206 goto unknown_op;
Andi Kleenc045af22010-06-27 00:06:11 +02004207 }
balrog4242b1b2008-09-25 18:01:46 +00004208
Blue Swirld3eb5ea2012-04-28 21:28:09 +00004209 sse_fn_eppi = sse_op_table7[b].op[b1];
4210 if (!sse_fn_eppi) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004211 goto unknown_op;
Blue Swirlc4baa052012-05-13 18:53:07 +00004212 }
balrog222a3332008-10-04 03:27:44 +00004213 if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask))
4214 goto illegal_op;
4215
Joseph Myersc6a82422017-08-08 23:51:29 +00004216 s->rip_offset = 1;
4217
Blue Swirld3eb5ea2012-04-28 21:28:09 +00004218 if (sse_fn_eppi == SSE_SPECIAL) {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004219 ot = mo_64_32(s->dflag);
balrog222a3332008-10-04 03:27:44 +00004220 rm = (modrm & 7) | REX_B(s);
4221 if (mod != 3)
Richard Henderson4eeb3932013-11-02 08:55:59 -10004222 gen_lea_modrm(env, s, modrm);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004223 reg = ((modrm >> 3) & 7) | REX_R(s);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004224 val = x86_ldub_code(env, s);
balrog222a3332008-10-04 03:27:44 +00004225 switch (b) {
4226 case 0x14: /* pextrb */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004227 tcg_gen_ld8u_tl(s->T0, cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004228 xmm_regs[reg].ZMM_B(val & 15)));
Richard Henderson3523e4b2013-11-02 09:49:20 -07004229 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004230 gen_op_mov_reg_v(s, ot, rm, s->T0);
Richard Henderson3523e4b2013-11-02 09:49:20 -07004231 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004232 tcg_gen_qemu_st_tl(s->T0, s->A0,
Richard Henderson3523e4b2013-11-02 09:49:20 -07004233 s->mem_index, MO_UB);
4234 }
balrog222a3332008-10-04 03:27:44 +00004235 break;
4236 case 0x15: /* pextrw */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004237 tcg_gen_ld16u_tl(s->T0, cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004238 xmm_regs[reg].ZMM_W(val & 7)));
Richard Henderson3523e4b2013-11-02 09:49:20 -07004239 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004240 gen_op_mov_reg_v(s, ot, rm, s->T0);
Richard Henderson3523e4b2013-11-02 09:49:20 -07004241 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004242 tcg_gen_qemu_st_tl(s->T0, s->A0,
Richard Henderson3523e4b2013-11-02 09:49:20 -07004243 s->mem_index, MO_LEUW);
4244 }
balrog222a3332008-10-04 03:27:44 +00004245 break;
4246 case 0x16:
Richard Henderson4ba99382013-11-02 09:54:47 -07004247 if (ot == MO_32) { /* pextrd */
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004248 tcg_gen_ld_i32(s->tmp2_i32, cpu_env,
balrog222a3332008-10-04 03:27:44 +00004249 offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004250 xmm_regs[reg].ZMM_L(val & 3)));
Richard Henderson3523e4b2013-11-02 09:49:20 -07004251 if (mod == 3) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004252 tcg_gen_extu_i32_tl(cpu_regs[rm], s->tmp2_i32);
Richard Henderson3523e4b2013-11-02 09:49:20 -07004253 } else {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004254 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
Richard Hendersond5601ad2013-11-05 11:14:33 +10004255 s->mem_index, MO_LEUL);
Richard Henderson3523e4b2013-11-02 09:49:20 -07004256 }
balrog222a3332008-10-04 03:27:44 +00004257 } else { /* pextrq */
pbrooka7812ae2008-11-17 14:43:54 +00004258#ifdef TARGET_X86_64
Emilio G. Cota776678b2018-09-11 14:22:31 -04004259 tcg_gen_ld_i64(s->tmp1_i64, cpu_env,
balrog222a3332008-10-04 03:27:44 +00004260 offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004261 xmm_regs[reg].ZMM_Q(val & 1)));
Richard Henderson3523e4b2013-11-02 09:49:20 -07004262 if (mod == 3) {
Emilio G. Cota776678b2018-09-11 14:22:31 -04004263 tcg_gen_mov_i64(cpu_regs[rm], s->tmp1_i64);
Richard Henderson3523e4b2013-11-02 09:49:20 -07004264 } else {
Emilio G. Cota776678b2018-09-11 14:22:31 -04004265 tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
Richard Henderson3523e4b2013-11-02 09:49:20 -07004266 s->mem_index, MO_LEQ);
4267 }
pbrooka7812ae2008-11-17 14:43:54 +00004268#else
4269 goto illegal_op;
4270#endif
balrog222a3332008-10-04 03:27:44 +00004271 }
4272 break;
4273 case 0x17: /* extractps */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004274 tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004275 xmm_regs[reg].ZMM_L(val & 3)));
Richard Henderson3523e4b2013-11-02 09:49:20 -07004276 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004277 gen_op_mov_reg_v(s, ot, rm, s->T0);
Richard Henderson3523e4b2013-11-02 09:49:20 -07004278 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004279 tcg_gen_qemu_st_tl(s->T0, s->A0,
Richard Henderson3523e4b2013-11-02 09:49:20 -07004280 s->mem_index, MO_LEUL);
4281 }
balrog222a3332008-10-04 03:27:44 +00004282 break;
4283 case 0x20: /* pinsrb */
Richard Henderson3c5f4112013-11-02 09:30:34 -07004284 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004285 gen_op_mov_v_reg(s, MO_32, s->T0, rm);
Richard Henderson3c5f4112013-11-02 09:30:34 -07004286 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004287 tcg_gen_qemu_ld_tl(s->T0, s->A0,
Richard Henderson3c5f4112013-11-02 09:30:34 -07004288 s->mem_index, MO_UB);
4289 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004290 tcg_gen_st8_tl(s->T0, cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004291 xmm_regs[reg].ZMM_B(val & 15)));
balrog222a3332008-10-04 03:27:44 +00004292 break;
4293 case 0x21: /* insertps */
pbrooka7812ae2008-11-17 14:43:54 +00004294 if (mod == 3) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004295 tcg_gen_ld_i32(s->tmp2_i32, cpu_env,
balrog222a3332008-10-04 03:27:44 +00004296 offsetof(CPUX86State,xmm_regs[rm]
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004297 .ZMM_L((val >> 6) & 3)));
pbrooka7812ae2008-11-17 14:43:54 +00004298 } else {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004299 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
Richard Henderson3c5f4112013-11-02 09:30:34 -07004300 s->mem_index, MO_LEUL);
pbrooka7812ae2008-11-17 14:43:54 +00004301 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004302 tcg_gen_st_i32(s->tmp2_i32, cpu_env,
balrog222a3332008-10-04 03:27:44 +00004303 offsetof(CPUX86State,xmm_regs[reg]
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004304 .ZMM_L((val >> 4) & 3)));
balrog222a3332008-10-04 03:27:44 +00004305 if ((val >> 0) & 1)
4306 tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
4307 cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004308 xmm_regs[reg].ZMM_L(0)));
balrog222a3332008-10-04 03:27:44 +00004309 if ((val >> 1) & 1)
4310 tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
4311 cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004312 xmm_regs[reg].ZMM_L(1)));
balrog222a3332008-10-04 03:27:44 +00004313 if ((val >> 2) & 1)
4314 tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
4315 cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004316 xmm_regs[reg].ZMM_L(2)));
balrog222a3332008-10-04 03:27:44 +00004317 if ((val >> 3) & 1)
4318 tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
4319 cpu_env, offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004320 xmm_regs[reg].ZMM_L(3)));
balrog222a3332008-10-04 03:27:44 +00004321 break;
4322 case 0x22:
Richard Henderson4ba99382013-11-02 09:54:47 -07004323 if (ot == MO_32) { /* pinsrd */
Richard Henderson3c5f4112013-11-02 09:30:34 -07004324 if (mod == 3) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004325 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[rm]);
Richard Henderson3c5f4112013-11-02 09:30:34 -07004326 } else {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004327 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
Richard Henderson80b02012013-11-02 09:54:48 -10004328 s->mem_index, MO_LEUL);
Richard Henderson3c5f4112013-11-02 09:30:34 -07004329 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004330 tcg_gen_st_i32(s->tmp2_i32, cpu_env,
balrog222a3332008-10-04 03:27:44 +00004331 offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004332 xmm_regs[reg].ZMM_L(val & 3)));
balrog222a3332008-10-04 03:27:44 +00004333 } else { /* pinsrq */
pbrooka7812ae2008-11-17 14:43:54 +00004334#ifdef TARGET_X86_64
Richard Henderson3c5f4112013-11-02 09:30:34 -07004335 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004336 gen_op_mov_v_reg(s, ot, s->tmp1_i64, rm);
Richard Henderson3c5f4112013-11-02 09:30:34 -07004337 } else {
Emilio G. Cota776678b2018-09-11 14:22:31 -04004338 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
Richard Henderson3c5f4112013-11-02 09:30:34 -07004339 s->mem_index, MO_LEQ);
4340 }
Emilio G. Cota776678b2018-09-11 14:22:31 -04004341 tcg_gen_st_i64(s->tmp1_i64, cpu_env,
balrog222a3332008-10-04 03:27:44 +00004342 offsetof(CPUX86State,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004343 xmm_regs[reg].ZMM_Q(val & 1)));
pbrooka7812ae2008-11-17 14:43:54 +00004344#else
4345 goto illegal_op;
4346#endif
balrog222a3332008-10-04 03:27:44 +00004347 }
4348 break;
4349 }
4350 return;
4351 }
balrog4242b1b2008-09-25 18:01:46 +00004352
4353 if (b1) {
4354 op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
4355 if (mod == 3) {
4356 op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]);
4357 } else {
4358 op2_offset = offsetof(CPUX86State,xmm_t0);
Richard Henderson4eeb3932013-11-02 08:55:59 -10004359 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07004360 gen_ldo_env_A0(s, op2_offset);
balrog4242b1b2008-09-25 18:01:46 +00004361 }
4362 } else {
4363 op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
4364 if (mod == 3) {
4365 op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
4366 } else {
4367 op2_offset = offsetof(CPUX86State,mmx_t0);
Richard Henderson4eeb3932013-11-02 08:55:59 -10004368 gen_lea_modrm(env, s, modrm);
Richard Henderson323d1872013-10-30 22:04:05 -07004369 gen_ldq_env_A0(s, op2_offset);
balrog4242b1b2008-09-25 18:01:46 +00004370 }
4371 }
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004372 val = x86_ldub_code(env, s);
balrog4242b1b2008-09-25 18:01:46 +00004373
balrog222a3332008-10-04 03:27:44 +00004374 if ((b & 0xfc) == 0x60) { /* pcmpXstrX */
Richard Henderson3ca51d02013-01-23 12:30:52 -08004375 set_cc_op(s, CC_OP_EFLAGS);
balrog222a3332008-10-04 03:27:44 +00004376
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004377 if (s->dflag == MO_64) {
balrog222a3332008-10-04 03:27:44 +00004378 /* The helper must use entire 64-bit gp registers */
4379 val |= 1 << 8;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004380 }
balrog222a3332008-10-04 03:27:44 +00004381 }
4382
Emilio G. Cota2ee26462018-09-11 14:11:35 -04004383 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04004384 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
4385 sse_fn_eppi(cpu_env, s->ptr0, s->ptr1, tcg_const_i32(val));
balrog4242b1b2008-09-25 18:01:46 +00004386 break;
Richard Hendersone2c3c2c2013-01-16 14:55:09 -08004387
4388 case 0x33a:
4389 /* Various integer extensions at 0f 3a f[0-f]. */
4390 b = modrm | (b1 << 8);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004391 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004392 reg = ((modrm >> 3) & 7) | REX_R(s);
Richard Hendersone2c3c2c2013-01-16 14:55:09 -08004393
4394 switch (b) {
4395 case 0x3f0: /* rorx Gy,Ey, Ib */
4396 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI2)
4397 || !(s->prefix & PREFIX_VEX)
4398 || s->vex_l != 0) {
4399 goto illegal_op;
4400 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004401 ot = mo_64_32(s->dflag);
Richard Hendersone2c3c2c2013-01-16 14:55:09 -08004402 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004403 b = x86_ldub_code(env, s);
Richard Henderson4ba99382013-11-02 09:54:47 -07004404 if (ot == MO_64) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004405 tcg_gen_rotri_tl(s->T0, s->T0, b & 63);
Richard Hendersone2c3c2c2013-01-16 14:55:09 -08004406 } else {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004407 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
4408 tcg_gen_rotri_i32(s->tmp2_i32, s->tmp2_i32, b & 31);
4409 tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
Richard Hendersone2c3c2c2013-01-16 14:55:09 -08004410 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004411 gen_op_mov_reg_v(s, ot, reg, s->T0);
Richard Hendersone2c3c2c2013-01-16 14:55:09 -08004412 break;
4413
4414 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004415 goto unknown_op;
Richard Hendersone2c3c2c2013-01-16 14:55:09 -08004416 }
4417 break;
4418
bellard664e0f12005-01-08 18:58:29 +00004419 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004420 unknown_op:
4421 gen_unknown_opcode(env, s);
4422 return;
bellard664e0f12005-01-08 18:58:29 +00004423 }
4424 } else {
4425 /* generic MMX or SSE operation */
bellardd1e42c52006-06-14 14:29:34 +00004426 switch(b) {
bellardd1e42c52006-06-14 14:29:34 +00004427 case 0x70: /* pshufx insn */
4428 case 0xc6: /* pshufx insn */
4429 case 0xc2: /* compare insns */
4430 s->rip_offset = 1;
4431 break;
4432 default:
4433 break;
bellard664e0f12005-01-08 18:58:29 +00004434 }
4435 if (is_xmm) {
4436 op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
4437 if (mod != 3) {
Richard Hendersoncb48da72014-02-24 15:53:40 -08004438 int sz = 4;
4439
Richard Henderson4eeb3932013-11-02 08:55:59 -10004440 gen_lea_modrm(env, s, modrm);
bellard664e0f12005-01-08 18:58:29 +00004441 op2_offset = offsetof(CPUX86State,xmm_t0);
Richard Hendersoncb48da72014-02-24 15:53:40 -08004442
4443 switch (b) {
4444 case 0x50 ... 0x5a:
4445 case 0x5c ... 0x5f:
4446 case 0xc2:
4447 /* Most sse scalar operations. */
bellard664e0f12005-01-08 18:58:29 +00004448 if (b1 == 2) {
Richard Hendersoncb48da72014-02-24 15:53:40 -08004449 sz = 2;
4450 } else if (b1 == 3) {
4451 sz = 3;
bellard664e0f12005-01-08 18:58:29 +00004452 }
Richard Hendersoncb48da72014-02-24 15:53:40 -08004453 break;
4454
4455 case 0x2e: /* ucomis[sd] */
4456 case 0x2f: /* comis[sd] */
4457 if (b1 == 0) {
4458 sz = 2;
4459 } else {
4460 sz = 3;
4461 }
4462 break;
4463 }
4464
4465 switch (sz) {
4466 case 2:
4467 /* 32 bit access */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004468 gen_op_ld_v(s, MO_32, s->T0, s->A0);
4469 tcg_gen_st32_tl(s->T0, cpu_env,
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004470 offsetof(CPUX86State,xmm_t0.ZMM_L(0)));
Richard Hendersoncb48da72014-02-24 15:53:40 -08004471 break;
4472 case 3:
4473 /* 64 bit access */
Eduardo Habkost19cbd872015-11-26 17:14:32 -02004474 gen_ldq_env_A0(s, offsetof(CPUX86State, xmm_t0.ZMM_D(0)));
Richard Hendersoncb48da72014-02-24 15:53:40 -08004475 break;
4476 default:
4477 /* 128 bit access */
Richard Henderson323d1872013-10-30 22:04:05 -07004478 gen_ldo_env_A0(s, op2_offset);
Richard Hendersoncb48da72014-02-24 15:53:40 -08004479 break;
bellard664e0f12005-01-08 18:58:29 +00004480 }
4481 } else {
4482 rm = (modrm & 7) | REX_B(s);
4483 op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
4484 }
4485 } else {
4486 op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
4487 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10004488 gen_lea_modrm(env, s, modrm);
bellard664e0f12005-01-08 18:58:29 +00004489 op2_offset = offsetof(CPUX86State,mmx_t0);
Richard Henderson323d1872013-10-30 22:04:05 -07004490 gen_ldq_env_A0(s, op2_offset);
bellard664e0f12005-01-08 18:58:29 +00004491 } else {
4492 rm = (modrm & 7);
4493 op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
4494 }
4495 }
4496 switch(b) {
aurel32a35f3ec2008-04-08 19:51:29 +00004497 case 0x0f: /* 3DNow! data insns */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004498 val = x86_ldub_code(env, s);
Blue Swirld3eb5ea2012-04-28 21:28:09 +00004499 sse_fn_epp = sse_op_table5[val];
4500 if (!sse_fn_epp) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004501 goto unknown_op;
4502 }
4503 if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
aurel32a35f3ec2008-04-08 19:51:29 +00004504 goto illegal_op;
Blue Swirlc4baa052012-05-13 18:53:07 +00004505 }
Emilio G. Cota2ee26462018-09-11 14:11:35 -04004506 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04004507 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
4508 sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
aurel32a35f3ec2008-04-08 19:51:29 +00004509 break;
bellard664e0f12005-01-08 18:58:29 +00004510 case 0x70: /* pshufx insn */
4511 case 0xc6: /* pshufx insn */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004512 val = x86_ldub_code(env, s);
Emilio G. Cota2ee26462018-09-11 14:11:35 -04004513 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04004514 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
Blue Swirlc4baa052012-05-13 18:53:07 +00004515 /* XXX: introduce a new table? */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00004516 sse_fn_ppi = (SSEFunc_0_ppi)sse_fn_epp;
Emilio G. Cota6387e832018-09-11 14:14:06 -04004517 sse_fn_ppi(s->ptr0, s->ptr1, tcg_const_i32(val));
bellard664e0f12005-01-08 18:58:29 +00004518 break;
4519 case 0xc2:
4520 /* compare insns */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004521 val = x86_ldub_code(env, s);
bellard664e0f12005-01-08 18:58:29 +00004522 if (val >= 8)
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004523 goto unknown_op;
Blue Swirld3eb5ea2012-04-28 21:28:09 +00004524 sse_fn_epp = sse_op_table4[val][b1];
Blue Swirlc4baa052012-05-13 18:53:07 +00004525
Emilio G. Cota2ee26462018-09-11 14:11:35 -04004526 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04004527 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
4528 sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00004529 break;
bellardb8b6a502008-05-15 16:46:30 +00004530 case 0xf7:
4531 /* maskmov : we must prepare A0 */
4532 if (mod != 3)
4533 goto illegal_op;
Emilio G. Cota6b672b52018-09-11 14:41:57 -04004534 tcg_gen_mov_tl(s->A0, cpu_regs[R_EDI]);
4535 gen_extu(s->aflag, s->A0);
bellardb8b6a502008-05-15 16:46:30 +00004536 gen_add_A0_ds_seg(s);
4537
Emilio G. Cota2ee26462018-09-11 14:11:35 -04004538 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04004539 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
Blue Swirlc4baa052012-05-13 18:53:07 +00004540 /* XXX: introduce a new table? */
Blue Swirld3eb5ea2012-04-28 21:28:09 +00004541 sse_fn_eppt = (SSEFunc_0_eppt)sse_fn_epp;
Emilio G. Cota6387e832018-09-11 14:14:06 -04004542 sse_fn_eppt(cpu_env, s->ptr0, s->ptr1, s->A0);
bellardb8b6a502008-05-15 16:46:30 +00004543 break;
bellard664e0f12005-01-08 18:58:29 +00004544 default:
Emilio G. Cota2ee26462018-09-11 14:11:35 -04004545 tcg_gen_addi_ptr(s->ptr0, cpu_env, op1_offset);
Emilio G. Cota6387e832018-09-11 14:14:06 -04004546 tcg_gen_addi_ptr(s->ptr1, cpu_env, op2_offset);
4547 sse_fn_epp(cpu_env, s->ptr0, s->ptr1);
bellard664e0f12005-01-08 18:58:29 +00004548 break;
4549 }
4550 if (b == 0x2e || b == 0x2f) {
Richard Henderson3ca51d02013-01-23 12:30:52 -08004551 set_cc_op(s, CC_OP_EFLAGS);
bellard664e0f12005-01-08 18:58:29 +00004552 }
4553 }
4554}
4555
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03004556/* convert one instruction. s->base.is_jmp is set if the translation must
bellard2c0262a2003-09-30 20:34:21 +00004557 be stopped. Return the next pc value */
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03004558static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
bellard2c0262a2003-09-30 20:34:21 +00004559{
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03004560 CPUX86State *env = cpu->env_ptr;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004561 int b, prefixes;
Richard Hendersond67dc9e2013-11-06 07:25:05 +10004562 int shift;
Tony Nguyen14776ab2019-08-24 04:10:58 +10004563 MemOp ot, aflag, dflag;
Richard Henderson4eeb3932013-11-02 08:55:59 -10004564 int modrm, reg, rm, mod, op, opreg, val;
bellard14ce26e2005-01-03 23:50:08 +00004565 target_ulong next_eip, tval;
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03004566 target_ulong pc_start = s->base.pc_next;
bellard2c0262a2003-09-30 20:34:21 +00004567
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004568 s->pc_start = s->pc = pc_start;
bellard2c0262a2003-09-30 20:34:21 +00004569 s->override = -1;
bellard14ce26e2005-01-03 23:50:08 +00004570#ifdef TARGET_X86_64
Richard Henderson8ab1e482021-05-14 10:13:10 -05004571 s->rex_w = false;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004572 s->rex_r = 0;
bellard14ce26e2005-01-03 23:50:08 +00004573 s->rex_x = 0;
4574 s->rex_b = 0;
bellard14ce26e2005-01-03 23:50:08 +00004575#endif
4576 s->rip_offset = 0; /* for relative ip address */
Richard Henderson701ed212013-01-11 11:35:02 -08004577 s->vex_l = 0;
4578 s->vex_v = 0;
Paolo Bonzinib066c532017-03-22 11:57:10 +01004579 if (sigsetjmp(s->jmpbuf, 0) != 0) {
Richard Henderson6bd99582021-05-14 10:12:53 -05004580 gen_exception_gpf(s);
Paolo Bonzinib066c532017-03-22 11:57:10 +01004581 return s->pc;
Pranith Kumar30663fd2017-03-23 13:58:51 -04004582 }
Paolo Bonzinib066c532017-03-22 11:57:10 +01004583
Stefan Weila4926d92017-11-13 07:48:45 +01004584 prefixes = 0;
Stefan Weila4926d92017-11-13 07:48:45 +01004585
Paolo Bonzinib066c532017-03-22 11:57:10 +01004586 next_byte:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004587 b = x86_ldub_code(env, s);
Richard Henderson4a6fd932013-01-10 13:29:23 -08004588 /* Collect prefixes. */
4589 switch (b) {
4590 case 0xf3:
4591 prefixes |= PREFIX_REPZ;
4592 goto next_byte;
4593 case 0xf2:
4594 prefixes |= PREFIX_REPNZ;
4595 goto next_byte;
4596 case 0xf0:
4597 prefixes |= PREFIX_LOCK;
4598 goto next_byte;
4599 case 0x2e:
4600 s->override = R_CS;
4601 goto next_byte;
4602 case 0x36:
4603 s->override = R_SS;
4604 goto next_byte;
4605 case 0x3e:
4606 s->override = R_DS;
4607 goto next_byte;
4608 case 0x26:
4609 s->override = R_ES;
4610 goto next_byte;
4611 case 0x64:
4612 s->override = R_FS;
4613 goto next_byte;
4614 case 0x65:
4615 s->override = R_GS;
4616 goto next_byte;
4617 case 0x66:
4618 prefixes |= PREFIX_DATA;
4619 goto next_byte;
4620 case 0x67:
4621 prefixes |= PREFIX_ADR;
4622 goto next_byte;
bellard14ce26e2005-01-03 23:50:08 +00004623#ifdef TARGET_X86_64
Richard Henderson4a6fd932013-01-10 13:29:23 -08004624 case 0x40 ... 0x4f:
4625 if (CODE64(s)) {
bellard14ce26e2005-01-03 23:50:08 +00004626 /* REX prefix */
Richard Henderson1e92b722021-05-14 10:13:07 -05004627 prefixes |= PREFIX_REX;
Richard Henderson8ab1e482021-05-14 10:13:10 -05004628 s->rex_w = (b >> 3) & 1;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004629 s->rex_r = (b & 0x4) << 1;
bellard14ce26e2005-01-03 23:50:08 +00004630 s->rex_x = (b & 0x2) << 2;
Richard Henderson915ffe82021-05-14 10:13:08 -05004631 s->rex_b = (b & 0x1) << 3;
bellard14ce26e2005-01-03 23:50:08 +00004632 goto next_byte;
4633 }
Richard Henderson4a6fd932013-01-10 13:29:23 -08004634 break;
4635#endif
Richard Henderson701ed212013-01-11 11:35:02 -08004636 case 0xc5: /* 2-byte VEX */
4637 case 0xc4: /* 3-byte VEX */
4638 /* VEX prefixes cannot be used except in 32-bit mode.
4639 Otherwise the instruction is LES or LDS. */
Richard Henderson9996dcf2021-05-14 10:13:02 -05004640 if (CODE32(s) && !VM86(s)) {
Richard Henderson701ed212013-01-11 11:35:02 -08004641 static const int pp_prefix[4] = {
4642 0, PREFIX_DATA, PREFIX_REPZ, PREFIX_REPNZ
4643 };
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004644 int vex3, vex2 = x86_ldub_code(env, s);
Richard Henderson701ed212013-01-11 11:35:02 -08004645
4646 if (!CODE64(s) && (vex2 & 0xc0) != 0xc0) {
4647 /* 4.1.4.6: In 32-bit mode, bits [7:6] must be 11b,
4648 otherwise the instruction is LES or LDS. */
Peter Maydellcfcca362017-12-13 11:19:19 +00004649 s->pc--; /* rewind the advance_pc() x86_ldub_code() did */
Richard Henderson701ed212013-01-11 11:35:02 -08004650 break;
4651 }
Richard Henderson701ed212013-01-11 11:35:02 -08004652
Peter Maydell085d8132013-03-18 17:20:07 +00004653 /* 4.1.1-4.1.3: No preceding lock, 66, f2, f3, or rex prefixes. */
Richard Henderson701ed212013-01-11 11:35:02 -08004654 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ
Richard Henderson1e92b722021-05-14 10:13:07 -05004655 | PREFIX_LOCK | PREFIX_DATA | PREFIX_REX)) {
Richard Henderson701ed212013-01-11 11:35:02 -08004656 goto illegal_op;
4657 }
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004658#ifdef TARGET_X86_64
4659 s->rex_r = (~vex2 >> 4) & 8;
4660#endif
Richard Henderson701ed212013-01-11 11:35:02 -08004661 if (b == 0xc5) {
Eugene Minibaeve0014d42018-04-06 16:41:52 +03004662 /* 2-byte VEX prefix: RVVVVlpp, implied 0f leading opcode byte */
Richard Henderson701ed212013-01-11 11:35:02 -08004663 vex3 = vex2;
Eugene Minibaeve0014d42018-04-06 16:41:52 +03004664 b = x86_ldub_code(env, s) | 0x100;
Richard Henderson701ed212013-01-11 11:35:02 -08004665 } else {
Eugene Minibaeve0014d42018-04-06 16:41:52 +03004666 /* 3-byte VEX prefix: RXBmmmmm wVVVVlpp */
Richard Henderson8ab1e482021-05-14 10:13:10 -05004667 vex3 = x86_ldub_code(env, s);
Richard Henderson701ed212013-01-11 11:35:02 -08004668#ifdef TARGET_X86_64
4669 s->rex_x = (~vex2 >> 3) & 8;
4670 s->rex_b = (~vex2 >> 2) & 8;
Richard Henderson8ab1e482021-05-14 10:13:10 -05004671 s->rex_w = (vex3 >> 7) & 1;
Richard Henderson701ed212013-01-11 11:35:02 -08004672#endif
Richard Henderson701ed212013-01-11 11:35:02 -08004673 switch (vex2 & 0x1f) {
4674 case 0x01: /* Implied 0f leading opcode bytes. */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004675 b = x86_ldub_code(env, s) | 0x100;
Richard Henderson701ed212013-01-11 11:35:02 -08004676 break;
4677 case 0x02: /* Implied 0f 38 leading opcode bytes. */
4678 b = 0x138;
4679 break;
4680 case 0x03: /* Implied 0f 3a leading opcode bytes. */
4681 b = 0x13a;
4682 break;
4683 default: /* Reserved for future use. */
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08004684 goto unknown_op;
Richard Henderson701ed212013-01-11 11:35:02 -08004685 }
4686 }
4687 s->vex_v = (~vex3 >> 3) & 0xf;
4688 s->vex_l = (vex3 >> 2) & 1;
4689 prefixes |= pp_prefix[vex3 & 3] | PREFIX_VEX;
4690 }
4691 break;
Richard Henderson4a6fd932013-01-10 13:29:23 -08004692 }
4693
4694 /* Post-process prefixes. */
Richard Henderson4a6fd932013-01-10 13:29:23 -08004695 if (CODE64(s)) {
Richard Hendersondec3fc92013-05-29 12:30:51 -07004696 /* In 64-bit mode, the default data size is 32-bit. Select 64-bit
4697 data with rex_w, and 16-bit data with 0x66; rex_w takes precedence
4698 over 0x66 if both are present. */
Richard Henderson8ab1e482021-05-14 10:13:10 -05004699 dflag = (REX_W(s) ? MO_64 : prefixes & PREFIX_DATA ? MO_16 : MO_32);
Richard Hendersondec3fc92013-05-29 12:30:51 -07004700 /* In 64-bit mode, 0x67 selects 32-bit addressing. */
Richard Henderson1d71ddb2013-11-06 08:27:33 +10004701 aflag = (prefixes & PREFIX_ADR ? MO_32 : MO_64);
Richard Hendersondec3fc92013-05-29 12:30:51 -07004702 } else {
4703 /* In 16/32-bit mode, 0x66 selects the opposite data size. */
Richard Henderson9996dcf2021-05-14 10:13:02 -05004704 if (CODE32(s) ^ ((prefixes & PREFIX_DATA) != 0)) {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004705 dflag = MO_32;
4706 } else {
4707 dflag = MO_16;
bellard14ce26e2005-01-03 23:50:08 +00004708 }
Richard Hendersondec3fc92013-05-29 12:30:51 -07004709 /* In 16/32-bit mode, 0x67 selects the opposite addressing. */
Richard Henderson9996dcf2021-05-14 10:13:02 -05004710 if (CODE32(s) ^ ((prefixes & PREFIX_ADR) != 0)) {
Richard Henderson1d71ddb2013-11-06 08:27:33 +10004711 aflag = MO_32;
4712 } else {
4713 aflag = MO_16;
bellard14ce26e2005-01-03 23:50:08 +00004714 }
bellard2c0262a2003-09-30 20:34:21 +00004715 }
4716
bellard2c0262a2003-09-30 20:34:21 +00004717 s->prefix = prefixes;
4718 s->aflag = aflag;
4719 s->dflag = dflag;
4720
bellard2c0262a2003-09-30 20:34:21 +00004721 /* now check op code */
4722 reswitch:
4723 switch(b) {
4724 case 0x0f:
4725 /**************************/
4726 /* extended op code */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004727 b = x86_ldub_code(env, s) | 0x100;
bellard2c0262a2003-09-30 20:34:21 +00004728 goto reswitch;
ths3b46e622007-09-17 08:09:54 +00004729
bellard2c0262a2003-09-30 20:34:21 +00004730 /**************************/
4731 /* arith & logic */
4732 case 0x00 ... 0x05:
4733 case 0x08 ... 0x0d:
4734 case 0x10 ... 0x15:
4735 case 0x18 ... 0x1d:
4736 case 0x20 ... 0x25:
4737 case 0x28 ... 0x2d:
4738 case 0x30 ... 0x35:
4739 case 0x38 ... 0x3d:
4740 {
4741 int op, f, val;
4742 op = (b >> 3) & 7;
4743 f = (b >> 1) & 3;
4744
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004745 ot = mo_b_d(b, dflag);
ths3b46e622007-09-17 08:09:54 +00004746
bellard2c0262a2003-09-30 20:34:21 +00004747 switch(f) {
4748 case 0: /* OP Ev, Gv */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004749 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004750 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard2c0262a2003-09-30 20:34:21 +00004751 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00004752 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00004753 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10004754 gen_lea_modrm(env, s, modrm);
bellard2c0262a2003-09-30 20:34:21 +00004755 opreg = OR_TMP0;
4756 } else if (op == OP_XORL && rm == reg) {
4757 xor_zero:
4758 /* xor reg, reg optimisation */
Richard Henderson436ff2d2013-01-29 13:38:43 -08004759 set_cc_op(s, CC_OP_CLR);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004760 tcg_gen_movi_tl(s->T0, 0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004761 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00004762 break;
4763 } else {
4764 opreg = rm;
4765 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004766 gen_op_mov_v_reg(s, ot, s->T1, reg);
bellard2c0262a2003-09-30 20:34:21 +00004767 gen_op(s, op, ot, opreg);
4768 break;
4769 case 1: /* OP Gv, Ev */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004770 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00004771 mod = (modrm >> 6) & 3;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05004772 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard14ce26e2005-01-03 23:50:08 +00004773 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00004774 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10004775 gen_lea_modrm(env, s, modrm);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004776 gen_op_ld_v(s, ot, s->T1, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00004777 } else if (op == OP_XORL && rm == reg) {
4778 goto xor_zero;
4779 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004780 gen_op_mov_v_reg(s, ot, s->T1, rm);
bellard2c0262a2003-09-30 20:34:21 +00004781 }
4782 gen_op(s, op, ot, reg);
4783 break;
4784 case 2: /* OP A, Iv */
Blue Swirl0af10c82012-09-08 13:26:02 +00004785 val = insn_get(env, s, ot);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004786 tcg_gen_movi_tl(s->T1, val);
bellard2c0262a2003-09-30 20:34:21 +00004787 gen_op(s, op, ot, OR_EAX);
4788 break;
4789 }
4790 }
4791 break;
4792
bellardec9d6072008-06-06 12:54:30 +00004793 case 0x82:
4794 if (CODE64(s))
4795 goto illegal_op;
Paolo Bonziniedd75412018-08-01 17:14:09 +02004796 /* fall through */
bellard2c0262a2003-09-30 20:34:21 +00004797 case 0x80: /* GRP1 */
4798 case 0x81:
4799 case 0x83:
4800 {
4801 int val;
4802
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004803 ot = mo_b_d(b, dflag);
ths3b46e622007-09-17 08:09:54 +00004804
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004805 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00004806 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00004807 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00004808 op = (modrm >> 3) & 7;
ths3b46e622007-09-17 08:09:54 +00004809
bellard2c0262a2003-09-30 20:34:21 +00004810 if (mod != 3) {
bellard14ce26e2005-01-03 23:50:08 +00004811 if (b == 0x83)
4812 s->rip_offset = 1;
4813 else
4814 s->rip_offset = insn_const_size(ot);
Richard Henderson4eeb3932013-11-02 08:55:59 -10004815 gen_lea_modrm(env, s, modrm);
bellard2c0262a2003-09-30 20:34:21 +00004816 opreg = OR_TMP0;
4817 } else {
bellard14ce26e2005-01-03 23:50:08 +00004818 opreg = rm;
bellard2c0262a2003-09-30 20:34:21 +00004819 }
4820
4821 switch(b) {
4822 default:
4823 case 0x80:
4824 case 0x81:
bellardd64477a2004-04-22 21:34:25 +00004825 case 0x82:
Blue Swirl0af10c82012-09-08 13:26:02 +00004826 val = insn_get(env, s, ot);
bellard2c0262a2003-09-30 20:34:21 +00004827 break;
4828 case 0x83:
Richard Henderson4ba99382013-11-02 09:54:47 -07004829 val = (int8_t)insn_get(env, s, MO_8);
bellard2c0262a2003-09-30 20:34:21 +00004830 break;
4831 }
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004832 tcg_gen_movi_tl(s->T1, val);
bellard2c0262a2003-09-30 20:34:21 +00004833 gen_op(s, op, ot, opreg);
4834 }
4835 break;
4836
4837 /**************************/
4838 /* inc, dec, and other misc arith */
4839 case 0x40 ... 0x47: /* inc Gv */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004840 ot = dflag;
bellard2c0262a2003-09-30 20:34:21 +00004841 gen_inc(s, ot, OR_EAX + (b & 7), 1);
4842 break;
4843 case 0x48 ... 0x4f: /* dec Gv */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004844 ot = dflag;
bellard2c0262a2003-09-30 20:34:21 +00004845 gen_inc(s, ot, OR_EAX + (b & 7), -1);
4846 break;
4847 case 0xf6: /* GRP3 */
4848 case 0xf7:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10004849 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00004850
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02004851 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00004852 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00004853 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00004854 op = (modrm >> 3) & 7;
4855 if (mod != 3) {
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004856 if (op == 0) {
bellard14ce26e2005-01-03 23:50:08 +00004857 s->rip_offset = insn_const_size(ot);
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004858 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10004859 gen_lea_modrm(env, s, modrm);
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004860 /* For those below that handle locked memory, don't load here. */
4861 if (!(s->prefix & PREFIX_LOCK)
4862 || op != 2) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004863 gen_op_ld_v(s, ot, s->T0, s->A0);
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004864 }
bellard2c0262a2003-09-30 20:34:21 +00004865 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004866 gen_op_mov_v_reg(s, ot, s->T0, rm);
bellard2c0262a2003-09-30 20:34:21 +00004867 }
4868
4869 switch(op) {
4870 case 0: /* test */
Blue Swirl0af10c82012-09-08 13:26:02 +00004871 val = insn_get(env, s, ot);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004872 tcg_gen_movi_tl(s->T1, val);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004873 gen_op_testl_T0_T1_cc(s);
Richard Henderson3ca51d02013-01-23 12:30:52 -08004874 set_cc_op(s, CC_OP_LOGICB + ot);
bellard2c0262a2003-09-30 20:34:21 +00004875 break;
4876 case 2: /* not */
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004877 if (s->prefix & PREFIX_LOCK) {
4878 if (mod == 3) {
4879 goto illegal_op;
4880 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004881 tcg_gen_movi_tl(s->T0, ~0);
4882 tcg_gen_atomic_xor_fetch_tl(s->T0, s->A0, s->T0,
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004883 s->mem_index, ot | MO_LE);
bellard2c0262a2003-09-30 20:34:21 +00004884 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004885 tcg_gen_not_tl(s->T0, s->T0);
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004886 if (mod != 3) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004887 gen_op_st_v(s, ot, s->T0, s->A0);
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004888 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004889 gen_op_mov_reg_v(s, ot, rm, s->T0);
Emilio G. Cota2a5fe8a2016-06-27 15:02:00 -04004890 }
bellard2c0262a2003-09-30 20:34:21 +00004891 }
4892 break;
4893 case 3: /* neg */
Emilio G. Cota8eb8c732016-06-27 15:02:01 -04004894 if (s->prefix & PREFIX_LOCK) {
4895 TCGLabel *label1;
4896 TCGv a0, t0, t1, t2;
4897
4898 if (mod == 3) {
4899 goto illegal_op;
4900 }
4901 a0 = tcg_temp_local_new();
4902 t0 = tcg_temp_local_new();
4903 label1 = gen_new_label();
4904
Emilio G. Cota6b672b52018-09-11 14:41:57 -04004905 tcg_gen_mov_tl(a0, s->A0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004906 tcg_gen_mov_tl(t0, s->T0);
Emilio G. Cota8eb8c732016-06-27 15:02:01 -04004907
4908 gen_set_label(label1);
4909 t1 = tcg_temp_new();
4910 t2 = tcg_temp_new();
4911 tcg_gen_mov_tl(t2, t0);
4912 tcg_gen_neg_tl(t1, t0);
4913 tcg_gen_atomic_cmpxchg_tl(t0, a0, t0, t1,
4914 s->mem_index, ot | MO_LE);
4915 tcg_temp_free(t1);
4916 tcg_gen_brcond_tl(TCG_COND_NE, t0, t2, label1);
4917
4918 tcg_temp_free(t2);
4919 tcg_temp_free(a0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004920 tcg_gen_mov_tl(s->T0, t0);
Emilio G. Cota8eb8c732016-06-27 15:02:01 -04004921 tcg_temp_free(t0);
bellard2c0262a2003-09-30 20:34:21 +00004922 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004923 tcg_gen_neg_tl(s->T0, s->T0);
Emilio G. Cota8eb8c732016-06-27 15:02:01 -04004924 if (mod != 3) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004925 gen_op_st_v(s, ot, s->T0, s->A0);
Emilio G. Cota8eb8c732016-06-27 15:02:01 -04004926 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004927 gen_op_mov_reg_v(s, ot, rm, s->T0);
Emilio G. Cota8eb8c732016-06-27 15:02:01 -04004928 }
bellard2c0262a2003-09-30 20:34:21 +00004929 }
Emilio G. Cota93a3e102018-09-11 14:38:47 -04004930 gen_op_update_neg_cc(s);
Richard Henderson3ca51d02013-01-23 12:30:52 -08004931 set_cc_op(s, CC_OP_SUBB + ot);
bellard2c0262a2003-09-30 20:34:21 +00004932 break;
4933 case 4: /* mul */
4934 switch(ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07004935 case MO_8:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004936 gen_op_mov_v_reg(s, MO_8, s->T1, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004937 tcg_gen_ext8u_tl(s->T0, s->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004938 tcg_gen_ext8u_tl(s->T1, s->T1);
bellard0211e5a2008-05-21 10:12:54 +00004939 /* XXX: use 32 bit mul which could be faster */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004940 tcg_gen_mul_tl(s->T0, s->T0, s->T1);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004941 gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004942 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
4943 tcg_gen_andi_tl(cpu_cc_src, s->T0, 0xff00);
Richard Henderson3ca51d02013-01-23 12:30:52 -08004944 set_cc_op(s, CC_OP_MULB);
bellard2c0262a2003-09-30 20:34:21 +00004945 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07004946 case MO_16:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004947 gen_op_mov_v_reg(s, MO_16, s->T1, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004948 tcg_gen_ext16u_tl(s->T0, s->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004949 tcg_gen_ext16u_tl(s->T1, s->T1);
bellard0211e5a2008-05-21 10:12:54 +00004950 /* XXX: use 32 bit mul which could be faster */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004951 tcg_gen_mul_tl(s->T0, s->T0, s->T1);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004952 gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004953 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
4954 tcg_gen_shri_tl(s->T0, s->T0, 16);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004955 gen_op_mov_reg_v(s, MO_16, R_EDX, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004956 tcg_gen_mov_tl(cpu_cc_src, s->T0);
Richard Henderson3ca51d02013-01-23 12:30:52 -08004957 set_cc_op(s, CC_OP_MULW);
bellard2c0262a2003-09-30 20:34:21 +00004958 break;
4959 default:
Richard Henderson4ba99382013-11-02 09:54:47 -07004960 case MO_32:
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004961 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
Emilio G. Cota4f824462018-09-11 14:17:56 -04004962 tcg_gen_trunc_tl_i32(s->tmp3_i32, cpu_regs[R_EAX]);
4963 tcg_gen_mulu2_i32(s->tmp2_i32, s->tmp3_i32,
4964 s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04004965 tcg_gen_extu_i32_tl(cpu_regs[R_EAX], s->tmp2_i32);
Emilio G. Cota4f824462018-09-11 14:17:56 -04004966 tcg_gen_extu_i32_tl(cpu_regs[R_EDX], s->tmp3_i32);
Richard Hendersona4bcea32013-02-26 12:06:23 -08004967 tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
4968 tcg_gen_mov_tl(cpu_cc_src, cpu_regs[R_EDX]);
Richard Henderson3ca51d02013-01-23 12:30:52 -08004969 set_cc_op(s, CC_OP_MULL);
bellard2c0262a2003-09-30 20:34:21 +00004970 break;
bellard14ce26e2005-01-03 23:50:08 +00004971#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07004972 case MO_64:
Richard Hendersona4bcea32013-02-26 12:06:23 -08004973 tcg_gen_mulu2_i64(cpu_regs[R_EAX], cpu_regs[R_EDX],
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004974 s->T0, cpu_regs[R_EAX]);
Richard Hendersona4bcea32013-02-26 12:06:23 -08004975 tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
4976 tcg_gen_mov_tl(cpu_cc_src, cpu_regs[R_EDX]);
Richard Henderson3ca51d02013-01-23 12:30:52 -08004977 set_cc_op(s, CC_OP_MULQ);
bellard14ce26e2005-01-03 23:50:08 +00004978 break;
4979#endif
bellard2c0262a2003-09-30 20:34:21 +00004980 }
bellard2c0262a2003-09-30 20:34:21 +00004981 break;
4982 case 5: /* imul */
4983 switch(ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07004984 case MO_8:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004985 gen_op_mov_v_reg(s, MO_8, s->T1, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004986 tcg_gen_ext8s_tl(s->T0, s->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004987 tcg_gen_ext8s_tl(s->T1, s->T1);
bellard0211e5a2008-05-21 10:12:54 +00004988 /* XXX: use 32 bit mul which could be faster */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004989 tcg_gen_mul_tl(s->T0, s->T0, s->T1);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004990 gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004991 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04004992 tcg_gen_ext8s_tl(s->tmp0, s->T0);
4993 tcg_gen_sub_tl(cpu_cc_src, s->T0, s->tmp0);
Richard Henderson3ca51d02013-01-23 12:30:52 -08004994 set_cc_op(s, CC_OP_MULB);
bellard2c0262a2003-09-30 20:34:21 +00004995 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07004996 case MO_16:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04004997 gen_op_mov_v_reg(s, MO_16, s->T1, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04004998 tcg_gen_ext16s_tl(s->T0, s->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04004999 tcg_gen_ext16s_tl(s->T1, s->T1);
bellard0211e5a2008-05-21 10:12:54 +00005000 /* XXX: use 32 bit mul which could be faster */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005001 tcg_gen_mul_tl(s->T0, s->T0, s->T1);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005002 gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005003 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04005004 tcg_gen_ext16s_tl(s->tmp0, s->T0);
5005 tcg_gen_sub_tl(cpu_cc_src, s->T0, s->tmp0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005006 tcg_gen_shri_tl(s->T0, s->T0, 16);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005007 gen_op_mov_reg_v(s, MO_16, R_EDX, s->T0);
Richard Henderson3ca51d02013-01-23 12:30:52 -08005008 set_cc_op(s, CC_OP_MULW);
bellard2c0262a2003-09-30 20:34:21 +00005009 break;
5010 default:
Richard Henderson4ba99382013-11-02 09:54:47 -07005011 case MO_32:
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005012 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
Emilio G. Cota4f824462018-09-11 14:17:56 -04005013 tcg_gen_trunc_tl_i32(s->tmp3_i32, cpu_regs[R_EAX]);
5014 tcg_gen_muls2_i32(s->tmp2_i32, s->tmp3_i32,
5015 s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005016 tcg_gen_extu_i32_tl(cpu_regs[R_EAX], s->tmp2_i32);
Emilio G. Cota4f824462018-09-11 14:17:56 -04005017 tcg_gen_extu_i32_tl(cpu_regs[R_EDX], s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005018 tcg_gen_sari_i32(s->tmp2_i32, s->tmp2_i32, 31);
Richard Hendersona4bcea32013-02-26 12:06:23 -08005019 tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
Emilio G. Cota4f824462018-09-11 14:17:56 -04005020 tcg_gen_sub_i32(s->tmp2_i32, s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005021 tcg_gen_extu_i32_tl(cpu_cc_src, s->tmp2_i32);
Richard Henderson3ca51d02013-01-23 12:30:52 -08005022 set_cc_op(s, CC_OP_MULL);
bellard2c0262a2003-09-30 20:34:21 +00005023 break;
bellard14ce26e2005-01-03 23:50:08 +00005024#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07005025 case MO_64:
Richard Hendersona4bcea32013-02-26 12:06:23 -08005026 tcg_gen_muls2_i64(cpu_regs[R_EAX], cpu_regs[R_EDX],
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005027 s->T0, cpu_regs[R_EAX]);
Richard Hendersona4bcea32013-02-26 12:06:23 -08005028 tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[R_EAX]);
5029 tcg_gen_sari_tl(cpu_cc_src, cpu_regs[R_EAX], 63);
5030 tcg_gen_sub_tl(cpu_cc_src, cpu_cc_src, cpu_regs[R_EDX]);
Richard Henderson3ca51d02013-01-23 12:30:52 -08005031 set_cc_op(s, CC_OP_MULQ);
bellard14ce26e2005-01-03 23:50:08 +00005032 break;
5033#endif
bellard2c0262a2003-09-30 20:34:21 +00005034 }
bellard2c0262a2003-09-30 20:34:21 +00005035 break;
5036 case 6: /* div */
5037 switch(ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07005038 case MO_8:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005039 gen_helper_divb_AL(cpu_env, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005040 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07005041 case MO_16:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005042 gen_helper_divw_AX(cpu_env, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005043 break;
5044 default:
Richard Henderson4ba99382013-11-02 09:54:47 -07005045 case MO_32:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005046 gen_helper_divl_EAX(cpu_env, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005047 break;
bellard14ce26e2005-01-03 23:50:08 +00005048#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07005049 case MO_64:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005050 gen_helper_divq_EAX(cpu_env, s->T0);
bellard14ce26e2005-01-03 23:50:08 +00005051 break;
5052#endif
bellard2c0262a2003-09-30 20:34:21 +00005053 }
5054 break;
5055 case 7: /* idiv */
5056 switch(ot) {
Richard Henderson4ba99382013-11-02 09:54:47 -07005057 case MO_8:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005058 gen_helper_idivb_AL(cpu_env, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005059 break;
Richard Henderson4ba99382013-11-02 09:54:47 -07005060 case MO_16:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005061 gen_helper_idivw_AX(cpu_env, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005062 break;
5063 default:
Richard Henderson4ba99382013-11-02 09:54:47 -07005064 case MO_32:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005065 gen_helper_idivl_EAX(cpu_env, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005066 break;
bellard14ce26e2005-01-03 23:50:08 +00005067#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07005068 case MO_64:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005069 gen_helper_idivq_EAX(cpu_env, s->T0);
bellard14ce26e2005-01-03 23:50:08 +00005070 break;
5071#endif
bellard2c0262a2003-09-30 20:34:21 +00005072 }
5073 break;
5074 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08005075 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00005076 }
5077 break;
5078
5079 case 0xfe: /* GRP4 */
5080 case 0xff: /* GRP5 */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005081 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00005082
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005083 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005084 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00005085 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00005086 op = (modrm >> 3) & 7;
5087 if (op >= 2 && b == 0xfe) {
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08005088 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00005089 }
bellard14ce26e2005-01-03 23:50:08 +00005090 if (CODE64(s)) {
bellardaba9d612005-04-23 17:53:12 +00005091 if (op == 2 || op == 4) {
bellard14ce26e2005-01-03 23:50:08 +00005092 /* operand size for jumps is 64 bit */
Richard Henderson4ba99382013-11-02 09:54:47 -07005093 ot = MO_64;
bellardaba9d612005-04-23 17:53:12 +00005094 } else if (op == 3 || op == 5) {
Richard Henderson8ab1e482021-05-14 10:13:10 -05005095 ot = dflag != MO_16 ? MO_32 + REX_W(s) : MO_16;
bellard14ce26e2005-01-03 23:50:08 +00005096 } else if (op == 6) {
5097 /* default push size is 64 bit */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005098 ot = mo_pushpop(s, dflag);
bellard14ce26e2005-01-03 23:50:08 +00005099 }
5100 }
bellard2c0262a2003-09-30 20:34:21 +00005101 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10005102 gen_lea_modrm(env, s, modrm);
bellard2c0262a2003-09-30 20:34:21 +00005103 if (op >= 2 && op != 3 && op != 5)
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005104 gen_op_ld_v(s, ot, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00005105 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005106 gen_op_mov_v_reg(s, ot, s->T0, rm);
bellard2c0262a2003-09-30 20:34:21 +00005107 }
5108
5109 switch(op) {
5110 case 0: /* inc Ev */
5111 if (mod != 3)
5112 opreg = OR_TMP0;
5113 else
5114 opreg = rm;
5115 gen_inc(s, ot, opreg, 1);
5116 break;
5117 case 1: /* dec Ev */
5118 if (mod != 3)
5119 opreg = OR_TMP0;
5120 else
5121 opreg = rm;
5122 gen_inc(s, ot, opreg, -1);
5123 break;
5124 case 2: /* call Ev */
bellard4f319162004-01-04 17:35:00 +00005125 /* XXX: optimize if memory (no 'and' is necessary) */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005126 if (dflag == MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005127 tcg_gen_ext16u_tl(s->T0, s->T0);
Richard Henderson40b90232013-11-05 12:23:48 +10005128 }
bellard2c0262a2003-09-30 20:34:21 +00005129 next_eip = s->pc - s->cs_base;
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005130 tcg_gen_movi_tl(s->T1, next_eip);
5131 gen_push_v(s, s->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005132 gen_op_jmp_v(s->T0);
Richard Henderson7d117ce2015-07-07 14:38:58 +01005133 gen_bnd_jmp(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005134 gen_jr(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005135 break;
bellard61382a52003-10-27 21:22:23 +00005136 case 3: /* lcall Ev */
Richard Henderson10b8eb92021-03-24 10:46:50 -06005137 if (mod == 3) {
5138 goto illegal_op;
5139 }
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005140 gen_op_ld_v(s, ot, s->T1, s->A0);
Richard Henderson830a19a2013-11-07 09:13:27 +10005141 gen_add_A0_im(s, 1 << ot);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005142 gen_op_ld_v(s, MO_16, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00005143 do_lcall:
Richard Hendersonf8a35842021-05-14 10:13:01 -05005144 if (PE(s) && !VM86(s)) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005145 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
5146 gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1,
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005147 tcg_const_i32(dflag - 1),
Pavel Dovgalyuk100ec092015-07-10 12:57:36 +03005148 tcg_const_tl(s->pc - s->cs_base));
bellard2c0262a2003-09-30 20:34:21 +00005149 } else {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005150 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
5151 gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->T1,
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005152 tcg_const_i32(dflag - 1),
pbrooka7812ae2008-11-17 14:43:54 +00005153 tcg_const_i32(s->pc - s->cs_base));
bellard2c0262a2003-09-30 20:34:21 +00005154 }
Emilio G. Cota5022f282018-09-11 14:10:21 -04005155 tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip));
5156 gen_jr(s, s->tmp4);
bellard2c0262a2003-09-30 20:34:21 +00005157 break;
5158 case 4: /* jmp Ev */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005159 if (dflag == MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005160 tcg_gen_ext16u_tl(s->T0, s->T0);
Richard Henderson40b90232013-11-05 12:23:48 +10005161 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005162 gen_op_jmp_v(s->T0);
Richard Henderson7d117ce2015-07-07 14:38:58 +01005163 gen_bnd_jmp(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005164 gen_jr(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005165 break;
5166 case 5: /* ljmp Ev */
Richard Henderson10b8eb92021-03-24 10:46:50 -06005167 if (mod == 3) {
5168 goto illegal_op;
5169 }
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005170 gen_op_ld_v(s, ot, s->T1, s->A0);
Richard Henderson830a19a2013-11-07 09:13:27 +10005171 gen_add_A0_im(s, 1 << ot);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005172 gen_op_ld_v(s, MO_16, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00005173 do_ljmp:
Richard Hendersonf8a35842021-05-14 10:13:01 -05005174 if (PE(s) && !VM86(s)) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005175 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
5176 gen_helper_ljmp_protected(cpu_env, s->tmp2_i32, s->T1,
Pavel Dovgalyuk100ec092015-07-10 12:57:36 +03005177 tcg_const_tl(s->pc - s->cs_base));
bellard2c0262a2003-09-30 20:34:21 +00005178 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005179 gen_op_movl_seg_T0_vm(s, R_CS);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005180 gen_op_jmp_v(s->T1);
bellard2c0262a2003-09-30 20:34:21 +00005181 }
Emilio G. Cota5022f282018-09-11 14:10:21 -04005182 tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip));
5183 gen_jr(s, s->tmp4);
bellard2c0262a2003-09-30 20:34:21 +00005184 break;
5185 case 6: /* push Ev */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005186 gen_push_v(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005187 break;
5188 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08005189 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00005190 }
5191 break;
5192
5193 case 0x84: /* test Ev, Gv */
ths5fafdf22007-09-16 21:08:06 +00005194 case 0x85:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005195 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00005196
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005197 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005198 reg = ((modrm >> 3) & 7) | REX_R(s);
ths3b46e622007-09-17 08:09:54 +00005199
Blue Swirl0af10c82012-09-08 13:26:02 +00005200 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005201 gen_op_mov_v_reg(s, ot, s->T1, reg);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005202 gen_op_testl_T0_T1_cc(s);
Richard Henderson3ca51d02013-01-23 12:30:52 -08005203 set_cc_op(s, CC_OP_LOGICB + ot);
bellard2c0262a2003-09-30 20:34:21 +00005204 break;
ths3b46e622007-09-17 08:09:54 +00005205
bellard2c0262a2003-09-30 20:34:21 +00005206 case 0xa8: /* test eAX, Iv */
5207 case 0xa9:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005208 ot = mo_b_d(b, dflag);
Blue Swirl0af10c82012-09-08 13:26:02 +00005209 val = insn_get(env, s, ot);
bellard2c0262a2003-09-30 20:34:21 +00005210
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005211 gen_op_mov_v_reg(s, ot, s->T0, OR_EAX);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005212 tcg_gen_movi_tl(s->T1, val);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005213 gen_op_testl_T0_T1_cc(s);
Richard Henderson3ca51d02013-01-23 12:30:52 -08005214 set_cc_op(s, CC_OP_LOGICB + ot);
bellard2c0262a2003-09-30 20:34:21 +00005215 break;
ths3b46e622007-09-17 08:09:54 +00005216
bellard2c0262a2003-09-30 20:34:21 +00005217 case 0x98: /* CWDE/CBW */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005218 switch (dflag) {
bellard14ce26e2005-01-03 23:50:08 +00005219#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005220 case MO_64:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005221 gen_op_mov_v_reg(s, MO_32, s->T0, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005222 tcg_gen_ext32s_tl(s->T0, s->T0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005223 gen_op_mov_reg_v(s, MO_64, R_EAX, s->T0);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005224 break;
bellard14ce26e2005-01-03 23:50:08 +00005225#endif
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005226 case MO_32:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005227 gen_op_mov_v_reg(s, MO_16, s->T0, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005228 tcg_gen_ext16s_tl(s->T0, s->T0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005229 gen_op_mov_reg_v(s, MO_32, R_EAX, s->T0);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005230 break;
5231 case MO_16:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005232 gen_op_mov_v_reg(s, MO_8, s->T0, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005233 tcg_gen_ext8s_tl(s->T0, s->T0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005234 gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005235 break;
5236 default:
5237 tcg_abort();
bellarde108dd02008-05-17 19:24:07 +00005238 }
bellard2c0262a2003-09-30 20:34:21 +00005239 break;
5240 case 0x99: /* CDQ/CWD */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005241 switch (dflag) {
bellard14ce26e2005-01-03 23:50:08 +00005242#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005243 case MO_64:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005244 gen_op_mov_v_reg(s, MO_64, s->T0, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005245 tcg_gen_sari_tl(s->T0, s->T0, 63);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005246 gen_op_mov_reg_v(s, MO_64, R_EDX, s->T0);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005247 break;
bellard14ce26e2005-01-03 23:50:08 +00005248#endif
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005249 case MO_32:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005250 gen_op_mov_v_reg(s, MO_32, s->T0, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005251 tcg_gen_ext32s_tl(s->T0, s->T0);
5252 tcg_gen_sari_tl(s->T0, s->T0, 31);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005253 gen_op_mov_reg_v(s, MO_32, R_EDX, s->T0);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005254 break;
5255 case MO_16:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005256 gen_op_mov_v_reg(s, MO_16, s->T0, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005257 tcg_gen_ext16s_tl(s->T0, s->T0);
5258 tcg_gen_sari_tl(s->T0, s->T0, 15);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005259 gen_op_mov_reg_v(s, MO_16, R_EDX, s->T0);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005260 break;
5261 default:
5262 tcg_abort();
bellarde108dd02008-05-17 19:24:07 +00005263 }
bellard2c0262a2003-09-30 20:34:21 +00005264 break;
5265 case 0x1af: /* imul Gv, Ev */
5266 case 0x69: /* imul Gv, Ev, I */
5267 case 0x6b:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005268 ot = dflag;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005269 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005270 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard14ce26e2005-01-03 23:50:08 +00005271 if (b == 0x69)
5272 s->rip_offset = insn_const_size(ot);
5273 else if (b == 0x6b)
5274 s->rip_offset = 1;
Blue Swirl0af10c82012-09-08 13:26:02 +00005275 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
bellard2c0262a2003-09-30 20:34:21 +00005276 if (b == 0x69) {
Blue Swirl0af10c82012-09-08 13:26:02 +00005277 val = insn_get(env, s, ot);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005278 tcg_gen_movi_tl(s->T1, val);
bellard2c0262a2003-09-30 20:34:21 +00005279 } else if (b == 0x6b) {
Richard Henderson4ba99382013-11-02 09:54:47 -07005280 val = (int8_t)insn_get(env, s, MO_8);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005281 tcg_gen_movi_tl(s->T1, val);
bellard2c0262a2003-09-30 20:34:21 +00005282 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005283 gen_op_mov_v_reg(s, ot, s->T1, reg);
bellard2c0262a2003-09-30 20:34:21 +00005284 }
Richard Hendersona4bcea32013-02-26 12:06:23 -08005285 switch (ot) {
bellard14ce26e2005-01-03 23:50:08 +00005286#ifdef TARGET_X86_64
Richard Henderson4ba99382013-11-02 09:54:47 -07005287 case MO_64:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005288 tcg_gen_muls2_i64(cpu_regs[reg], s->T1, s->T0, s->T1);
Richard Hendersona4bcea32013-02-26 12:06:23 -08005289 tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[reg]);
5290 tcg_gen_sari_tl(cpu_cc_src, cpu_cc_dst, 63);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005291 tcg_gen_sub_tl(cpu_cc_src, cpu_cc_src, s->T1);
Richard Hendersona4bcea32013-02-26 12:06:23 -08005292 break;
bellard14ce26e2005-01-03 23:50:08 +00005293#endif
Richard Henderson4ba99382013-11-02 09:54:47 -07005294 case MO_32:
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005295 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
Emilio G. Cota4f824462018-09-11 14:17:56 -04005296 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
5297 tcg_gen_muls2_i32(s->tmp2_i32, s->tmp3_i32,
5298 s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005299 tcg_gen_extu_i32_tl(cpu_regs[reg], s->tmp2_i32);
5300 tcg_gen_sari_i32(s->tmp2_i32, s->tmp2_i32, 31);
Richard Hendersona4bcea32013-02-26 12:06:23 -08005301 tcg_gen_mov_tl(cpu_cc_dst, cpu_regs[reg]);
Emilio G. Cota4f824462018-09-11 14:17:56 -04005302 tcg_gen_sub_i32(s->tmp2_i32, s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04005303 tcg_gen_extu_i32_tl(cpu_cc_src, s->tmp2_i32);
Richard Hendersona4bcea32013-02-26 12:06:23 -08005304 break;
5305 default:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005306 tcg_gen_ext16s_tl(s->T0, s->T0);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005307 tcg_gen_ext16s_tl(s->T1, s->T1);
bellard0211e5a2008-05-21 10:12:54 +00005308 /* XXX: use 32 bit mul which could be faster */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005309 tcg_gen_mul_tl(s->T0, s->T0, s->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005310 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04005311 tcg_gen_ext16s_tl(s->tmp0, s->T0);
5312 tcg_gen_sub_tl(cpu_cc_src, s->T0, s->tmp0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005313 gen_op_mov_reg_v(s, ot, reg, s->T0);
Richard Hendersona4bcea32013-02-26 12:06:23 -08005314 break;
bellard2c0262a2003-09-30 20:34:21 +00005315 }
Richard Henderson3ca51d02013-01-23 12:30:52 -08005316 set_cc_op(s, CC_OP_MULB + ot);
bellard2c0262a2003-09-30 20:34:21 +00005317 break;
5318 case 0x1c0:
5319 case 0x1c1: /* xadd Ev, Gv */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005320 ot = mo_b_d(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005321 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005322 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard2c0262a2003-09-30 20:34:21 +00005323 mod = (modrm >> 6) & 3;
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005324 gen_op_mov_v_reg(s, ot, s->T0, reg);
bellard2c0262a2003-09-30 20:34:21 +00005325 if (mod == 3) {
bellard14ce26e2005-01-03 23:50:08 +00005326 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005327 gen_op_mov_v_reg(s, ot, s->T1, rm);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005328 tcg_gen_add_tl(s->T0, s->T0, s->T1);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005329 gen_op_mov_reg_v(s, ot, reg, s->T1);
5330 gen_op_mov_reg_v(s, ot, rm, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005331 } else {
Richard Henderson4eeb3932013-11-02 08:55:59 -10005332 gen_lea_modrm(env, s, modrm);
Emilio G. Cotaf53b0182016-06-27 15:02:02 -04005333 if (s->prefix & PREFIX_LOCK) {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005334 tcg_gen_atomic_fetch_add_tl(s->T1, s->A0, s->T0,
Emilio G. Cotaf53b0182016-06-27 15:02:02 -04005335 s->mem_index, ot | MO_LE);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005336 tcg_gen_add_tl(s->T0, s->T0, s->T1);
Emilio G. Cotaf53b0182016-06-27 15:02:02 -04005337 } else {
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005338 gen_op_ld_v(s, ot, s->T1, s->A0);
5339 tcg_gen_add_tl(s->T0, s->T0, s->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005340 gen_op_st_v(s, ot, s->T0, s->A0);
Emilio G. Cotaf53b0182016-06-27 15:02:02 -04005341 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005342 gen_op_mov_reg_v(s, ot, reg, s->T1);
bellard2c0262a2003-09-30 20:34:21 +00005343 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005344 gen_op_update2_cc(s);
Richard Henderson3ca51d02013-01-23 12:30:52 -08005345 set_cc_op(s, CC_OP_ADDB + ot);
bellard2c0262a2003-09-30 20:34:21 +00005346 break;
5347 case 0x1b0:
5348 case 0x1b1: /* cmpxchg Ev, Gv */
bellardcad3a372008-05-17 13:50:02 +00005349 {
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005350 TCGv oldv, newv, cmpv;
bellardcad3a372008-05-17 13:50:02 +00005351
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005352 ot = mo_b_d(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005353 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005354 reg = ((modrm >> 3) & 7) | REX_R(s);
bellardcad3a372008-05-17 13:50:02 +00005355 mod = (modrm >> 6) & 3;
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005356 oldv = tcg_temp_new();
5357 newv = tcg_temp_new();
5358 cmpv = tcg_temp_new();
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005359 gen_op_mov_v_reg(s, ot, newv, reg);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005360 tcg_gen_mov_tl(cmpv, cpu_regs[R_EAX]);
5361
5362 if (s->prefix & PREFIX_LOCK) {
5363 if (mod == 3) {
5364 goto illegal_op;
5365 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10005366 gen_lea_modrm(env, s, modrm);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005367 tcg_gen_atomic_cmpxchg_tl(oldv, s->A0, cmpv, newv,
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005368 s->mem_index, ot | MO_LE);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005369 gen_op_mov_reg_v(s, ot, R_EAX, oldv);
bellardcad3a372008-05-17 13:50:02 +00005370 } else {
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005371 if (mod == 3) {
5372 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005373 gen_op_mov_v_reg(s, ot, oldv, rm);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005374 } else {
5375 gen_lea_modrm(env, s, modrm);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005376 gen_op_ld_v(s, ot, oldv, s->A0);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005377 rm = 0; /* avoid warning */
5378 }
5379 gen_extu(ot, oldv);
5380 gen_extu(ot, cmpv);
5381 /* store value = (old == cmp ? new : old); */
5382 tcg_gen_movcond_tl(TCG_COND_EQ, newv, oldv, cmpv, newv, oldv);
5383 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005384 gen_op_mov_reg_v(s, ot, R_EAX, oldv);
5385 gen_op_mov_reg_v(s, ot, rm, newv);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005386 } else {
5387 /* Perform an unconditional store cycle like physical cpu;
5388 must be before changing accumulator to ensure
5389 idempotency if the store faults and the instruction
5390 is restarted */
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005391 gen_op_st_v(s, ot, newv, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005392 gen_op_mov_reg_v(s, ot, R_EAX, oldv);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005393 }
bellardcad3a372008-05-17 13:50:02 +00005394 }
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005395 tcg_gen_mov_tl(cpu_cc_src, oldv);
Emilio G. Cota93a3e102018-09-11 14:38:47 -04005396 tcg_gen_mov_tl(s->cc_srcT, cmpv);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005397 tcg_gen_sub_tl(cpu_cc_dst, cmpv, oldv);
Richard Henderson3ca51d02013-01-23 12:30:52 -08005398 set_cc_op(s, CC_OP_SUBB + ot);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005399 tcg_temp_free(oldv);
5400 tcg_temp_free(newv);
5401 tcg_temp_free(cmpv);
bellard2c0262a2003-09-30 20:34:21 +00005402 }
bellard2c0262a2003-09-30 20:34:21 +00005403 break;
5404 case 0x1c7: /* cmpxchg8b */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005405 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005406 mod = (modrm >> 6) & 3;
Richard Henderson369fd5c2019-03-14 20:01:42 -07005407 switch ((modrm >> 3) & 7) {
5408 case 1: /* CMPXCHG8, CMPXCHG16 */
5409 if (mod == 3) {
bellard1b9d9eb2008-05-22 09:52:38 +00005410 goto illegal_op;
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005411 }
Richard Henderson369fd5c2019-03-14 20:01:42 -07005412#ifdef TARGET_X86_64
5413 if (dflag == MO_64) {
5414 if (!(s->cpuid_ext_features & CPUID_EXT_CX16)) {
5415 goto illegal_op;
5416 }
5417 gen_lea_modrm(env, s, modrm);
5418 if ((s->prefix & PREFIX_LOCK) &&
5419 (tb_cflags(s->base.tb) & CF_PARALLEL)) {
5420 gen_helper_cmpxchg16b(cpu_env, s->A0);
5421 } else {
5422 gen_helper_cmpxchg16b_unlocked(cpu_env, s->A0);
5423 }
5424 set_cc_op(s, CC_OP_EFLAGS);
5425 break;
5426 }
bellard1b9d9eb2008-05-22 09:52:38 +00005427#endif
Richard Henderson369fd5c2019-03-14 20:01:42 -07005428 if (!(s->cpuid_features & CPUID_CX8)) {
bellard1b9d9eb2008-05-22 09:52:38 +00005429 goto illegal_op;
Richard Henderson369fd5c2019-03-14 20:01:42 -07005430 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10005431 gen_lea_modrm(env, s, modrm);
Richard Henderson369fd5c2019-03-14 20:01:42 -07005432 if ((s->prefix & PREFIX_LOCK) &&
5433 (tb_cflags(s->base.tb) & CF_PARALLEL)) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005434 gen_helper_cmpxchg8b(cpu_env, s->A0);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005435 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005436 gen_helper_cmpxchg8b_unlocked(cpu_env, s->A0);
Emilio G. Cotaae03f8d2016-06-27 15:01:51 -04005437 }
Richard Henderson369fd5c2019-03-14 20:01:42 -07005438 set_cc_op(s, CC_OP_EFLAGS);
5439 break;
5440
5441 case 7: /* RDSEED */
5442 case 6: /* RDRAND */
5443 if (mod != 3 ||
5444 (s->prefix & (PREFIX_LOCK | PREFIX_REPZ | PREFIX_REPNZ)) ||
5445 !(s->cpuid_ext_features & CPUID_EXT_RDRAND)) {
5446 goto illegal_op;
5447 }
5448 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
5449 gen_io_start();
5450 }
5451 gen_helper_rdrand(s->T0, cpu_env);
5452 rm = (modrm & 7) | REX_B(s);
5453 gen_op_mov_reg_v(s, dflag, rm, s->T0);
5454 set_cc_op(s, CC_OP_EFLAGS);
5455 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
Richard Henderson369fd5c2019-03-14 20:01:42 -07005456 gen_jmp(s, s->pc - s->cs_base);
5457 }
5458 break;
5459
5460 default:
5461 goto illegal_op;
bellard1b9d9eb2008-05-22 09:52:38 +00005462 }
bellard2c0262a2003-09-30 20:34:21 +00005463 break;
ths3b46e622007-09-17 08:09:54 +00005464
bellard2c0262a2003-09-30 20:34:21 +00005465 /**************************/
5466 /* push/pop */
5467 case 0x50 ... 0x57: /* push */
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005468 gen_op_mov_v_reg(s, MO_32, s->T0, (b & 7) | REX_B(s));
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005469 gen_push_v(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005470 break;
5471 case 0x58 ... 0x5f: /* pop */
Richard Henderson8e31d232013-11-06 13:57:45 +10005472 ot = gen_pop_T0(s);
bellard77729c22003-11-13 23:09:07 +00005473 /* NOTE: order is important for pop %sp */
Richard Henderson8e31d232013-11-06 13:57:45 +10005474 gen_pop_update(s, ot);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005475 gen_op_mov_reg_v(s, ot, (b & 7) | REX_B(s), s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005476 break;
5477 case 0x60: /* pusha */
bellard14ce26e2005-01-03 23:50:08 +00005478 if (CODE64(s))
5479 goto illegal_op;
bellard2c0262a2003-09-30 20:34:21 +00005480 gen_pusha(s);
5481 break;
5482 case 0x61: /* popa */
bellard14ce26e2005-01-03 23:50:08 +00005483 if (CODE64(s))
5484 goto illegal_op;
bellard2c0262a2003-09-30 20:34:21 +00005485 gen_popa(s);
5486 break;
5487 case 0x68: /* push Iv */
5488 case 0x6a:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005489 ot = mo_pushpop(s, dflag);
bellard2c0262a2003-09-30 20:34:21 +00005490 if (b == 0x68)
Blue Swirl0af10c82012-09-08 13:26:02 +00005491 val = insn_get(env, s, ot);
bellard2c0262a2003-09-30 20:34:21 +00005492 else
Richard Henderson4ba99382013-11-02 09:54:47 -07005493 val = (int8_t)insn_get(env, s, MO_8);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005494 tcg_gen_movi_tl(s->T0, val);
5495 gen_push_v(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005496 break;
5497 case 0x8f: /* pop Ev */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005498 modrm = x86_ldub_code(env, s);
bellard77729c22003-11-13 23:09:07 +00005499 mod = (modrm >> 6) & 3;
Richard Henderson8e31d232013-11-06 13:57:45 +10005500 ot = gen_pop_T0(s);
bellard77729c22003-11-13 23:09:07 +00005501 if (mod == 3) {
5502 /* NOTE: order is important for pop %sp */
Richard Henderson8e31d232013-11-06 13:57:45 +10005503 gen_pop_update(s, ot);
bellard14ce26e2005-01-03 23:50:08 +00005504 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005505 gen_op_mov_reg_v(s, ot, rm, s->T0);
bellard77729c22003-11-13 23:09:07 +00005506 } else {
5507 /* NOTE: order is important too for MMU exceptions */
bellard14ce26e2005-01-03 23:50:08 +00005508 s->popl_esp_hack = 1 << ot;
Blue Swirl0af10c82012-09-08 13:26:02 +00005509 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
bellard77729c22003-11-13 23:09:07 +00005510 s->popl_esp_hack = 0;
Richard Henderson8e31d232013-11-06 13:57:45 +10005511 gen_pop_update(s, ot);
bellard77729c22003-11-13 23:09:07 +00005512 }
bellard2c0262a2003-09-30 20:34:21 +00005513 break;
5514 case 0xc8: /* enter */
5515 {
5516 int level;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005517 val = x86_lduw_code(env, s);
5518 level = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005519 gen_enter(s, val, level);
5520 }
5521 break;
5522 case 0xc9: /* leave */
Richard Henderson2045f042015-12-17 11:19:24 -08005523 gen_leave(s);
bellard2c0262a2003-09-30 20:34:21 +00005524 break;
5525 case 0x06: /* push es */
5526 case 0x0e: /* push cs */
5527 case 0x16: /* push ss */
5528 case 0x1e: /* push ds */
bellard14ce26e2005-01-03 23:50:08 +00005529 if (CODE64(s))
5530 goto illegal_op;
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005531 gen_op_movl_T0_seg(s, b >> 3);
5532 gen_push_v(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005533 break;
5534 case 0x1a0: /* push fs */
5535 case 0x1a8: /* push gs */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005536 gen_op_movl_T0_seg(s, (b >> 3) & 7);
5537 gen_push_v(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005538 break;
5539 case 0x07: /* pop es */
5540 case 0x17: /* pop ss */
5541 case 0x1f: /* pop ds */
bellard14ce26e2005-01-03 23:50:08 +00005542 if (CODE64(s))
5543 goto illegal_op;
bellard2c0262a2003-09-30 20:34:21 +00005544 reg = b >> 3;
Richard Henderson8e31d232013-11-06 13:57:45 +10005545 ot = gen_pop_T0(s);
Pavel Dovgalyuk100ec092015-07-10 12:57:36 +03005546 gen_movl_seg_T0(s, reg);
Richard Henderson8e31d232013-11-06 13:57:45 +10005547 gen_pop_update(s, ot);
Richard Hendersonf083d922016-03-02 21:16:51 -08005548 /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03005549 if (s->base.is_jmp) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04005550 gen_jmp_im(s, s->pc - s->cs_base);
Richard Hendersonf083d922016-03-02 21:16:51 -08005551 if (reg == R_SS) {
Richard Hendersonc1de1a12021-05-14 10:13:17 -05005552 s->flags &= ~HF_TF_MASK;
Richard Hendersonf083d922016-03-02 21:16:51 -08005553 gen_eob_inhibit_irq(s, true);
5554 } else {
5555 gen_eob(s);
5556 }
bellard2c0262a2003-09-30 20:34:21 +00005557 }
5558 break;
5559 case 0x1a1: /* pop fs */
5560 case 0x1a9: /* pop gs */
Richard Henderson8e31d232013-11-06 13:57:45 +10005561 ot = gen_pop_T0(s);
Pavel Dovgalyuk100ec092015-07-10 12:57:36 +03005562 gen_movl_seg_T0(s, (b >> 3) & 7);
Richard Henderson8e31d232013-11-06 13:57:45 +10005563 gen_pop_update(s, ot);
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03005564 if (s->base.is_jmp) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04005565 gen_jmp_im(s, s->pc - s->cs_base);
bellard2c0262a2003-09-30 20:34:21 +00005566 gen_eob(s);
5567 }
5568 break;
5569
5570 /**************************/
5571 /* mov */
5572 case 0x88:
5573 case 0x89: /* mov Gv, Ev */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005574 ot = mo_b_d(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005575 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005576 reg = ((modrm >> 3) & 7) | REX_R(s);
ths3b46e622007-09-17 08:09:54 +00005577
bellard2c0262a2003-09-30 20:34:21 +00005578 /* generate a generic store */
Blue Swirl0af10c82012-09-08 13:26:02 +00005579 gen_ldst_modrm(env, s, modrm, ot, reg, 1);
bellard2c0262a2003-09-30 20:34:21 +00005580 break;
5581 case 0xc6:
5582 case 0xc7: /* mov Ev, Iv */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005583 ot = mo_b_d(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005584 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005585 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00005586 if (mod != 3) {
5587 s->rip_offset = insn_const_size(ot);
Richard Henderson4eeb3932013-11-02 08:55:59 -10005588 gen_lea_modrm(env, s, modrm);
bellard14ce26e2005-01-03 23:50:08 +00005589 }
Blue Swirl0af10c82012-09-08 13:26:02 +00005590 val = insn_get(env, s, ot);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005591 tcg_gen_movi_tl(s->T0, val);
Richard Hendersonfd8ca9f2013-11-02 08:12:01 -10005592 if (mod != 3) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005593 gen_op_st_v(s, ot, s->T0, s->A0);
Richard Hendersonfd8ca9f2013-11-02 08:12:01 -10005594 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005595 gen_op_mov_reg_v(s, ot, (modrm & 7) | REX_B(s), s->T0);
Richard Hendersonfd8ca9f2013-11-02 08:12:01 -10005596 }
bellard2c0262a2003-09-30 20:34:21 +00005597 break;
5598 case 0x8a:
5599 case 0x8b: /* mov Ev, Gv */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005600 ot = mo_b_d(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005601 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005602 reg = ((modrm >> 3) & 7) | REX_R(s);
ths3b46e622007-09-17 08:09:54 +00005603
Blue Swirl0af10c82012-09-08 13:26:02 +00005604 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005605 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005606 break;
5607 case 0x8e: /* mov seg, Gv */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005608 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005609 reg = (modrm >> 3) & 7;
5610 if (reg >= 6 || reg == R_CS)
5611 goto illegal_op;
Richard Henderson4ba99382013-11-02 09:54:47 -07005612 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
Pavel Dovgalyuk100ec092015-07-10 12:57:36 +03005613 gen_movl_seg_T0(s, reg);
Richard Hendersonf083d922016-03-02 21:16:51 -08005614 /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03005615 if (s->base.is_jmp) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04005616 gen_jmp_im(s, s->pc - s->cs_base);
Richard Hendersonf083d922016-03-02 21:16:51 -08005617 if (reg == R_SS) {
Richard Hendersonc1de1a12021-05-14 10:13:17 -05005618 s->flags &= ~HF_TF_MASK;
Richard Hendersonf083d922016-03-02 21:16:51 -08005619 gen_eob_inhibit_irq(s, true);
5620 } else {
5621 gen_eob(s);
5622 }
bellard2c0262a2003-09-30 20:34:21 +00005623 }
5624 break;
5625 case 0x8c: /* mov Gv, seg */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005626 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005627 reg = (modrm >> 3) & 7;
5628 mod = (modrm >> 6) & 3;
5629 if (reg >= 6)
5630 goto illegal_op;
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005631 gen_op_movl_T0_seg(s, reg);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005632 ot = mod == 3 ? dflag : MO_16;
Blue Swirl0af10c82012-09-08 13:26:02 +00005633 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
bellard2c0262a2003-09-30 20:34:21 +00005634 break;
5635
5636 case 0x1b6: /* movzbS Gv, Eb */
5637 case 0x1b7: /* movzwS Gv, Eb */
5638 case 0x1be: /* movsbS Gv, Eb */
5639 case 0x1bf: /* movswS Gv, Eb */
5640 {
Tony Nguyen14776ab2019-08-24 04:10:58 +10005641 MemOp d_ot;
5642 MemOp s_ot;
Richard Hendersonc8fbc472013-11-02 08:28:40 -10005643
bellard2c0262a2003-09-30 20:34:21 +00005644 /* d_ot is the size of destination */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005645 d_ot = dflag;
bellard2c0262a2003-09-30 20:34:21 +00005646 /* ot is the size of source */
Richard Henderson4ba99382013-11-02 09:54:47 -07005647 ot = (b & 1) + MO_8;
Richard Hendersonc8fbc472013-11-02 08:28:40 -10005648 /* s_ot is the sign+size of source */
5649 s_ot = b & 8 ? MO_SIGN | ot : ot;
5650
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005651 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005652 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard2c0262a2003-09-30 20:34:21 +00005653 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00005654 rm = (modrm & 7) | REX_B(s);
ths3b46e622007-09-17 08:09:54 +00005655
bellard2c0262a2003-09-30 20:34:21 +00005656 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005657 if (s_ot == MO_SB && byte_reg_is_xH(s, rm)) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005658 tcg_gen_sextract_tl(s->T0, cpu_regs[rm - 4], 8, 8);
Richard Henderson04fc2f12016-10-15 11:54:17 -05005659 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005660 gen_op_mov_v_reg(s, ot, s->T0, rm);
Richard Henderson04fc2f12016-10-15 11:54:17 -05005661 switch (s_ot) {
5662 case MO_UB:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005663 tcg_gen_ext8u_tl(s->T0, s->T0);
Richard Henderson04fc2f12016-10-15 11:54:17 -05005664 break;
5665 case MO_SB:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005666 tcg_gen_ext8s_tl(s->T0, s->T0);
Richard Henderson04fc2f12016-10-15 11:54:17 -05005667 break;
5668 case MO_UW:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005669 tcg_gen_ext16u_tl(s->T0, s->T0);
Richard Henderson04fc2f12016-10-15 11:54:17 -05005670 break;
5671 default:
5672 case MO_SW:
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005673 tcg_gen_ext16s_tl(s->T0, s->T0);
Richard Henderson04fc2f12016-10-15 11:54:17 -05005674 break;
5675 }
bellard2c0262a2003-09-30 20:34:21 +00005676 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005677 gen_op_mov_reg_v(s, d_ot, reg, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005678 } else {
Richard Henderson4eeb3932013-11-02 08:55:59 -10005679 gen_lea_modrm(env, s, modrm);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005680 gen_op_ld_v(s, s_ot, s->T0, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005681 gen_op_mov_reg_v(s, d_ot, reg, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005682 }
5683 }
5684 break;
5685
5686 case 0x8d: /* lea */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005687 modrm = x86_ldub_code(env, s);
bellard3a1d9b82004-02-16 22:10:33 +00005688 mod = (modrm >> 6) & 3;
5689 if (mod == 3)
5690 goto illegal_op;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005691 reg = ((modrm >> 3) & 7) | REX_R(s);
Richard Hendersona074ce42015-07-09 08:22:01 +01005692 {
5693 AddressParts a = gen_lea_modrm_0(env, s, modrm);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005694 TCGv ea = gen_lea_modrm_1(s, a);
Paolo Bonzini620abfb2016-10-12 09:23:39 +02005695 gen_lea_v_seg(s, s->aflag, ea, -1, -1);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005696 gen_op_mov_reg_v(s, dflag, reg, s->A0);
Richard Hendersona074ce42015-07-09 08:22:01 +01005697 }
bellard2c0262a2003-09-30 20:34:21 +00005698 break;
ths3b46e622007-09-17 08:09:54 +00005699
bellard2c0262a2003-09-30 20:34:21 +00005700 case 0xa0: /* mov EAX, Ov */
5701 case 0xa1:
5702 case 0xa2: /* mov Ov, EAX */
5703 case 0xa3:
bellard2c0262a2003-09-30 20:34:21 +00005704 {
bellard14ce26e2005-01-03 23:50:08 +00005705 target_ulong offset_addr;
5706
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005707 ot = mo_b_d(b, dflag);
Richard Henderson1d71ddb2013-11-06 08:27:33 +10005708 switch (s->aflag) {
bellard14ce26e2005-01-03 23:50:08 +00005709#ifdef TARGET_X86_64
Richard Henderson1d71ddb2013-11-06 08:27:33 +10005710 case MO_64:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005711 offset_addr = x86_ldq_code(env, s);
Richard Henderson1d71ddb2013-11-06 08:27:33 +10005712 break;
bellard14ce26e2005-01-03 23:50:08 +00005713#endif
Richard Henderson1d71ddb2013-11-06 08:27:33 +10005714 default:
5715 offset_addr = insn_get(env, s, s->aflag);
5716 break;
bellard14ce26e2005-01-03 23:50:08 +00005717 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005718 tcg_gen_movi_tl(s->A0, offset_addr);
bellard664e0f12005-01-08 18:58:29 +00005719 gen_add_A0_ds_seg(s);
bellard14ce26e2005-01-03 23:50:08 +00005720 if ((b & 2) == 0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005721 gen_op_ld_v(s, ot, s->T0, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005722 gen_op_mov_reg_v(s, ot, R_EAX, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005723 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005724 gen_op_mov_v_reg(s, ot, s->T0, R_EAX);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005725 gen_op_st_v(s, ot, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00005726 }
bellard2c0262a2003-09-30 20:34:21 +00005727 }
5728 break;
5729 case 0xd7: /* xlat */
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005730 tcg_gen_mov_tl(s->A0, cpu_regs[R_EBX]);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005731 tcg_gen_ext8u_tl(s->T0, cpu_regs[R_EAX]);
5732 tcg_gen_add_tl(s->A0, s->A0, s->T0);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04005733 gen_extu(s->aflag, s->A0);
bellard664e0f12005-01-08 18:58:29 +00005734 gen_add_A0_ds_seg(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005735 gen_op_ld_v(s, MO_8, s->T0, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005736 gen_op_mov_reg_v(s, MO_8, R_EAX, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005737 break;
5738 case 0xb0 ... 0xb7: /* mov R, Ib */
Richard Henderson4ba99382013-11-02 09:54:47 -07005739 val = insn_get(env, s, MO_8);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005740 tcg_gen_movi_tl(s->T0, val);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005741 gen_op_mov_reg_v(s, MO_8, (b & 7) | REX_B(s), s->T0);
bellard2c0262a2003-09-30 20:34:21 +00005742 break;
5743 case 0xb8 ... 0xbf: /* mov R, Iv */
bellard14ce26e2005-01-03 23:50:08 +00005744#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005745 if (dflag == MO_64) {
bellard14ce26e2005-01-03 23:50:08 +00005746 uint64_t tmp;
5747 /* 64 bit case */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005748 tmp = x86_ldq_code(env, s);
bellard14ce26e2005-01-03 23:50:08 +00005749 reg = (b & 7) | REX_B(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005750 tcg_gen_movi_tl(s->T0, tmp);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005751 gen_op_mov_reg_v(s, MO_64, reg, s->T0);
ths5fafdf22007-09-16 21:08:06 +00005752 } else
bellard14ce26e2005-01-03 23:50:08 +00005753#endif
5754 {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005755 ot = dflag;
Blue Swirl0af10c82012-09-08 13:26:02 +00005756 val = insn_get(env, s, ot);
bellard14ce26e2005-01-03 23:50:08 +00005757 reg = (b & 7) | REX_B(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005758 tcg_gen_movi_tl(s->T0, val);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005759 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard14ce26e2005-01-03 23:50:08 +00005760 }
bellard2c0262a2003-09-30 20:34:21 +00005761 break;
5762
5763 case 0x91 ... 0x97: /* xchg R, EAX */
Richard Henderson74180272010-07-01 09:42:21 -07005764 do_xchg_reg_eax:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005765 ot = dflag;
bellard14ce26e2005-01-03 23:50:08 +00005766 reg = (b & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00005767 rm = R_EAX;
5768 goto do_xchg_reg;
5769 case 0x86:
5770 case 0x87: /* xchg Ev, Gv */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005771 ot = mo_b_d(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005772 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005773 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard2c0262a2003-09-30 20:34:21 +00005774 mod = (modrm >> 6) & 3;
5775 if (mod == 3) {
bellard14ce26e2005-01-03 23:50:08 +00005776 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00005777 do_xchg_reg:
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005778 gen_op_mov_v_reg(s, ot, s->T0, reg);
5779 gen_op_mov_v_reg(s, ot, s->T1, rm);
5780 gen_op_mov_reg_v(s, ot, rm, s->T0);
5781 gen_op_mov_reg_v(s, ot, reg, s->T1);
bellard2c0262a2003-09-30 20:34:21 +00005782 } else {
Richard Henderson4eeb3932013-11-02 08:55:59 -10005783 gen_lea_modrm(env, s, modrm);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005784 gen_op_mov_v_reg(s, ot, s->T0, reg);
bellard2c0262a2003-09-30 20:34:21 +00005785 /* for xchg, lock is implicit */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005786 tcg_gen_atomic_xchg_tl(s->T1, s->A0, s->T0,
Emilio G. Cotaea97ebe2016-06-27 15:02:04 -04005787 s->mem_index, ot | MO_LE);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005788 gen_op_mov_reg_v(s, ot, reg, s->T1);
bellard2c0262a2003-09-30 20:34:21 +00005789 }
5790 break;
5791 case 0xc4: /* les Gv */
Richard Henderson701ed212013-01-11 11:35:02 -08005792 /* In CODE64 this is VEX3; see above. */
bellard2c0262a2003-09-30 20:34:21 +00005793 op = R_ES;
5794 goto do_lxx;
5795 case 0xc5: /* lds Gv */
Richard Henderson701ed212013-01-11 11:35:02 -08005796 /* In CODE64 this is VEX2; see above. */
bellard2c0262a2003-09-30 20:34:21 +00005797 op = R_DS;
5798 goto do_lxx;
5799 case 0x1b2: /* lss Gv */
5800 op = R_SS;
5801 goto do_lxx;
5802 case 0x1b4: /* lfs Gv */
5803 op = R_FS;
5804 goto do_lxx;
5805 case 0x1b5: /* lgs Gv */
5806 op = R_GS;
5807 do_lxx:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005808 ot = dflag != MO_16 ? MO_32 : MO_16;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005809 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005810 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard2c0262a2003-09-30 20:34:21 +00005811 mod = (modrm >> 6) & 3;
5812 if (mod == 3)
5813 goto illegal_op;
Richard Henderson4eeb3932013-11-02 08:55:59 -10005814 gen_lea_modrm(env, s, modrm);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04005815 gen_op_ld_v(s, ot, s->T1, s->A0);
Richard Henderson830a19a2013-11-07 09:13:27 +10005816 gen_add_A0_im(s, 1 << ot);
bellard2c0262a2003-09-30 20:34:21 +00005817 /* load the segment first to handle exceptions properly */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04005818 gen_op_ld_v(s, MO_16, s->T0, s->A0);
Pavel Dovgalyuk100ec092015-07-10 12:57:36 +03005819 gen_movl_seg_T0(s, op);
bellard2c0262a2003-09-30 20:34:21 +00005820 /* then put the data */
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005821 gen_op_mov_reg_v(s, ot, reg, s->T1);
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03005822 if (s->base.is_jmp) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04005823 gen_jmp_im(s, s->pc - s->cs_base);
bellard2c0262a2003-09-30 20:34:21 +00005824 gen_eob(s);
5825 }
5826 break;
ths3b46e622007-09-17 08:09:54 +00005827
bellard2c0262a2003-09-30 20:34:21 +00005828 /************************/
5829 /* shifts */
5830 case 0xc0:
5831 case 0xc1:
5832 /* shift Ev,Ib */
5833 shift = 2;
5834 grp2:
5835 {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005836 ot = mo_b_d(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005837 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005838 mod = (modrm >> 6) & 3;
bellard2c0262a2003-09-30 20:34:21 +00005839 op = (modrm >> 3) & 7;
ths3b46e622007-09-17 08:09:54 +00005840
bellard2c0262a2003-09-30 20:34:21 +00005841 if (mod != 3) {
bellard14ce26e2005-01-03 23:50:08 +00005842 if (shift == 2) {
5843 s->rip_offset = 1;
5844 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10005845 gen_lea_modrm(env, s, modrm);
bellard2c0262a2003-09-30 20:34:21 +00005846 opreg = OR_TMP0;
5847 } else {
bellard14ce26e2005-01-03 23:50:08 +00005848 opreg = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00005849 }
5850
5851 /* simpler op */
5852 if (shift == 0) {
5853 gen_shift(s, op, ot, opreg, OR_ECX);
5854 } else {
5855 if (shift == 2) {
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005856 shift = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005857 }
5858 gen_shifti(s, op, ot, opreg, shift);
5859 }
5860 }
5861 break;
5862 case 0xd0:
5863 case 0xd1:
5864 /* shift Ev,1 */
5865 shift = 1;
5866 goto grp2;
5867 case 0xd2:
5868 case 0xd3:
5869 /* shift Ev,cl */
5870 shift = 0;
5871 goto grp2;
5872
5873 case 0x1a4: /* shld imm */
5874 op = 0;
5875 shift = 1;
5876 goto do_shiftd;
5877 case 0x1a5: /* shld cl */
5878 op = 0;
5879 shift = 0;
5880 goto do_shiftd;
5881 case 0x1ac: /* shrd imm */
5882 op = 1;
5883 shift = 1;
5884 goto do_shiftd;
5885 case 0x1ad: /* shrd cl */
5886 op = 1;
5887 shift = 0;
5888 do_shiftd:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10005889 ot = dflag;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005890 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00005891 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00005892 rm = (modrm & 7) | REX_B(s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05005893 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard2c0262a2003-09-30 20:34:21 +00005894 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10005895 gen_lea_modrm(env, s, modrm);
bellardb6abf972008-05-17 12:44:31 +00005896 opreg = OR_TMP0;
bellard2c0262a2003-09-30 20:34:21 +00005897 } else {
bellardb6abf972008-05-17 12:44:31 +00005898 opreg = rm;
bellard2c0262a2003-09-30 20:34:21 +00005899 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04005900 gen_op_mov_v_reg(s, ot, s->T1, reg);
ths3b46e622007-09-17 08:09:54 +00005901
bellard2c0262a2003-09-30 20:34:21 +00005902 if (shift) {
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02005903 TCGv imm = tcg_const_tl(x86_ldub_code(env, s));
Paolo Bonzini3b9d3cf2012-10-12 15:04:10 +02005904 gen_shiftd_rm_T1(s, ot, opreg, op, imm);
5905 tcg_temp_free(imm);
bellard2c0262a2003-09-30 20:34:21 +00005906 } else {
Paolo Bonzini3b9d3cf2012-10-12 15:04:10 +02005907 gen_shiftd_rm_T1(s, ot, opreg, op, cpu_regs[R_ECX]);
bellard2c0262a2003-09-30 20:34:21 +00005908 }
bellard2c0262a2003-09-30 20:34:21 +00005909 break;
5910
5911 /************************/
5912 /* floats */
ths5fafdf22007-09-16 21:08:06 +00005913 case 0xd8 ... 0xdf:
Ziqiao Kong505910a2021-05-30 23:01:12 +08005914 {
Ziqiao Kong84abdd72021-05-30 23:01:14 +08005915 bool update_fip = true;
5916
Ziqiao Kong505910a2021-05-30 23:01:12 +08005917 if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
5918 /* if CR0.EM or CR0.TS are set, generate an FPU exception */
5919 /* XXX: what to do if illegal op ? */
5920 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
bellard2c0262a2003-09-30 20:34:21 +00005921 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08005922 }
5923 modrm = x86_ldub_code(env, s);
5924 mod = (modrm >> 6) & 3;
5925 rm = modrm & 7;
5926 op = ((b & 7) << 3) | ((modrm >> 3) & 7);
5927 if (mod != 3) {
5928 /* memory op */
Ziqiao Kong84abdd72021-05-30 23:01:14 +08005929 AddressParts a = gen_lea_modrm_0(env, s, modrm);
5930 TCGv ea = gen_lea_modrm_1(s, a);
5931 TCGv last_addr = tcg_temp_new();
5932 bool update_fdp = true;
5933
5934 tcg_gen_mov_tl(last_addr, ea);
5935 gen_lea_v_seg(s, s->aflag, ea, a.def_seg, s->override);
5936
Ziqiao Kong505910a2021-05-30 23:01:12 +08005937 switch (op) {
5938 case 0x00 ... 0x07: /* fxxxs */
5939 case 0x10 ... 0x17: /* fixxxl */
5940 case 0x20 ... 0x27: /* fxxxl */
5941 case 0x30 ... 0x37: /* fixxx */
5942 {
5943 int op1;
5944 op1 = op & 7;
5945
5946 switch (op >> 4) {
5947 case 0:
5948 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
5949 s->mem_index, MO_LEUL);
5950 gen_helper_flds_FT0(cpu_env, s->tmp2_i32);
5951 break;
5952 case 1:
5953 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
5954 s->mem_index, MO_LEUL);
5955 gen_helper_fildl_FT0(cpu_env, s->tmp2_i32);
5956 break;
5957 case 2:
5958 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
5959 s->mem_index, MO_LEQ);
5960 gen_helper_fldl_FT0(cpu_env, s->tmp1_i64);
5961 break;
5962 case 3:
5963 default:
5964 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
5965 s->mem_index, MO_LESW);
5966 gen_helper_fildl_FT0(cpu_env, s->tmp2_i32);
5967 break;
5968 }
5969
5970 gen_helper_fp_arith_ST0_FT0(op1);
5971 if (op1 == 3) {
5972 /* fcomp needs pop */
5973 gen_helper_fpop(cpu_env);
5974 }
5975 }
5976 break;
5977 case 0x08: /* flds */
5978 case 0x0a: /* fsts */
5979 case 0x0b: /* fstps */
5980 case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */
5981 case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */
5982 case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */
5983 switch (op & 7) {
bellard2c0262a2003-09-30 20:34:21 +00005984 case 0:
Ziqiao Kong505910a2021-05-30 23:01:12 +08005985 switch (op >> 4) {
5986 case 0:
5987 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
5988 s->mem_index, MO_LEUL);
5989 gen_helper_flds_ST0(cpu_env, s->tmp2_i32);
5990 break;
5991 case 1:
5992 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
5993 s->mem_index, MO_LEUL);
5994 gen_helper_fildl_ST0(cpu_env, s->tmp2_i32);
5995 break;
5996 case 2:
5997 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
5998 s->mem_index, MO_LEQ);
5999 gen_helper_fldl_ST0(cpu_env, s->tmp1_i64);
6000 break;
6001 case 3:
6002 default:
6003 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
6004 s->mem_index, MO_LESW);
6005 gen_helper_fildl_ST0(cpu_env, s->tmp2_i32);
6006 break;
6007 }
bellard2c0262a2003-09-30 20:34:21 +00006008 break;
6009 case 1:
Ziqiao Kong505910a2021-05-30 23:01:12 +08006010 /* XXX: the corresponding CPUID bit must be tested ! */
6011 switch (op >> 4) {
6012 case 1:
6013 gen_helper_fisttl_ST0(s->tmp2_i32, cpu_env);
6014 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
6015 s->mem_index, MO_LEUL);
6016 break;
6017 case 2:
6018 gen_helper_fisttll_ST0(s->tmp1_i64, cpu_env);
6019 tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
6020 s->mem_index, MO_LEQ);
6021 break;
6022 case 3:
6023 default:
6024 gen_helper_fistt_ST0(s->tmp2_i32, cpu_env);
6025 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
6026 s->mem_index, MO_LEUW);
6027 break;
6028 }
6029 gen_helper_fpop(cpu_env);
bellard2c0262a2003-09-30 20:34:21 +00006030 break;
bellard2c0262a2003-09-30 20:34:21 +00006031 default:
Ziqiao Kong505910a2021-05-30 23:01:12 +08006032 switch (op >> 4) {
6033 case 0:
6034 gen_helper_fsts_ST0(s->tmp2_i32, cpu_env);
6035 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
6036 s->mem_index, MO_LEUL);
6037 break;
6038 case 1:
6039 gen_helper_fistl_ST0(s->tmp2_i32, cpu_env);
6040 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
6041 s->mem_index, MO_LEUL);
6042 break;
6043 case 2:
6044 gen_helper_fstl_ST0(s->tmp1_i64, cpu_env);
6045 tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
6046 s->mem_index, MO_LEQ);
6047 break;
6048 case 3:
6049 default:
6050 gen_helper_fist_ST0(s->tmp2_i32, cpu_env);
6051 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
6052 s->mem_index, MO_LEUW);
6053 break;
6054 }
6055 if ((op & 7) == 3) {
6056 gen_helper_fpop(cpu_env);
6057 }
bellard2c0262a2003-09-30 20:34:21 +00006058 break;
6059 }
6060 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006061 case 0x0c: /* fldenv mem */
6062 gen_helper_fldenv(cpu_env, s->A0,
6063 tcg_const_i32(dflag - 1));
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006064 update_fip = update_fdp = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006065 break;
6066 case 0x0d: /* fldcw mem */
6067 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0,
6068 s->mem_index, MO_LEUW);
6069 gen_helper_fldcw(cpu_env, s->tmp2_i32);
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006070 update_fip = update_fdp = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006071 break;
6072 case 0x0e: /* fnstenv mem */
6073 gen_helper_fstenv(cpu_env, s->A0,
6074 tcg_const_i32(dflag - 1));
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006075 update_fip = update_fdp = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006076 break;
6077 case 0x0f: /* fnstcw mem */
6078 gen_helper_fnstcw(s->tmp2_i32, cpu_env);
6079 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
6080 s->mem_index, MO_LEUW);
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006081 update_fip = update_fdp = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006082 break;
6083 case 0x1d: /* fldt mem */
6084 gen_helper_fldt_ST0(cpu_env, s->A0);
6085 break;
6086 case 0x1f: /* fstpt mem */
6087 gen_helper_fstt_ST0(cpu_env, s->A0);
6088 gen_helper_fpop(cpu_env);
6089 break;
6090 case 0x2c: /* frstor mem */
6091 gen_helper_frstor(cpu_env, s->A0,
6092 tcg_const_i32(dflag - 1));
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006093 update_fip = update_fdp = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006094 break;
6095 case 0x2e: /* fnsave mem */
6096 gen_helper_fsave(cpu_env, s->A0,
6097 tcg_const_i32(dflag - 1));
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006098 update_fip = update_fdp = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006099 break;
6100 case 0x2f: /* fnstsw mem */
6101 gen_helper_fnstsw(s->tmp2_i32, cpu_env);
6102 tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0,
6103 s->mem_index, MO_LEUW);
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006104 update_fip = update_fdp = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006105 break;
6106 case 0x3c: /* fbld */
6107 gen_helper_fbld_ST0(cpu_env, s->A0);
6108 break;
6109 case 0x3e: /* fbstp */
6110 gen_helper_fbst_ST0(cpu_env, s->A0);
6111 gen_helper_fpop(cpu_env);
6112 break;
6113 case 0x3d: /* fildll */
6114 tcg_gen_qemu_ld_i64(s->tmp1_i64, s->A0,
6115 s->mem_index, MO_LEQ);
6116 gen_helper_fildll_ST0(cpu_env, s->tmp1_i64);
6117 break;
6118 case 0x3f: /* fistpll */
6119 gen_helper_fistll_ST0(s->tmp1_i64, cpu_env);
6120 tcg_gen_qemu_st_i64(s->tmp1_i64, s->A0,
6121 s->mem_index, MO_LEQ);
Blue Swirld3eb5ea2012-04-28 21:28:09 +00006122 gen_helper_fpop(cpu_env);
bellard465e9832006-04-23 21:54:01 +00006123 break;
bellard2c0262a2003-09-30 20:34:21 +00006124 default:
Ziqiao Kong505910a2021-05-30 23:01:12 +08006125 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00006126 }
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006127
6128 if (update_fdp) {
6129 int last_seg = s->override >= 0 ? s->override : a.def_seg;
6130
6131 tcg_gen_ld_i32(s->tmp2_i32, cpu_env,
6132 offsetof(CPUX86State,
6133 segs[last_seg].selector));
6134 tcg_gen_st16_i32(s->tmp2_i32, cpu_env,
6135 offsetof(CPUX86State, fpds));
6136 tcg_gen_st_tl(last_addr, cpu_env,
6137 offsetof(CPUX86State, fpdp));
6138 }
6139 tcg_temp_free(last_addr);
Ziqiao Kong505910a2021-05-30 23:01:12 +08006140 } else {
6141 /* register float ops */
6142 opreg = rm;
bellard2c0262a2003-09-30 20:34:21 +00006143
Ziqiao Kong505910a2021-05-30 23:01:12 +08006144 switch (op) {
6145 case 0x08: /* fld sti */
6146 gen_helper_fpush(cpu_env);
6147 gen_helper_fmov_ST0_STN(cpu_env,
6148 tcg_const_i32((opreg + 1) & 7));
bellard2c0262a2003-09-30 20:34:21 +00006149 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006150 case 0x09: /* fxchg sti */
6151 case 0x29: /* fxchg4 sti, undocumented op */
6152 case 0x39: /* fxchg7 sti, undocumented op */
6153 gen_helper_fxchg_ST0_STN(cpu_env, tcg_const_i32(opreg));
bellard2c0262a2003-09-30 20:34:21 +00006154 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006155 case 0x0a: /* grp d9/2 */
6156 switch (rm) {
6157 case 0: /* fnop */
6158 /* check exceptions (FreeBSD FPU probe) */
6159 gen_helper_fwait(cpu_env);
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006160 update_fip = false;
bellard2c0262a2003-09-30 20:34:21 +00006161 break;
6162 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08006163 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00006164 }
bellard2c0262a2003-09-30 20:34:21 +00006165 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006166 case 0x0c: /* grp d9/4 */
6167 switch (rm) {
6168 case 0: /* fchs */
6169 gen_helper_fchs_ST0(cpu_env);
6170 break;
6171 case 1: /* fabs */
6172 gen_helper_fabs_ST0(cpu_env);
6173 break;
6174 case 4: /* ftst */
6175 gen_helper_fldz_FT0(cpu_env);
6176 gen_helper_fcom_ST0_FT0(cpu_env);
6177 break;
6178 case 5: /* fxam */
6179 gen_helper_fxam_ST0(cpu_env);
6180 break;
6181 default:
6182 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00006183 }
bellard2c0262a2003-09-30 20:34:21 +00006184 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006185 case 0x0d: /* grp d9/5 */
6186 {
6187 switch (rm) {
6188 case 0:
6189 gen_helper_fpush(cpu_env);
6190 gen_helper_fld1_ST0(cpu_env);
6191 break;
6192 case 1:
6193 gen_helper_fpush(cpu_env);
6194 gen_helper_fldl2t_ST0(cpu_env);
6195 break;
6196 case 2:
6197 gen_helper_fpush(cpu_env);
6198 gen_helper_fldl2e_ST0(cpu_env);
6199 break;
6200 case 3:
6201 gen_helper_fpush(cpu_env);
6202 gen_helper_fldpi_ST0(cpu_env);
6203 break;
6204 case 4:
6205 gen_helper_fpush(cpu_env);
6206 gen_helper_fldlg2_ST0(cpu_env);
6207 break;
6208 case 5:
6209 gen_helper_fpush(cpu_env);
6210 gen_helper_fldln2_ST0(cpu_env);
6211 break;
6212 case 6:
6213 gen_helper_fpush(cpu_env);
6214 gen_helper_fldz_ST0(cpu_env);
6215 break;
6216 default:
6217 goto unknown_op;
6218 }
6219 }
bellard2c0262a2003-09-30 20:34:21 +00006220 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006221 case 0x0e: /* grp d9/6 */
6222 switch (rm) {
6223 case 0: /* f2xm1 */
6224 gen_helper_f2xm1(cpu_env);
6225 break;
6226 case 1: /* fyl2x */
6227 gen_helper_fyl2x(cpu_env);
6228 break;
6229 case 2: /* fptan */
6230 gen_helper_fptan(cpu_env);
6231 break;
6232 case 3: /* fpatan */
6233 gen_helper_fpatan(cpu_env);
6234 break;
6235 case 4: /* fxtract */
6236 gen_helper_fxtract(cpu_env);
6237 break;
6238 case 5: /* fprem1 */
6239 gen_helper_fprem1(cpu_env);
6240 break;
6241 case 6: /* fdecstp */
6242 gen_helper_fdecstp(cpu_env);
6243 break;
6244 default:
6245 case 7: /* fincstp */
6246 gen_helper_fincstp(cpu_env);
6247 break;
6248 }
bellard2c0262a2003-09-30 20:34:21 +00006249 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006250 case 0x0f: /* grp d9/7 */
6251 switch (rm) {
6252 case 0: /* fprem */
6253 gen_helper_fprem(cpu_env);
6254 break;
6255 case 1: /* fyl2xp1 */
6256 gen_helper_fyl2xp1(cpu_env);
6257 break;
6258 case 2: /* fsqrt */
6259 gen_helper_fsqrt(cpu_env);
6260 break;
6261 case 3: /* fsincos */
6262 gen_helper_fsincos(cpu_env);
6263 break;
6264 case 5: /* fscale */
6265 gen_helper_fscale(cpu_env);
6266 break;
6267 case 4: /* frndint */
6268 gen_helper_frndint(cpu_env);
6269 break;
6270 case 6: /* fsin */
6271 gen_helper_fsin(cpu_env);
6272 break;
6273 default:
6274 case 7: /* fcos */
6275 gen_helper_fcos(cpu_env);
6276 break;
6277 }
bellard2c0262a2003-09-30 20:34:21 +00006278 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006279 case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
6280 case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
6281 case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
6282 {
6283 int op1;
6284
6285 op1 = op & 7;
6286 if (op >= 0x20) {
6287 gen_helper_fp_arith_STN_ST0(op1, opreg);
6288 if (op >= 0x30) {
6289 gen_helper_fpop(cpu_env);
6290 }
6291 } else {
6292 gen_helper_fmov_FT0_STN(cpu_env,
6293 tcg_const_i32(opreg));
6294 gen_helper_fp_arith_ST0_FT0(op1);
6295 }
6296 }
bellard2c0262a2003-09-30 20:34:21 +00006297 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006298 case 0x02: /* fcom */
6299 case 0x22: /* fcom2, undocumented op */
6300 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
6301 gen_helper_fcom_ST0_FT0(cpu_env);
bellard2c0262a2003-09-30 20:34:21 +00006302 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006303 case 0x03: /* fcomp */
6304 case 0x23: /* fcomp3, undocumented op */
6305 case 0x32: /* fcomp5, undocumented op */
6306 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
Blue Swirld3eb5ea2012-04-28 21:28:09 +00006307 gen_helper_fcom_ST0_FT0(cpu_env);
6308 gen_helper_fpop(cpu_env);
bellard2c0262a2003-09-30 20:34:21 +00006309 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006310 case 0x15: /* da/5 */
6311 switch (rm) {
6312 case 1: /* fucompp */
6313 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1));
6314 gen_helper_fucom_ST0_FT0(cpu_env);
6315 gen_helper_fpop(cpu_env);
6316 gen_helper_fpop(cpu_env);
6317 break;
6318 default:
6319 goto unknown_op;
6320 }
bellard2c0262a2003-09-30 20:34:21 +00006321 break;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006322 case 0x1c:
6323 switch (rm) {
6324 case 0: /* feni (287 only, just do nop here) */
6325 break;
6326 case 1: /* fdisi (287 only, just do nop here) */
6327 break;
6328 case 2: /* fclex */
6329 gen_helper_fclex(cpu_env);
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006330 update_fip = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006331 break;
6332 case 3: /* fninit */
6333 gen_helper_fninit(cpu_env);
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006334 update_fip = false;
Ziqiao Kong505910a2021-05-30 23:01:12 +08006335 break;
6336 case 4: /* fsetpm (287 only, just do nop here) */
6337 break;
6338 default:
6339 goto unknown_op;
6340 }
6341 break;
6342 case 0x1d: /* fucomi */
Peter Maydellbff93282013-07-15 18:21:40 +01006343 if (!(s->cpuid_features & CPUID_CMOV)) {
6344 goto illegal_op;
6345 }
Ziqiao Kong505910a2021-05-30 23:01:12 +08006346 gen_update_cc_op(s);
6347 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
6348 gen_helper_fucomi_ST0_FT0(cpu_env);
6349 set_cc_op(s, CC_OP_EFLAGS);
6350 break;
6351 case 0x1e: /* fcomi */
6352 if (!(s->cpuid_features & CPUID_CMOV)) {
6353 goto illegal_op;
6354 }
6355 gen_update_cc_op(s);
6356 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
6357 gen_helper_fcomi_ST0_FT0(cpu_env);
6358 set_cc_op(s, CC_OP_EFLAGS);
6359 break;
6360 case 0x28: /* ffree sti */
6361 gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg));
6362 break;
6363 case 0x2a: /* fst sti */
6364 gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg));
6365 break;
6366 case 0x2b: /* fstp sti */
6367 case 0x0b: /* fstp1 sti, undocumented op */
6368 case 0x3a: /* fstp8 sti, undocumented op */
6369 case 0x3b: /* fstp9 sti, undocumented op */
6370 gen_helper_fmov_STN_ST0(cpu_env, tcg_const_i32(opreg));
6371 gen_helper_fpop(cpu_env);
6372 break;
6373 case 0x2c: /* fucom st(i) */
6374 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
6375 gen_helper_fucom_ST0_FT0(cpu_env);
6376 break;
6377 case 0x2d: /* fucomp st(i) */
6378 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
6379 gen_helper_fucom_ST0_FT0(cpu_env);
6380 gen_helper_fpop(cpu_env);
6381 break;
6382 case 0x33: /* de/3 */
6383 switch (rm) {
6384 case 1: /* fcompp */
6385 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(1));
6386 gen_helper_fcom_ST0_FT0(cpu_env);
6387 gen_helper_fpop(cpu_env);
6388 gen_helper_fpop(cpu_env);
6389 break;
6390 default:
6391 goto unknown_op;
6392 }
6393 break;
6394 case 0x38: /* ffreep sti, undocumented op */
6395 gen_helper_ffree_STN(cpu_env, tcg_const_i32(opreg));
6396 gen_helper_fpop(cpu_env);
6397 break;
6398 case 0x3c: /* df/4 */
6399 switch (rm) {
6400 case 0:
6401 gen_helper_fnstsw(s->tmp2_i32, cpu_env);
6402 tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32);
6403 gen_op_mov_reg_v(s, MO_16, R_EAX, s->T0);
6404 break;
6405 default:
6406 goto unknown_op;
6407 }
6408 break;
6409 case 0x3d: /* fucomip */
6410 if (!(s->cpuid_features & CPUID_CMOV)) {
6411 goto illegal_op;
6412 }
6413 gen_update_cc_op(s);
6414 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
6415 gen_helper_fucomi_ST0_FT0(cpu_env);
6416 gen_helper_fpop(cpu_env);
6417 set_cc_op(s, CC_OP_EFLAGS);
6418 break;
6419 case 0x3e: /* fcomip */
6420 if (!(s->cpuid_features & CPUID_CMOV)) {
6421 goto illegal_op;
6422 }
6423 gen_update_cc_op(s);
6424 gen_helper_fmov_FT0_STN(cpu_env, tcg_const_i32(opreg));
6425 gen_helper_fcomi_ST0_FT0(cpu_env);
6426 gen_helper_fpop(cpu_env);
6427 set_cc_op(s, CC_OP_EFLAGS);
6428 break;
6429 case 0x10 ... 0x13: /* fcmovxx */
6430 case 0x18 ... 0x1b:
6431 {
6432 int op1;
6433 TCGLabel *l1;
6434 static const uint8_t fcmov_cc[8] = {
6435 (JCC_B << 1),
6436 (JCC_Z << 1),
6437 (JCC_BE << 1),
6438 (JCC_P << 1),
6439 };
6440
6441 if (!(s->cpuid_features & CPUID_CMOV)) {
6442 goto illegal_op;
6443 }
6444 op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1);
6445 l1 = gen_new_label();
6446 gen_jcc1_noeob(s, op1, l1);
6447 gen_helper_fmov_ST0_STN(cpu_env, tcg_const_i32(opreg));
6448 gen_set_label(l1);
6449 }
6450 break;
6451 default:
6452 goto unknown_op;
bellarda2cc3b22003-11-19 22:08:13 +00006453 }
bellard2c0262a2003-09-30 20:34:21 +00006454 }
Ziqiao Kong84abdd72021-05-30 23:01:14 +08006455
6456 if (update_fip) {
6457 tcg_gen_ld_i32(s->tmp2_i32, cpu_env,
6458 offsetof(CPUX86State, segs[R_CS].selector));
6459 tcg_gen_st16_i32(s->tmp2_i32, cpu_env,
6460 offsetof(CPUX86State, fpcs));
6461 tcg_gen_st_tl(tcg_constant_tl(pc_start - s->cs_base),
6462 cpu_env, offsetof(CPUX86State, fpip));
6463 }
bellard2c0262a2003-09-30 20:34:21 +00006464 }
6465 break;
6466 /************************/
6467 /* string ops */
6468
6469 case 0xa4: /* movsS */
6470 case 0xa5:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006471 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00006472 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
6473 gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
6474 } else {
6475 gen_movs(s, ot);
6476 }
6477 break;
ths3b46e622007-09-17 08:09:54 +00006478
bellard2c0262a2003-09-30 20:34:21 +00006479 case 0xaa: /* stosS */
6480 case 0xab:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006481 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00006482 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
6483 gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
6484 } else {
6485 gen_stos(s, ot);
6486 }
6487 break;
6488 case 0xac: /* lodsS */
6489 case 0xad:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006490 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00006491 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
6492 gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
6493 } else {
6494 gen_lods(s, ot);
6495 }
6496 break;
6497 case 0xae: /* scasS */
6498 case 0xaf:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006499 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00006500 if (prefixes & PREFIX_REPNZ) {
6501 gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
6502 } else if (prefixes & PREFIX_REPZ) {
6503 gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
6504 } else {
6505 gen_scas(s, ot);
bellard2c0262a2003-09-30 20:34:21 +00006506 }
6507 break;
6508
6509 case 0xa6: /* cmpsS */
6510 case 0xa7:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006511 ot = mo_b_d(b, dflag);
bellard2c0262a2003-09-30 20:34:21 +00006512 if (prefixes & PREFIX_REPNZ) {
6513 gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
6514 } else if (prefixes & PREFIX_REPZ) {
6515 gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
6516 } else {
6517 gen_cmps(s, ot);
bellard2c0262a2003-09-30 20:34:21 +00006518 }
6519 break;
6520 case 0x6c: /* insS */
6521 case 0x6d:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006522 ot = mo_b_d32(b, dflag);
Richard Henderson1bca40f2021-05-14 10:13:39 -05006523 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
6524 tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
6525 if (!gen_check_io(s, ot, s->tmp2_i32,
6526 SVM_IOIO_TYPE_MASK | SVM_IOIO_STR_MASK)) {
Richard Hendersonbc2e4362021-05-14 10:13:38 -05006527 break;
6528 }
Paolo Bonzini6c9cce12020-06-26 05:19:27 -04006529 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
6530 gen_io_start();
6531 }
bellardf115e912003-11-13 01:43:28 +00006532 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
6533 gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
Paolo Bonzini6c9cce12020-06-26 05:19:27 -04006534 /* jump generated by gen_repz_ins */
bellard2c0262a2003-09-30 20:34:21 +00006535 } else {
bellardf115e912003-11-13 01:43:28 +00006536 gen_ins(s, ot);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006537 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006538 gen_jmp(s, s->pc - s->cs_base);
6539 }
bellard2c0262a2003-09-30 20:34:21 +00006540 }
6541 break;
6542 case 0x6e: /* outsS */
6543 case 0x6f:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006544 ot = mo_b_d32(b, dflag);
Richard Henderson1bca40f2021-05-14 10:13:39 -05006545 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
6546 tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
6547 if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_STR_MASK)) {
Richard Hendersonbc2e4362021-05-14 10:13:38 -05006548 break;
6549 }
Paolo Bonzini6c9cce12020-06-26 05:19:27 -04006550 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
6551 gen_io_start();
6552 }
bellardf115e912003-11-13 01:43:28 +00006553 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
6554 gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
Paolo Bonzini6c9cce12020-06-26 05:19:27 -04006555 /* jump generated by gen_repz_outs */
bellard2c0262a2003-09-30 20:34:21 +00006556 } else {
bellardf115e912003-11-13 01:43:28 +00006557 gen_outs(s, ot);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006558 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006559 gen_jmp(s, s->pc - s->cs_base);
6560 }
bellard2c0262a2003-09-30 20:34:21 +00006561 }
6562 break;
6563
6564 /************************/
6565 /* port I/O */
ths0573fbf2007-09-23 15:28:04 +00006566
bellard2c0262a2003-09-30 20:34:21 +00006567 case 0xe4:
6568 case 0xe5:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006569 ot = mo_b_d32(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006570 val = x86_ldub_code(env, s);
Richard Henderson1bca40f2021-05-14 10:13:39 -05006571 tcg_gen_movi_i32(s->tmp2_i32, val);
6572 if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) {
Richard Hendersonbc2e4362021-05-14 10:13:38 -05006573 break;
6574 }
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006575 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006576 gen_io_start();
Paolo Bonzini7d374352018-12-13 23:37:37 +01006577 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006578 gen_helper_in_func(ot, s->T1, s->tmp2_i32);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04006579 gen_op_mov_reg_v(s, ot, R_EAX, s->T1);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006580 gen_bpt_io(s, s->tmp2_i32, ot);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006581 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006582 gen_jmp(s, s->pc - s->cs_base);
6583 }
bellard2c0262a2003-09-30 20:34:21 +00006584 break;
6585 case 0xe6:
6586 case 0xe7:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006587 ot = mo_b_d32(b, dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006588 val = x86_ldub_code(env, s);
Richard Henderson1bca40f2021-05-14 10:13:39 -05006589 tcg_gen_movi_i32(s->tmp2_i32, val);
6590 if (!gen_check_io(s, ot, s->tmp2_i32, 0)) {
Richard Hendersonbc2e4362021-05-14 10:13:38 -05006591 break;
6592 }
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006593 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006594 gen_io_start();
Paolo Bonzini7d374352018-12-13 23:37:37 +01006595 }
Richard Henderson1bca40f2021-05-14 10:13:39 -05006596 gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
Emilio G. Cota4f824462018-09-11 14:17:56 -04006597 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
6598 gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006599 gen_bpt_io(s, s->tmp2_i32, ot);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006600 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006601 gen_jmp(s, s->pc - s->cs_base);
6602 }
bellard2c0262a2003-09-30 20:34:21 +00006603 break;
6604 case 0xec:
6605 case 0xed:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006606 ot = mo_b_d32(b, dflag);
Richard Henderson1bca40f2021-05-14 10:13:39 -05006607 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
6608 tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
6609 if (!gen_check_io(s, ot, s->tmp2_i32, SVM_IOIO_TYPE_MASK)) {
Richard Hendersonbc2e4362021-05-14 10:13:38 -05006610 break;
6611 }
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006612 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006613 gen_io_start();
Paolo Bonzini7d374352018-12-13 23:37:37 +01006614 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006615 gen_helper_in_func(ot, s->T1, s->tmp2_i32);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04006616 gen_op_mov_reg_v(s, ot, R_EAX, s->T1);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006617 gen_bpt_io(s, s->tmp2_i32, ot);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006618 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006619 gen_jmp(s, s->pc - s->cs_base);
6620 }
bellard2c0262a2003-09-30 20:34:21 +00006621 break;
6622 case 0xee:
6623 case 0xef:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006624 ot = mo_b_d32(b, dflag);
Richard Henderson1bca40f2021-05-14 10:13:39 -05006625 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]);
6626 tcg_gen_ext16u_i32(s->tmp2_i32, s->tmp2_i32);
6627 if (!gen_check_io(s, ot, s->tmp2_i32, 0)) {
Richard Hendersonbc2e4362021-05-14 10:13:38 -05006628 break;
6629 }
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006630 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006631 gen_io_start();
Paolo Bonzini7d374352018-12-13 23:37:37 +01006632 }
Richard Henderson1bca40f2021-05-14 10:13:39 -05006633 gen_op_mov_v_reg(s, ot, s->T1, R_EAX);
Emilio G. Cota4f824462018-09-11 14:17:56 -04006634 tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1);
6635 gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006636 gen_bpt_io(s, s->tmp2_i32, ot);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04006637 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrook2e70f6e2008-06-29 01:03:05 +00006638 gen_jmp(s, s->pc - s->cs_base);
6639 }
bellard2c0262a2003-09-30 20:34:21 +00006640 break;
6641
6642 /************************/
6643 /* control */
6644 case 0xc2: /* ret im */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006645 val = x86_ldsw_code(env, s);
Richard Henderson8e31d232013-11-06 13:57:45 +10006646 ot = gen_pop_T0(s);
6647 gen_stack_update(s, val + (1 << ot));
6648 /* Note that gen_pop_T0 uses a zero-extending load. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006649 gen_op_jmp_v(s->T0);
Richard Henderson7d117ce2015-07-07 14:38:58 +01006650 gen_bnd_jmp(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006651 gen_jr(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00006652 break;
6653 case 0xc3: /* ret */
Richard Henderson8e31d232013-11-06 13:57:45 +10006654 ot = gen_pop_T0(s);
6655 gen_pop_update(s, ot);
6656 /* Note that gen_pop_T0 uses a zero-extending load. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006657 gen_op_jmp_v(s->T0);
Richard Henderson7d117ce2015-07-07 14:38:58 +01006658 gen_bnd_jmp(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006659 gen_jr(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00006660 break;
6661 case 0xca: /* lret im */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006662 val = x86_ldsw_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00006663 do_lret:
Richard Hendersonf8a35842021-05-14 10:13:01 -05006664 if (PE(s) && !VM86(s)) {
Richard Henderson773cdfc2013-01-23 12:43:12 -08006665 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04006666 gen_jmp_im(s, pc_start - s->cs_base);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006667 gen_helper_lret_protected(cpu_env, tcg_const_i32(dflag - 1),
pbrooka7812ae2008-11-17 14:43:54 +00006668 tcg_const_i32(val));
bellard2c0262a2003-09-30 20:34:21 +00006669 } else {
6670 gen_stack_A0(s);
6671 /* pop offset */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006672 gen_op_ld_v(s, dflag, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00006673 /* NOTE: keeping EIP updated is not a problem in case of
6674 exception */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006675 gen_op_jmp_v(s->T0);
bellard2c0262a2003-09-30 20:34:21 +00006676 /* pop selector */
Richard Henderson4e850572015-12-17 11:19:25 -08006677 gen_add_A0_im(s, 1 << dflag);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006678 gen_op_ld_v(s, dflag, s->T0, s->A0);
6679 gen_op_movl_seg_T0_vm(s, R_CS);
bellard2c0262a2003-09-30 20:34:21 +00006680 /* add stack offset */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006681 gen_stack_update(s, val + (2 << dflag));
bellard2c0262a2003-09-30 20:34:21 +00006682 }
6683 gen_eob(s);
6684 break;
6685 case 0xcb: /* lret */
6686 val = 0;
6687 goto do_lret;
6688 case 0xcf: /* iret */
Richard Hendersonb53605d2021-05-14 10:13:29 -05006689 gen_svm_check_intercept(s, SVM_EXIT_IRET);
Richard Hendersonf8a35842021-05-14 10:13:01 -05006690 if (!PE(s) || VM86(s)) {
Richard Hendersone048f3d2021-05-14 10:12:55 -05006691 /* real mode or vm86 mode */
Richard Hendersonaa9f21b2021-05-14 10:12:56 -05006692 if (!check_vm86_iopl(s)) {
Richard Hendersone048f3d2021-05-14 10:12:55 -05006693 break;
bellardf115e912003-11-13 01:43:28 +00006694 }
Richard Hendersone048f3d2021-05-14 10:12:55 -05006695 gen_helper_iret_real(cpu_env, tcg_const_i32(dflag - 1));
bellard2c0262a2003-09-30 20:34:21 +00006696 } else {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006697 gen_helper_iret_protected(cpu_env, tcg_const_i32(dflag - 1),
pbrooka7812ae2008-11-17 14:43:54 +00006698 tcg_const_i32(s->pc - s->cs_base));
bellard2c0262a2003-09-30 20:34:21 +00006699 }
Richard Hendersone048f3d2021-05-14 10:12:55 -05006700 set_cc_op(s, CC_OP_EFLAGS);
Doug Evans410e9812016-12-24 20:29:33 +00006701 gen_eob(s);
bellard2c0262a2003-09-30 20:34:21 +00006702 break;
6703 case 0xe8: /* call im */
6704 {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006705 if (dflag != MO_16) {
Richard Henderson4ba99382013-11-02 09:54:47 -07006706 tval = (int32_t)insn_get(env, s, MO_32);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006707 } else {
Richard Henderson4ba99382013-11-02 09:54:47 -07006708 tval = (int16_t)insn_get(env, s, MO_16);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006709 }
bellard2c0262a2003-09-30 20:34:21 +00006710 next_eip = s->pc - s->cs_base;
bellard14ce26e2005-01-03 23:50:08 +00006711 tval += next_eip;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006712 if (dflag == MO_16) {
bellard14ce26e2005-01-03 23:50:08 +00006713 tval &= 0xffff;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006714 } else if (!CODE64(s)) {
Aurelien Jarno99596382010-01-03 03:08:19 +01006715 tval &= 0xffffffff;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006716 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006717 tcg_gen_movi_tl(s->T0, next_eip);
6718 gen_push_v(s, s->T0);
Richard Henderson7d117ce2015-07-07 14:38:58 +01006719 gen_bnd_jmp(s);
bellard14ce26e2005-01-03 23:50:08 +00006720 gen_jmp(s, tval);
bellard2c0262a2003-09-30 20:34:21 +00006721 }
6722 break;
6723 case 0x9a: /* lcall im */
6724 {
6725 unsigned int selector, offset;
ths3b46e622007-09-17 08:09:54 +00006726
bellard14ce26e2005-01-03 23:50:08 +00006727 if (CODE64(s))
6728 goto illegal_op;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006729 ot = dflag;
Blue Swirl0af10c82012-09-08 13:26:02 +00006730 offset = insn_get(env, s, ot);
Richard Henderson4ba99382013-11-02 09:54:47 -07006731 selector = insn_get(env, s, MO_16);
ths3b46e622007-09-17 08:09:54 +00006732
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006733 tcg_gen_movi_tl(s->T0, selector);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04006734 tcg_gen_movi_tl(s->T1, offset);
bellard2c0262a2003-09-30 20:34:21 +00006735 }
6736 goto do_lcall;
bellardecada8a2005-08-21 10:28:44 +00006737 case 0xe9: /* jmp im */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006738 if (dflag != MO_16) {
Richard Henderson4ba99382013-11-02 09:54:47 -07006739 tval = (int32_t)insn_get(env, s, MO_32);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006740 } else {
Richard Henderson4ba99382013-11-02 09:54:47 -07006741 tval = (int16_t)insn_get(env, s, MO_16);
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006742 }
bellard14ce26e2005-01-03 23:50:08 +00006743 tval += s->pc - s->cs_base;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006744 if (dflag == MO_16) {
bellard14ce26e2005-01-03 23:50:08 +00006745 tval &= 0xffff;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006746 } else if (!CODE64(s)) {
aurel3232938e12008-12-10 15:02:16 +00006747 tval &= 0xffffffff;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006748 }
Richard Henderson7d117ce2015-07-07 14:38:58 +01006749 gen_bnd_jmp(s);
bellard14ce26e2005-01-03 23:50:08 +00006750 gen_jmp(s, tval);
bellard2c0262a2003-09-30 20:34:21 +00006751 break;
6752 case 0xea: /* ljmp im */
6753 {
6754 unsigned int selector, offset;
6755
bellard14ce26e2005-01-03 23:50:08 +00006756 if (CODE64(s))
6757 goto illegal_op;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006758 ot = dflag;
Blue Swirl0af10c82012-09-08 13:26:02 +00006759 offset = insn_get(env, s, ot);
Richard Henderson4ba99382013-11-02 09:54:47 -07006760 selector = insn_get(env, s, MO_16);
ths3b46e622007-09-17 08:09:54 +00006761
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006762 tcg_gen_movi_tl(s->T0, selector);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04006763 tcg_gen_movi_tl(s->T1, offset);
bellard2c0262a2003-09-30 20:34:21 +00006764 }
6765 goto do_ljmp;
6766 case 0xeb: /* jmp Jb */
Richard Henderson4ba99382013-11-02 09:54:47 -07006767 tval = (int8_t)insn_get(env, s, MO_8);
bellard14ce26e2005-01-03 23:50:08 +00006768 tval += s->pc - s->cs_base;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006769 if (dflag == MO_16) {
bellard14ce26e2005-01-03 23:50:08 +00006770 tval &= 0xffff;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006771 }
bellard14ce26e2005-01-03 23:50:08 +00006772 gen_jmp(s, tval);
bellard2c0262a2003-09-30 20:34:21 +00006773 break;
6774 case 0x70 ... 0x7f: /* jcc Jb */
Richard Henderson4ba99382013-11-02 09:54:47 -07006775 tval = (int8_t)insn_get(env, s, MO_8);
bellard2c0262a2003-09-30 20:34:21 +00006776 goto do_jcc;
6777 case 0x180 ... 0x18f: /* jcc Jv */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006778 if (dflag != MO_16) {
Richard Henderson4ba99382013-11-02 09:54:47 -07006779 tval = (int32_t)insn_get(env, s, MO_32);
bellard2c0262a2003-09-30 20:34:21 +00006780 } else {
Richard Henderson4ba99382013-11-02 09:54:47 -07006781 tval = (int16_t)insn_get(env, s, MO_16);
bellard2c0262a2003-09-30 20:34:21 +00006782 }
6783 do_jcc:
6784 next_eip = s->pc - s->cs_base;
bellard14ce26e2005-01-03 23:50:08 +00006785 tval += next_eip;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006786 if (dflag == MO_16) {
bellard14ce26e2005-01-03 23:50:08 +00006787 tval &= 0xffff;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006788 }
Richard Henderson7d117ce2015-07-07 14:38:58 +01006789 gen_bnd_jmp(s);
bellard14ce26e2005-01-03 23:50:08 +00006790 gen_jcc(s, b, tval, next_eip);
bellard2c0262a2003-09-30 20:34:21 +00006791 break;
6792
6793 case 0x190 ... 0x19f: /* setcc Gv */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006794 modrm = x86_ldub_code(env, s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006795 gen_setcc1(s, b, s->T0);
Richard Henderson4ba99382013-11-02 09:54:47 -07006796 gen_ldst_modrm(env, s, modrm, MO_8, OR_TMP0, 1);
bellard2c0262a2003-09-30 20:34:21 +00006797 break;
6798 case 0x140 ... 0x14f: /* cmov Gv, Ev */
Peter Maydellbff93282013-07-15 18:21:40 +01006799 if (!(s->cpuid_features & CPUID_CMOV)) {
6800 goto illegal_op;
6801 }
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006802 ot = dflag;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006803 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05006804 reg = ((modrm >> 3) & 7) | REX_R(s);
Paolo Bonzinif32d3782012-10-07 17:55:26 +02006805 gen_cmovcc1(env, s, ot, b, modrm, reg);
bellard2c0262a2003-09-30 20:34:21 +00006806 break;
ths3b46e622007-09-17 08:09:54 +00006807
bellard2c0262a2003-09-30 20:34:21 +00006808 /************************/
6809 /* flags */
6810 case 0x9c: /* pushf */
Richard Hendersonb53605d2021-05-14 10:13:29 -05006811 gen_svm_check_intercept(s, SVM_EXIT_PUSHF);
Richard Hendersonaa9f21b2021-05-14 10:12:56 -05006812 if (check_vm86_iopl(s)) {
Richard Henderson773cdfc2013-01-23 12:43:12 -08006813 gen_update_cc_op(s);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006814 gen_helper_read_eflags(s->T0, cpu_env);
6815 gen_push_v(s, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00006816 }
6817 break;
6818 case 0x9d: /* popf */
Richard Hendersonb53605d2021-05-14 10:13:29 -05006819 gen_svm_check_intercept(s, SVM_EXIT_POPF);
Richard Hendersonaa9f21b2021-05-14 10:12:56 -05006820 if (check_vm86_iopl(s)) {
Richard Henderson8e31d232013-11-06 13:57:45 +10006821 ot = gen_pop_T0(s);
Richard Henderson01b9d8c2021-05-14 10:12:59 -05006822 if (CPL(s) == 0) {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006823 if (dflag != MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006824 gen_helper_write_eflags(cpu_env, s->T0,
Blue Swirlf0967a12012-04-29 12:45:34 +00006825 tcg_const_i32((TF_MASK | AC_MASK |
6826 ID_MASK | NT_MASK |
6827 IF_MASK |
6828 IOPL_MASK)));
bellard2c0262a2003-09-30 20:34:21 +00006829 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006830 gen_helper_write_eflags(cpu_env, s->T0,
Blue Swirlf0967a12012-04-29 12:45:34 +00006831 tcg_const_i32((TF_MASK | AC_MASK |
6832 ID_MASK | NT_MASK |
6833 IF_MASK | IOPL_MASK)
6834 & 0xffff));
bellard2c0262a2003-09-30 20:34:21 +00006835 }
6836 } else {
Richard Henderson0ab011c2021-05-14 10:13:00 -05006837 if (CPL(s) <= IOPL(s)) {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006838 if (dflag != MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006839 gen_helper_write_eflags(cpu_env, s->T0,
Blue Swirlf0967a12012-04-29 12:45:34 +00006840 tcg_const_i32((TF_MASK |
6841 AC_MASK |
6842 ID_MASK |
6843 NT_MASK |
6844 IF_MASK)));
bellard4136f332003-11-23 23:09:40 +00006845 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006846 gen_helper_write_eflags(cpu_env, s->T0,
Blue Swirlf0967a12012-04-29 12:45:34 +00006847 tcg_const_i32((TF_MASK |
6848 AC_MASK |
6849 ID_MASK |
6850 NT_MASK |
6851 IF_MASK)
6852 & 0xffff));
bellard4136f332003-11-23 23:09:40 +00006853 }
bellard2c0262a2003-09-30 20:34:21 +00006854 } else {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006855 if (dflag != MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006856 gen_helper_write_eflags(cpu_env, s->T0,
Blue Swirlf0967a12012-04-29 12:45:34 +00006857 tcg_const_i32((TF_MASK | AC_MASK |
6858 ID_MASK | NT_MASK)));
bellard4136f332003-11-23 23:09:40 +00006859 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006860 gen_helper_write_eflags(cpu_env, s->T0,
Blue Swirlf0967a12012-04-29 12:45:34 +00006861 tcg_const_i32((TF_MASK | AC_MASK |
6862 ID_MASK | NT_MASK)
6863 & 0xffff));
bellard4136f332003-11-23 23:09:40 +00006864 }
bellard2c0262a2003-09-30 20:34:21 +00006865 }
6866 }
Richard Henderson8e31d232013-11-06 13:57:45 +10006867 gen_pop_update(s, ot);
Richard Henderson3ca51d02013-01-23 12:30:52 -08006868 set_cc_op(s, CC_OP_EFLAGS);
H. Peter Anvina9321a42012-09-26 13:18:43 -07006869 /* abort translation because TF/AC flag may change */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04006870 gen_jmp_im(s, s->pc - s->cs_base);
bellard2c0262a2003-09-30 20:34:21 +00006871 gen_eob(s);
6872 }
6873 break;
6874 case 0x9e: /* sahf */
bellard12e26b72008-05-22 10:13:38 +00006875 if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
bellard14ce26e2005-01-03 23:50:08 +00006876 goto illegal_op;
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04006877 gen_op_mov_v_reg(s, MO_8, s->T0, R_AH);
Richard Hendersond229edc2013-01-23 13:03:26 -08006878 gen_compute_eflags(s);
bellardbd7a7b32008-05-21 17:07:20 +00006879 tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006880 tcg_gen_andi_tl(s->T0, s->T0, CC_S | CC_Z | CC_A | CC_P | CC_C);
6881 tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00006882 break;
6883 case 0x9f: /* lahf */
bellard12e26b72008-05-22 10:13:38 +00006884 if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
bellard14ce26e2005-01-03 23:50:08 +00006885 goto illegal_op;
Richard Hendersond229edc2013-01-23 13:03:26 -08006886 gen_compute_eflags(s);
bellardbd7a7b32008-05-21 17:07:20 +00006887 /* Note: gen_compute_eflags() only gives the condition codes */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006888 tcg_gen_ori_tl(s->T0, cpu_cc_src, 0x02);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04006889 gen_op_mov_reg_v(s, MO_8, R_AH, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00006890 break;
6891 case 0xf5: /* cmc */
Richard Hendersond229edc2013-01-23 13:03:26 -08006892 gen_compute_eflags(s);
bellardbd7a7b32008-05-21 17:07:20 +00006893 tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C);
bellard2c0262a2003-09-30 20:34:21 +00006894 break;
6895 case 0xf8: /* clc */
Richard Hendersond229edc2013-01-23 13:03:26 -08006896 gen_compute_eflags(s);
bellardbd7a7b32008-05-21 17:07:20 +00006897 tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C);
bellard2c0262a2003-09-30 20:34:21 +00006898 break;
6899 case 0xf9: /* stc */
Richard Hendersond229edc2013-01-23 13:03:26 -08006900 gen_compute_eflags(s);
bellardbd7a7b32008-05-21 17:07:20 +00006901 tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C);
bellard2c0262a2003-09-30 20:34:21 +00006902 break;
6903 case 0xfc: /* cld */
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006904 tcg_gen_movi_i32(s->tmp2_i32, 1);
6905 tcg_gen_st_i32(s->tmp2_i32, cpu_env, offsetof(CPUX86State, df));
bellard2c0262a2003-09-30 20:34:21 +00006906 break;
6907 case 0xfd: /* std */
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04006908 tcg_gen_movi_i32(s->tmp2_i32, -1);
6909 tcg_gen_st_i32(s->tmp2_i32, cpu_env, offsetof(CPUX86State, df));
bellard2c0262a2003-09-30 20:34:21 +00006910 break;
6911
6912 /************************/
6913 /* bit operations */
6914 case 0x1ba: /* bt/bts/btr/btc Gv, im */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006915 ot = dflag;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006916 modrm = x86_ldub_code(env, s);
bellard33698e52006-04-02 19:13:41 +00006917 op = (modrm >> 3) & 7;
bellard2c0262a2003-09-30 20:34:21 +00006918 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00006919 rm = (modrm & 7) | REX_B(s);
bellard2c0262a2003-09-30 20:34:21 +00006920 if (mod != 3) {
bellard14ce26e2005-01-03 23:50:08 +00006921 s->rip_offset = 1;
Richard Henderson4eeb3932013-11-02 08:55:59 -10006922 gen_lea_modrm(env, s, modrm);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006923 if (!(s->prefix & PREFIX_LOCK)) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006924 gen_op_ld_v(s, ot, s->T0, s->A0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006925 }
bellard2c0262a2003-09-30 20:34:21 +00006926 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04006927 gen_op_mov_v_reg(s, ot, s->T0, rm);
bellard2c0262a2003-09-30 20:34:21 +00006928 }
6929 /* load shift */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006930 val = x86_ldub_code(env, s);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04006931 tcg_gen_movi_tl(s->T1, val);
bellard2c0262a2003-09-30 20:34:21 +00006932 if (op < 4)
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08006933 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00006934 op -= 4;
bellardf484d382008-05-17 16:10:38 +00006935 goto bt_op;
bellard2c0262a2003-09-30 20:34:21 +00006936 case 0x1a3: /* bt Gv, Ev */
6937 op = 0;
6938 goto do_btx;
6939 case 0x1ab: /* bts */
6940 op = 1;
6941 goto do_btx;
6942 case 0x1b3: /* btr */
6943 op = 2;
6944 goto do_btx;
6945 case 0x1bb: /* btc */
6946 op = 3;
6947 do_btx:
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10006948 ot = dflag;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02006949 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05006950 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard2c0262a2003-09-30 20:34:21 +00006951 mod = (modrm >> 6) & 3;
bellard14ce26e2005-01-03 23:50:08 +00006952 rm = (modrm & 7) | REX_B(s);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04006953 gen_op_mov_v_reg(s, MO_32, s->T1, reg);
bellard2c0262a2003-09-30 20:34:21 +00006954 if (mod != 3) {
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006955 AddressParts a = gen_lea_modrm_0(env, s, modrm);
bellard2c0262a2003-09-30 20:34:21 +00006956 /* specific case: we need to add a displacement */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04006957 gen_exts(ot, s->T1);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04006958 tcg_gen_sari_tl(s->tmp0, s->T1, 3 + ot);
6959 tcg_gen_shli_tl(s->tmp0, s->tmp0, ot);
6960 tcg_gen_add_tl(s->A0, gen_lea_modrm_1(s, a), s->tmp0);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04006961 gen_lea_v_seg(s, s->aflag, s->A0, a.def_seg, s->override);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006962 if (!(s->prefix & PREFIX_LOCK)) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006963 gen_op_ld_v(s, ot, s->T0, s->A0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006964 }
bellard2c0262a2003-09-30 20:34:21 +00006965 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04006966 gen_op_mov_v_reg(s, ot, s->T0, rm);
bellard2c0262a2003-09-30 20:34:21 +00006967 }
bellardf484d382008-05-17 16:10:38 +00006968 bt_op:
Emilio G. Cotab48597b2018-09-11 14:50:46 -04006969 tcg_gen_andi_tl(s->T1, s->T1, (1 << (3 + ot)) - 1);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04006970 tcg_gen_movi_tl(s->tmp0, 1);
6971 tcg_gen_shl_tl(s->tmp0, s->tmp0, s->T1);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006972 if (s->prefix & PREFIX_LOCK) {
6973 switch (op) {
6974 case 0: /* bt */
6975 /* Needs no atomic ops; we surpressed the normal
6976 memory load for LOCK above so do it now. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04006977 gen_op_ld_v(s, ot, s->T0, s->A0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006978 break;
6979 case 1: /* bts */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04006980 tcg_gen_atomic_fetch_or_tl(s->T0, s->A0, s->tmp0,
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006981 s->mem_index, ot | MO_LE);
6982 break;
6983 case 2: /* btr */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04006984 tcg_gen_not_tl(s->tmp0, s->tmp0);
6985 tcg_gen_atomic_fetch_and_tl(s->T0, s->A0, s->tmp0,
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006986 s->mem_index, ot | MO_LE);
6987 break;
6988 default:
6989 case 3: /* btc */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04006990 tcg_gen_atomic_fetch_xor_tl(s->T0, s->A0, s->tmp0,
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006991 s->mem_index, ot | MO_LE);
6992 break;
6993 }
Emilio G. Cota5022f282018-09-11 14:10:21 -04006994 tcg_gen_shr_tl(s->tmp4, s->T0, s->T1);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006995 } else {
Emilio G. Cota5022f282018-09-11 14:10:21 -04006996 tcg_gen_shr_tl(s->tmp4, s->T0, s->T1);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04006997 switch (op) {
6998 case 0: /* bt */
6999 /* Data already loaded; nothing to do. */
7000 break;
7001 case 1: /* bts */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007002 tcg_gen_or_tl(s->T0, s->T0, s->tmp0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04007003 break;
7004 case 2: /* btr */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007005 tcg_gen_andc_tl(s->T0, s->T0, s->tmp0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04007006 break;
7007 default:
7008 case 3: /* btc */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007009 tcg_gen_xor_tl(s->T0, s->T0, s->tmp0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04007010 break;
7011 }
7012 if (op != 0) {
7013 if (mod != 3) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007014 gen_op_st_v(s, ot, s->T0, s->A0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04007015 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007016 gen_op_mov_reg_v(s, ot, rm, s->T0);
Emilio G. Cotacfe819d2016-06-27 15:02:03 -04007017 }
Richard Hendersonfd8ca9f2013-11-02 08:12:01 -10007018 }
Richard Hendersondc1823c2014-04-09 13:51:41 -07007019 }
7020
7021 /* Delay all CC updates until after the store above. Note that
7022 C is the result of the test, Z is unchanged, and the others
7023 are all undefined. */
7024 switch (s->cc_op) {
7025 case CC_OP_MULB ... CC_OP_MULQ:
7026 case CC_OP_ADDB ... CC_OP_ADDQ:
7027 case CC_OP_ADCB ... CC_OP_ADCQ:
7028 case CC_OP_SUBB ... CC_OP_SUBQ:
7029 case CC_OP_SBBB ... CC_OP_SBBQ:
7030 case CC_OP_LOGICB ... CC_OP_LOGICQ:
7031 case CC_OP_INCB ... CC_OP_INCQ:
7032 case CC_OP_DECB ... CC_OP_DECQ:
7033 case CC_OP_SHLB ... CC_OP_SHLQ:
7034 case CC_OP_SARB ... CC_OP_SARQ:
7035 case CC_OP_BMILGB ... CC_OP_BMILGQ:
7036 /* Z was going to be computed from the non-zero status of CC_DST.
7037 We can get that same Z value (and the new C value) by leaving
7038 CC_DST alone, setting CC_SRC, and using a CC_OP_SAR of the
7039 same width. */
Emilio G. Cota5022f282018-09-11 14:10:21 -04007040 tcg_gen_mov_tl(cpu_cc_src, s->tmp4);
Richard Hendersondc1823c2014-04-09 13:51:41 -07007041 set_cc_op(s, ((s->cc_op - CC_OP_MULB) & 3) + CC_OP_SARB);
7042 break;
7043 default:
7044 /* Otherwise, generate EFLAGS and replace the C bit. */
7045 gen_compute_eflags(s);
Emilio G. Cota5022f282018-09-11 14:10:21 -04007046 tcg_gen_deposit_tl(cpu_cc_src, cpu_cc_src, s->tmp4,
Richard Hendersondc1823c2014-04-09 13:51:41 -07007047 ctz32(CC_C), 1);
7048 break;
bellard2c0262a2003-09-30 20:34:21 +00007049 }
7050 break;
Richard Henderson321c5352013-01-21 13:32:02 -08007051 case 0x1bc: /* bsf / tzcnt */
7052 case 0x1bd: /* bsr / lzcnt */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007053 ot = dflag;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007054 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05007055 reg = ((modrm >> 3) & 7) | REX_R(s);
Richard Henderson321c5352013-01-21 13:32:02 -08007056 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007057 gen_extu(ot, s->T0);
bellard1e4840b2008-05-25 17:26:41 +00007058
Richard Henderson321c5352013-01-21 13:32:02 -08007059 /* Note that lzcnt and tzcnt are in different extensions. */
7060 if ((prefixes & PREFIX_REPZ)
7061 && (b & 1
7062 ? s->cpuid_ext3_features & CPUID_EXT3_ABM
7063 : s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_BMI1)) {
7064 int size = 8 << ot;
Richard Hendersone5143c92016-11-16 12:21:13 +01007065 /* For lzcnt/tzcnt, C bit is defined related to the input. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007066 tcg_gen_mov_tl(cpu_cc_src, s->T0);
Richard Henderson321c5352013-01-21 13:32:02 -08007067 if (b & 1) {
7068 /* For lzcnt, reduce the target_ulong result by the
7069 number of zeros that we expect to find at the top. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007070 tcg_gen_clzi_tl(s->T0, s->T0, TARGET_LONG_BITS);
7071 tcg_gen_subi_tl(s->T0, s->T0, TARGET_LONG_BITS - size);
bellard6191b052008-05-17 18:44:58 +00007072 } else {
Richard Hendersone5143c92016-11-16 12:21:13 +01007073 /* For tzcnt, a zero input must return the operand size. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007074 tcg_gen_ctzi_tl(s->T0, s->T0, size);
bellard6191b052008-05-17 18:44:58 +00007075 }
Richard Hendersone5143c92016-11-16 12:21:13 +01007076 /* For lzcnt/tzcnt, Z bit is defined related to the result. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007077 gen_op_update1_cc(s);
Richard Henderson321c5352013-01-21 13:32:02 -08007078 set_cc_op(s, CC_OP_BMILGB + ot);
7079 } else {
7080 /* For bsr/bsf, only the Z bit is defined and it is related
7081 to the input and not the result. */
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007082 tcg_gen_mov_tl(cpu_cc_dst, s->T0);
Richard Henderson321c5352013-01-21 13:32:02 -08007083 set_cc_op(s, CC_OP_LOGICB + ot);
Richard Hendersone5143c92016-11-16 12:21:13 +01007084
7085 /* ??? The manual says that the output is undefined when the
7086 input is zero, but real hardware leaves it unchanged, and
7087 real programs appear to depend on that. Accomplish this
7088 by passing the output as the value to return upon zero. */
Richard Henderson321c5352013-01-21 13:32:02 -08007089 if (b & 1) {
7090 /* For bsr, return the bit index of the first 1 bit,
7091 not the count of leading zeros. */
Emilio G. Cotab48597b2018-09-11 14:50:46 -04007092 tcg_gen_xori_tl(s->T1, cpu_regs[reg], TARGET_LONG_BITS - 1);
7093 tcg_gen_clz_tl(s->T0, s->T0, s->T1);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007094 tcg_gen_xori_tl(s->T0, s->T0, TARGET_LONG_BITS - 1);
Richard Henderson321c5352013-01-21 13:32:02 -08007095 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007096 tcg_gen_ctz_tl(s->T0, s->T0, cpu_regs[reg]);
Richard Henderson321c5352013-01-21 13:32:02 -08007097 }
bellard6191b052008-05-17 18:44:58 +00007098 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007099 gen_op_mov_reg_v(s, ot, reg, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00007100 break;
7101 /************************/
7102 /* bcd */
7103 case 0x27: /* daa */
bellard14ce26e2005-01-03 23:50:08 +00007104 if (CODE64(s))
7105 goto illegal_op;
Richard Henderson773cdfc2013-01-23 12:43:12 -08007106 gen_update_cc_op(s);
Blue Swirl79230572012-04-29 14:11:56 +00007107 gen_helper_daa(cpu_env);
Richard Henderson3ca51d02013-01-23 12:30:52 -08007108 set_cc_op(s, CC_OP_EFLAGS);
bellard2c0262a2003-09-30 20:34:21 +00007109 break;
7110 case 0x2f: /* das */
bellard14ce26e2005-01-03 23:50:08 +00007111 if (CODE64(s))
7112 goto illegal_op;
Richard Henderson773cdfc2013-01-23 12:43:12 -08007113 gen_update_cc_op(s);
Blue Swirl79230572012-04-29 14:11:56 +00007114 gen_helper_das(cpu_env);
Richard Henderson3ca51d02013-01-23 12:30:52 -08007115 set_cc_op(s, CC_OP_EFLAGS);
bellard2c0262a2003-09-30 20:34:21 +00007116 break;
7117 case 0x37: /* aaa */
bellard14ce26e2005-01-03 23:50:08 +00007118 if (CODE64(s))
7119 goto illegal_op;
Richard Henderson773cdfc2013-01-23 12:43:12 -08007120 gen_update_cc_op(s);
Blue Swirl79230572012-04-29 14:11:56 +00007121 gen_helper_aaa(cpu_env);
Richard Henderson3ca51d02013-01-23 12:30:52 -08007122 set_cc_op(s, CC_OP_EFLAGS);
bellard2c0262a2003-09-30 20:34:21 +00007123 break;
7124 case 0x3f: /* aas */
bellard14ce26e2005-01-03 23:50:08 +00007125 if (CODE64(s))
7126 goto illegal_op;
Richard Henderson773cdfc2013-01-23 12:43:12 -08007127 gen_update_cc_op(s);
Blue Swirl79230572012-04-29 14:11:56 +00007128 gen_helper_aas(cpu_env);
Richard Henderson3ca51d02013-01-23 12:30:52 -08007129 set_cc_op(s, CC_OP_EFLAGS);
bellard2c0262a2003-09-30 20:34:21 +00007130 break;
7131 case 0xd4: /* aam */
bellard14ce26e2005-01-03 23:50:08 +00007132 if (CODE64(s))
7133 goto illegal_op;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007134 val = x86_ldub_code(env, s);
thsb6d7c3d2007-06-23 18:21:26 +00007135 if (val == 0) {
7136 gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base);
7137 } else {
Blue Swirl79230572012-04-29 14:11:56 +00007138 gen_helper_aam(cpu_env, tcg_const_i32(val));
Richard Henderson3ca51d02013-01-23 12:30:52 -08007139 set_cc_op(s, CC_OP_LOGICB);
thsb6d7c3d2007-06-23 18:21:26 +00007140 }
bellard2c0262a2003-09-30 20:34:21 +00007141 break;
7142 case 0xd5: /* aad */
bellard14ce26e2005-01-03 23:50:08 +00007143 if (CODE64(s))
7144 goto illegal_op;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007145 val = x86_ldub_code(env, s);
Blue Swirl79230572012-04-29 14:11:56 +00007146 gen_helper_aad(cpu_env, tcg_const_i32(val));
Richard Henderson3ca51d02013-01-23 12:30:52 -08007147 set_cc_op(s, CC_OP_LOGICB);
bellard2c0262a2003-09-30 20:34:21 +00007148 break;
7149 /************************/
7150 /* misc */
7151 case 0x90: /* nop */
bellardab1f1422004-01-19 20:31:37 +00007152 /* XXX: correct lock test for all insn */
Richard Henderson74180272010-07-01 09:42:21 -07007153 if (prefixes & PREFIX_LOCK) {
bellardab1f1422004-01-19 20:31:37 +00007154 goto illegal_op;
Richard Henderson74180272010-07-01 09:42:21 -07007155 }
7156 /* If REX_B is set, then this is xchg eax, r8d, not a nop. */
7157 if (REX_B(s)) {
7158 goto do_xchg_reg_eax;
7159 }
ths0573fbf2007-09-23 15:28:04 +00007160 if (prefixes & PREFIX_REPZ) {
Paolo Bonzini81f30532013-11-20 12:54:02 +01007161 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007162 gen_jmp_im(s, pc_start - s->cs_base);
Paolo Bonzini81f30532013-11-20 12:54:02 +01007163 gen_helper_pause(cpu_env, tcg_const_i32(s->pc - pc_start));
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03007164 s->base.is_jmp = DISAS_NORETURN;
ths0573fbf2007-09-23 15:28:04 +00007165 }
bellard2c0262a2003-09-30 20:34:21 +00007166 break;
7167 case 0x9b: /* fwait */
ths5fafdf22007-09-16 21:08:06 +00007168 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
bellard7eee2a52004-02-25 23:17:58 +00007169 (HF_MP_MASK | HF_TS_MASK)) {
7170 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
bellard2ee73ac2004-05-08 21:08:41 +00007171 } else {
Blue Swirld3eb5ea2012-04-28 21:28:09 +00007172 gen_helper_fwait(cpu_env);
bellard7eee2a52004-02-25 23:17:58 +00007173 }
bellard2c0262a2003-09-30 20:34:21 +00007174 break;
7175 case 0xcc: /* int3 */
7176 gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
7177 break;
7178 case 0xcd: /* int N */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007179 val = x86_ldub_code(env, s);
Richard Hendersonaa9f21b2021-05-14 10:12:56 -05007180 if (check_vm86_iopl(s)) {
bellardf115e912003-11-13 01:43:28 +00007181 gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
7182 }
bellard2c0262a2003-09-30 20:34:21 +00007183 break;
7184 case 0xce: /* into */
bellard14ce26e2005-01-03 23:50:08 +00007185 if (CODE64(s))
7186 goto illegal_op;
Richard Henderson773cdfc2013-01-23 12:43:12 -08007187 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007188 gen_jmp_im(s, pc_start - s->cs_base);
Blue Swirl4a7443b2012-04-29 18:42:47 +00007189 gen_helper_into(cpu_env, tcg_const_i32(s->pc - pc_start));
bellard2c0262a2003-09-30 20:34:21 +00007190 break;
aurel320b971342008-12-07 18:15:36 +00007191#ifdef WANT_ICEBP
bellard2c0262a2003-09-30 20:34:21 +00007192 case 0xf1: /* icebp (undocumented, exits to external debugger) */
Richard Hendersonb53605d2021-05-14 10:13:29 -05007193 gen_svm_check_intercept(s, SVM_EXIT_ICEBP);
Richard Hendersoned3c4732021-05-14 10:13:27 -05007194 gen_debug(s);
bellard2c0262a2003-09-30 20:34:21 +00007195 break;
aurel320b971342008-12-07 18:15:36 +00007196#endif
bellard2c0262a2003-09-30 20:34:21 +00007197 case 0xfa: /* cli */
Richard Hendersonca7874c2021-05-14 10:12:57 -05007198 if (check_iopl(s)) {
7199 gen_helper_cli(cpu_env);
bellard2c0262a2003-09-30 20:34:21 +00007200 }
7201 break;
7202 case 0xfb: /* sti */
Richard Hendersonca7874c2021-05-14 10:12:57 -05007203 if (check_iopl(s)) {
Richard Hendersonf083d922016-03-02 21:16:51 -08007204 gen_helper_sti(cpu_env);
7205 /* interruptions are enabled only the first insn after sti */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007206 gen_jmp_im(s, s->pc - s->cs_base);
Richard Hendersonf083d922016-03-02 21:16:51 -08007207 gen_eob_inhibit_irq(s, true);
bellard2c0262a2003-09-30 20:34:21 +00007208 }
7209 break;
7210 case 0x62: /* bound */
bellard14ce26e2005-01-03 23:50:08 +00007211 if (CODE64(s))
7212 goto illegal_op;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007213 ot = dflag;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007214 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00007215 reg = (modrm >> 3) & 7;
7216 mod = (modrm >> 6) & 3;
7217 if (mod == 3)
7218 goto illegal_op;
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007219 gen_op_mov_v_reg(s, ot, s->T0, reg);
Richard Henderson4eeb3932013-11-02 08:55:59 -10007220 gen_lea_modrm(env, s, modrm);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007221 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
Richard Henderson4ba99382013-11-02 09:54:47 -07007222 if (ot == MO_16) {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007223 gen_helper_boundw(cpu_env, s->A0, s->tmp2_i32);
Blue Swirl92fc4b52012-04-29 20:35:48 +00007224 } else {
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007225 gen_helper_boundl(cpu_env, s->A0, s->tmp2_i32);
Blue Swirl92fc4b52012-04-29 20:35:48 +00007226 }
bellard2c0262a2003-09-30 20:34:21 +00007227 break;
7228 case 0x1c8 ... 0x1cf: /* bswap reg */
bellard14ce26e2005-01-03 23:50:08 +00007229 reg = (b & 7) | REX_B(s);
7230#ifdef TARGET_X86_64
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007231 if (dflag == MO_64) {
Richard Henderson94fdf982021-06-13 16:23:14 -07007232 tcg_gen_bswap64_i64(cpu_regs[reg], cpu_regs[reg]);
7233 break;
aurel3287776432009-03-13 09:35:41 +00007234 }
Richard Henderson94fdf982021-06-13 16:23:14 -07007235#endif
7236 tcg_gen_bswap32_tl(cpu_regs[reg], cpu_regs[reg], TCG_BSWAP_OZ);
bellard2c0262a2003-09-30 20:34:21 +00007237 break;
7238 case 0xd6: /* salc */
bellard14ce26e2005-01-03 23:50:08 +00007239 if (CODE64(s))
7240 goto illegal_op;
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007241 gen_compute_eflags_c(s, s->T0);
7242 tcg_gen_neg_tl(s->T0, s->T0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007243 gen_op_mov_reg_v(s, MO_8, R_EAX, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00007244 break;
7245 case 0xe0: /* loopnz */
7246 case 0xe1: /* loopz */
bellard2c0262a2003-09-30 20:34:21 +00007247 case 0xe2: /* loop */
7248 case 0xe3: /* jecxz */
bellard14ce26e2005-01-03 23:50:08 +00007249 {
Richard Henderson42a268c2015-02-13 12:51:55 -08007250 TCGLabel *l1, *l2, *l3;
bellard14ce26e2005-01-03 23:50:08 +00007251
Richard Henderson4ba99382013-11-02 09:54:47 -07007252 tval = (int8_t)insn_get(env, s, MO_8);
bellard14ce26e2005-01-03 23:50:08 +00007253 next_eip = s->pc - s->cs_base;
7254 tval += next_eip;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007255 if (dflag == MO_16) {
bellard14ce26e2005-01-03 23:50:08 +00007256 tval &= 0xffff;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007257 }
ths3b46e622007-09-17 08:09:54 +00007258
bellard14ce26e2005-01-03 23:50:08 +00007259 l1 = gen_new_label();
7260 l2 = gen_new_label();
bellard6e0d8672008-05-18 19:28:26 +00007261 l3 = gen_new_label();
Richard Henderson3cb3a772020-07-20 08:30:40 -07007262 gen_update_cc_op(s);
bellard14ce26e2005-01-03 23:50:08 +00007263 b &= 3;
bellard6e0d8672008-05-18 19:28:26 +00007264 switch(b) {
7265 case 0: /* loopnz */
7266 case 1: /* loopz */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007267 gen_op_add_reg_im(s, s->aflag, R_ECX, -1);
7268 gen_op_jz_ecx(s, s->aflag, l3);
Paolo Bonzini5bdb91b2012-10-12 13:35:40 +02007269 gen_jcc1(s, (JCC_Z << 1) | (b ^ 1), l1);
bellard6e0d8672008-05-18 19:28:26 +00007270 break;
7271 case 2: /* loop */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007272 gen_op_add_reg_im(s, s->aflag, R_ECX, -1);
7273 gen_op_jnz_ecx(s, s->aflag, l1);
bellard6e0d8672008-05-18 19:28:26 +00007274 break;
7275 default:
7276 case 3: /* jcxz */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007277 gen_op_jz_ecx(s, s->aflag, l1);
bellard6e0d8672008-05-18 19:28:26 +00007278 break;
bellard14ce26e2005-01-03 23:50:08 +00007279 }
7280
bellard6e0d8672008-05-18 19:28:26 +00007281 gen_set_label(l3);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007282 gen_jmp_im(s, next_eip);
bellard8e1c85e2008-05-21 19:16:45 +00007283 tcg_gen_br(l2);
bellard6e0d8672008-05-18 19:28:26 +00007284
bellard14ce26e2005-01-03 23:50:08 +00007285 gen_set_label(l1);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007286 gen_jmp_im(s, tval);
bellard14ce26e2005-01-03 23:50:08 +00007287 gen_set_label(l2);
7288 gen_eob(s);
7289 }
bellard2c0262a2003-09-30 20:34:21 +00007290 break;
7291 case 0x130: /* wrmsr */
7292 case 0x132: /* rdmsr */
Richard Hendersonbc19f502021-05-14 10:12:54 -05007293 if (check_cpl0(s)) {
Richard Henderson773cdfc2013-01-23 12:43:12 -08007294 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007295 gen_jmp_im(s, pc_start - s->cs_base);
ths0573fbf2007-09-23 15:28:04 +00007296 if (b & 2) {
Blue Swirl4a7443b2012-04-29 18:42:47 +00007297 gen_helper_rdmsr(cpu_env);
ths0573fbf2007-09-23 15:28:04 +00007298 } else {
Blue Swirl4a7443b2012-04-29 18:42:47 +00007299 gen_helper_wrmsr(cpu_env);
Richard Henderson244843b2021-05-14 10:13:37 -05007300 gen_jmp_im(s, s->pc - s->cs_base);
7301 gen_eob(s);
ths0573fbf2007-09-23 15:28:04 +00007302 }
bellard2c0262a2003-09-30 20:34:21 +00007303 }
7304 break;
7305 case 0x131: /* rdtsc */
Richard Henderson773cdfc2013-01-23 12:43:12 -08007306 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007307 gen_jmp_im(s, pc_start - s->cs_base);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04007308 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrookefade672008-06-30 17:51:26 +00007309 gen_io_start();
Paolo Bonzini7d374352018-12-13 23:37:37 +01007310 }
Blue Swirl4a7443b2012-04-29 18:42:47 +00007311 gen_helper_rdtsc(cpu_env);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04007312 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
pbrookefade672008-06-30 17:51:26 +00007313 gen_jmp(s, s->pc - s->cs_base);
7314 }
bellard2c0262a2003-09-30 20:34:21 +00007315 break;
balrogdf01e0f2007-12-09 23:35:27 +00007316 case 0x133: /* rdpmc */
Richard Henderson773cdfc2013-01-23 12:43:12 -08007317 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007318 gen_jmp_im(s, pc_start - s->cs_base);
Blue Swirl4a7443b2012-04-29 18:42:47 +00007319 gen_helper_rdpmc(cpu_env);
Richard Hendersonb82055a2021-05-14 10:13:26 -05007320 s->base.is_jmp = DISAS_NORETURN;
balrogdf01e0f2007-12-09 23:35:27 +00007321 break;
bellard023fe102004-05-29 11:08:52 +00007322 case 0x134: /* sysenter */
balrog2436b612008-09-25 18:16:18 +00007323 /* For Intel SYSENTER is valid on 64-bit */
Blue Swirl0af10c82012-09-08 13:26:02 +00007324 if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
bellard14ce26e2005-01-03 23:50:08 +00007325 goto illegal_op;
Richard Hendersond75f9122021-05-14 10:12:58 -05007326 if (!PE(s)) {
Richard Henderson6bd99582021-05-14 10:12:53 -05007327 gen_exception_gpf(s);
bellard023fe102004-05-29 11:08:52 +00007328 } else {
Blue Swirl2999a0b2012-04-29 19:47:06 +00007329 gen_helper_sysenter(cpu_env);
bellard023fe102004-05-29 11:08:52 +00007330 gen_eob(s);
7331 }
7332 break;
7333 case 0x135: /* sysexit */
balrog2436b612008-09-25 18:16:18 +00007334 /* For Intel SYSEXIT is valid on 64-bit */
Blue Swirl0af10c82012-09-08 13:26:02 +00007335 if (CODE64(s) && env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
bellard14ce26e2005-01-03 23:50:08 +00007336 goto illegal_op;
Richard Hendersond75f9122021-05-14 10:12:58 -05007337 if (!PE(s)) {
Richard Henderson6bd99582021-05-14 10:12:53 -05007338 gen_exception_gpf(s);
bellard023fe102004-05-29 11:08:52 +00007339 } else {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007340 gen_helper_sysexit(cpu_env, tcg_const_i32(dflag - 1));
bellard023fe102004-05-29 11:08:52 +00007341 gen_eob(s);
7342 }
7343 break;
bellard14ce26e2005-01-03 23:50:08 +00007344#ifdef TARGET_X86_64
7345 case 0x105: /* syscall */
7346 /* XXX: is it usable in real mode ? */
Jun Koi728d8032010-07-25 12:30:03 +09007347 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007348 gen_jmp_im(s, pc_start - s->cs_base);
Blue Swirl2999a0b2012-04-29 19:47:06 +00007349 gen_helper_syscall(cpu_env, tcg_const_i32(s->pc - pc_start));
Doug Evans410e9812016-12-24 20:29:33 +00007350 /* TF handling for the syscall insn is different. The TF bit is checked
7351 after the syscall insn completes. This allows #DB to not be
7352 generated after one has entered CPL0 if TF is set in FMASK. */
7353 gen_eob_worker(s, false, true);
bellard14ce26e2005-01-03 23:50:08 +00007354 break;
7355 case 0x107: /* sysret */
Richard Hendersond75f9122021-05-14 10:12:58 -05007356 if (!PE(s)) {
Richard Henderson6bd99582021-05-14 10:12:53 -05007357 gen_exception_gpf(s);
bellard14ce26e2005-01-03 23:50:08 +00007358 } else {
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007359 gen_helper_sysret(cpu_env, tcg_const_i32(dflag - 1));
bellardaba9d612005-04-23 17:53:12 +00007360 /* condition codes are modified only in long mode */
Richard Henderson73e90dc2021-05-14 10:13:05 -05007361 if (LMA(s)) {
Richard Henderson3ca51d02013-01-23 12:30:52 -08007362 set_cc_op(s, CC_OP_EFLAGS);
7363 }
Doug Evansc52ab082016-12-06 23:06:30 +00007364 /* TF handling for the sysret insn is different. The TF bit is
7365 checked after the sysret insn completes. This allows #DB to be
7366 generated "as if" the syscall insn in userspace has just
7367 completed. */
7368 gen_eob_worker(s, false, true);
bellard14ce26e2005-01-03 23:50:08 +00007369 }
7370 break;
7371#endif
bellard2c0262a2003-09-30 20:34:21 +00007372 case 0x1a2: /* cpuid */
Richard Henderson773cdfc2013-01-23 12:43:12 -08007373 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007374 gen_jmp_im(s, pc_start - s->cs_base);
Blue Swirl4a7443b2012-04-29 18:42:47 +00007375 gen_helper_cpuid(cpu_env);
bellard2c0262a2003-09-30 20:34:21 +00007376 break;
7377 case 0xf4: /* hlt */
Richard Hendersonbc19f502021-05-14 10:12:54 -05007378 if (check_cpl0(s)) {
Richard Henderson773cdfc2013-01-23 12:43:12 -08007379 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007380 gen_jmp_im(s, pc_start - s->cs_base);
Blue Swirl4a7443b2012-04-29 18:42:47 +00007381 gen_helper_hlt(cpu_env, tcg_const_i32(s->pc - pc_start));
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03007382 s->base.is_jmp = DISAS_NORETURN;
bellard2c0262a2003-09-30 20:34:21 +00007383 }
7384 break;
7385 case 0x100:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007386 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00007387 mod = (modrm >> 6) & 3;
7388 op = (modrm >> 3) & 7;
7389 switch(op) {
7390 case 0: /* sldt */
Richard Hendersonf8a35842021-05-14 10:13:01 -05007391 if (!PE(s) || VM86(s))
bellardf115e912003-11-13 01:43:28 +00007392 goto illegal_op;
Richard Hendersonb53605d2021-05-14 10:13:29 -05007393 gen_svm_check_intercept(s, SVM_EXIT_LDTR_READ);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007394 tcg_gen_ld32u_tl(s->T0, cpu_env,
Richard Henderson1d1cc4d2015-07-09 08:15:22 +01007395 offsetof(CPUX86State, ldt.selector));
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007396 ot = mod == 3 ? dflag : MO_16;
Blue Swirl0af10c82012-09-08 13:26:02 +00007397 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
bellard2c0262a2003-09-30 20:34:21 +00007398 break;
7399 case 2: /* lldt */
Richard Hendersonf8a35842021-05-14 10:13:01 -05007400 if (!PE(s) || VM86(s))
bellardf115e912003-11-13 01:43:28 +00007401 goto illegal_op;
Richard Hendersonbc19f502021-05-14 10:12:54 -05007402 if (check_cpl0(s)) {
Richard Hendersonb53605d2021-05-14 10:13:29 -05007403 gen_svm_check_intercept(s, SVM_EXIT_LDTR_WRITE);
Richard Henderson4ba99382013-11-02 09:54:47 -07007404 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007405 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
7406 gen_helper_lldt(cpu_env, s->tmp2_i32);
bellard2c0262a2003-09-30 20:34:21 +00007407 }
7408 break;
7409 case 1: /* str */
Richard Hendersonf8a35842021-05-14 10:13:01 -05007410 if (!PE(s) || VM86(s))
bellardf115e912003-11-13 01:43:28 +00007411 goto illegal_op;
Richard Hendersonb53605d2021-05-14 10:13:29 -05007412 gen_svm_check_intercept(s, SVM_EXIT_TR_READ);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007413 tcg_gen_ld32u_tl(s->T0, cpu_env,
Richard Henderson1d1cc4d2015-07-09 08:15:22 +01007414 offsetof(CPUX86State, tr.selector));
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007415 ot = mod == 3 ? dflag : MO_16;
Blue Swirl0af10c82012-09-08 13:26:02 +00007416 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
bellard2c0262a2003-09-30 20:34:21 +00007417 break;
7418 case 3: /* ltr */
Richard Hendersonf8a35842021-05-14 10:13:01 -05007419 if (!PE(s) || VM86(s))
bellardf115e912003-11-13 01:43:28 +00007420 goto illegal_op;
Richard Hendersonbc19f502021-05-14 10:12:54 -05007421 if (check_cpl0(s)) {
Richard Hendersonb53605d2021-05-14 10:13:29 -05007422 gen_svm_check_intercept(s, SVM_EXIT_TR_WRITE);
Richard Henderson4ba99382013-11-02 09:54:47 -07007423 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007424 tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
7425 gen_helper_ltr(cpu_env, s->tmp2_i32);
bellard2c0262a2003-09-30 20:34:21 +00007426 }
7427 break;
7428 case 4: /* verr */
7429 case 5: /* verw */
Richard Hendersonf8a35842021-05-14 10:13:01 -05007430 if (!PE(s) || VM86(s))
bellardf115e912003-11-13 01:43:28 +00007431 goto illegal_op;
Richard Henderson4ba99382013-11-02 09:54:47 -07007432 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
Richard Henderson773cdfc2013-01-23 12:43:12 -08007433 gen_update_cc_op(s);
Blue Swirl2999a0b2012-04-29 19:47:06 +00007434 if (op == 4) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007435 gen_helper_verr(cpu_env, s->T0);
Blue Swirl2999a0b2012-04-29 19:47:06 +00007436 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007437 gen_helper_verw(cpu_env, s->T0);
Blue Swirl2999a0b2012-04-29 19:47:06 +00007438 }
Richard Henderson3ca51d02013-01-23 12:30:52 -08007439 set_cc_op(s, CC_OP_EFLAGS);
bellardf115e912003-11-13 01:43:28 +00007440 break;
bellard2c0262a2003-09-30 20:34:21 +00007441 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08007442 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00007443 }
7444 break;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007445
bellard2c0262a2003-09-30 20:34:21 +00007446 case 0x101:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007447 modrm = x86_ldub_code(env, s);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007448 switch (modrm) {
Paolo Bonzini880f8482016-03-01 16:12:14 +01007449 CASE_MODRM_MEM_OP(0): /* sgdt */
Richard Hendersonb53605d2021-05-14 10:13:29 -05007450 gen_svm_check_intercept(s, SVM_EXIT_GDTR_READ);
Richard Henderson4eeb3932013-11-02 08:55:59 -10007451 gen_lea_modrm(env, s, modrm);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007452 tcg_gen_ld32u_tl(s->T0,
Richard Henderson1d1cc4d2015-07-09 08:15:22 +01007453 cpu_env, offsetof(CPUX86State, gdt.limit));
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007454 gen_op_st_v(s, MO_16, s->T0, s->A0);
bellardaba9d612005-04-23 17:53:12 +00007455 gen_add_A0_im(s, 2);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007456 tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, gdt.base));
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007457 if (dflag == MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007458 tcg_gen_andi_tl(s->T0, s->T0, 0xffffff);
Richard Hendersonf0706f02013-11-05 12:27:09 +10007459 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007460 gen_op_st_v(s, CODE64(s) + MO_32, s->T0, s->A0);
bellard2c0262a2003-09-30 20:34:21 +00007461 break;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007462
7463 case 0xc8: /* monitor */
Richard Henderson01b9d8c2021-05-14 10:12:59 -05007464 if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007465 goto illegal_op;
bellard3d7374c2006-07-10 19:53:04 +00007466 }
Richard Henderson1906b2a2015-07-02 13:59:21 +01007467 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007468 gen_jmp_im(s, pc_start - s->cs_base);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007469 tcg_gen_mov_tl(s->A0, cpu_regs[R_EAX]);
7470 gen_extu(s->aflag, s->A0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007471 gen_add_A0_ds_seg(s);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007472 gen_helper_monitor(cpu_env, s->A0);
bellard3d7374c2006-07-10 19:53:04 +00007473 break;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007474
7475 case 0xc9: /* mwait */
Richard Henderson01b9d8c2021-05-14 10:12:59 -05007476 if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || CPL(s) != 0) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007477 goto illegal_op;
7478 }
7479 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007480 gen_jmp_im(s, pc_start - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007481 gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - pc_start));
Richard Hendersonb82055a2021-05-14 10:13:26 -05007482 s->base.is_jmp = DISAS_NORETURN;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007483 break;
7484
7485 case 0xca: /* clac */
7486 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
Richard Henderson01b9d8c2021-05-14 10:12:59 -05007487 || CPL(s) != 0) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007488 goto illegal_op;
7489 }
7490 gen_helper_clac(cpu_env);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007491 gen_jmp_im(s, s->pc - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007492 gen_eob(s);
7493 break;
7494
7495 case 0xcb: /* stac */
7496 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)
Richard Henderson01b9d8c2021-05-14 10:12:59 -05007497 || CPL(s) != 0) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007498 goto illegal_op;
7499 }
7500 gen_helper_stac(cpu_env);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007501 gen_jmp_im(s, s->pc - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007502 gen_eob(s);
7503 break;
7504
Paolo Bonzini880f8482016-03-01 16:12:14 +01007505 CASE_MODRM_MEM_OP(1): /* sidt */
Richard Hendersonb53605d2021-05-14 10:13:29 -05007506 gen_svm_check_intercept(s, SVM_EXIT_IDTR_READ);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007507 gen_lea_modrm(env, s, modrm);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007508 tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.limit));
7509 gen_op_st_v(s, MO_16, s->T0, s->A0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007510 gen_add_A0_im(s, 2);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007511 tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.base));
Richard Henderson1906b2a2015-07-02 13:59:21 +01007512 if (dflag == MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007513 tcg_gen_andi_tl(s->T0, s->T0, 0xffffff);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007514 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007515 gen_op_st_v(s, CODE64(s) + MO_32, s->T0, s->A0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007516 break;
7517
Richard Henderson19dc85d2015-07-02 14:53:40 +01007518 case 0xd0: /* xgetbv */
7519 if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
7520 || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
7521 | PREFIX_REPZ | PREFIX_REPNZ))) {
7522 goto illegal_op;
7523 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007524 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
Emilio G. Cota776678b2018-09-11 14:22:31 -04007525 gen_helper_xgetbv(s->tmp1_i64, cpu_env, s->tmp2_i32);
7526 tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], s->tmp1_i64);
Richard Henderson19dc85d2015-07-02 14:53:40 +01007527 break;
7528
7529 case 0xd1: /* xsetbv */
7530 if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
7531 || (s->prefix & (PREFIX_LOCK | PREFIX_DATA
7532 | PREFIX_REPZ | PREFIX_REPNZ))) {
7533 goto illegal_op;
7534 }
Richard Hendersonbc19f502021-05-14 10:12:54 -05007535 if (!check_cpl0(s)) {
Richard Henderson19dc85d2015-07-02 14:53:40 +01007536 break;
7537 }
Emilio G. Cota776678b2018-09-11 14:22:31 -04007538 tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
Richard Henderson19dc85d2015-07-02 14:53:40 +01007539 cpu_regs[R_EDX]);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007540 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
Emilio G. Cota776678b2018-09-11 14:22:31 -04007541 gen_helper_xsetbv(cpu_env, s->tmp2_i32, s->tmp1_i64);
Richard Henderson19dc85d2015-07-02 14:53:40 +01007542 /* End TB because translation flags may change. */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007543 gen_jmp_im(s, s->pc - s->cs_base);
Richard Henderson19dc85d2015-07-02 14:53:40 +01007544 gen_eob(s);
7545 break;
7546
Richard Henderson1906b2a2015-07-02 13:59:21 +01007547 case 0xd8: /* VMRUN */
Richard Henderson5d223882021-05-14 10:13:22 -05007548 if (!SVME(s) || !PE(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007549 goto illegal_op;
7550 }
Richard Hendersonbc19f502021-05-14 10:12:54 -05007551 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007552 break;
bellard2c0262a2003-09-30 20:34:21 +00007553 }
Richard Henderson1906b2a2015-07-02 13:59:21 +01007554 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007555 gen_jmp_im(s, pc_start - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007556 gen_helper_vmrun(cpu_env, tcg_const_i32(s->aflag - 1),
7557 tcg_const_i32(s->pc - pc_start));
Richard Henderson07ea28b2018-05-30 18:06:23 -07007558 tcg_gen_exit_tb(NULL, 0);
Lluís Vilanova6cf147a2017-07-14 11:29:42 +03007559 s->base.is_jmp = DISAS_NORETURN;
bellard2c0262a2003-09-30 20:34:21 +00007560 break;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007561
7562 case 0xd9: /* VMMCALL */
Richard Henderson5d223882021-05-14 10:13:22 -05007563 if (!SVME(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007564 goto illegal_op;
7565 }
7566 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007567 gen_jmp_im(s, pc_start - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007568 gen_helper_vmmcall(cpu_env);
7569 break;
7570
7571 case 0xda: /* VMLOAD */
Richard Henderson5d223882021-05-14 10:13:22 -05007572 if (!SVME(s) || !PE(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007573 goto illegal_op;
7574 }
Richard Hendersonbc19f502021-05-14 10:12:54 -05007575 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007576 break;
7577 }
7578 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007579 gen_jmp_im(s, pc_start - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007580 gen_helper_vmload(cpu_env, tcg_const_i32(s->aflag - 1));
7581 break;
7582
7583 case 0xdb: /* VMSAVE */
Richard Henderson5d223882021-05-14 10:13:22 -05007584 if (!SVME(s) || !PE(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007585 goto illegal_op;
7586 }
Richard Hendersonbc19f502021-05-14 10:12:54 -05007587 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007588 break;
7589 }
7590 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007591 gen_jmp_im(s, pc_start - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007592 gen_helper_vmsave(cpu_env, tcg_const_i32(s->aflag - 1));
7593 break;
7594
7595 case 0xdc: /* STGI */
Richard Henderson5d223882021-05-14 10:13:22 -05007596 if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
Richard Hendersond75f9122021-05-14 10:12:58 -05007597 || !PE(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007598 goto illegal_op;
7599 }
Richard Hendersonbc19f502021-05-14 10:12:54 -05007600 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007601 break;
7602 }
7603 gen_update_cc_op(s);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007604 gen_helper_stgi(cpu_env);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007605 gen_jmp_im(s, s->pc - s->cs_base);
Jan Kiszkadf2518a2018-04-03 17:36:12 +02007606 gen_eob(s);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007607 break;
7608
7609 case 0xdd: /* CLGI */
Richard Henderson5d223882021-05-14 10:13:22 -05007610 if (!SVME(s) || !PE(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007611 goto illegal_op;
7612 }
Richard Hendersonbc19f502021-05-14 10:12:54 -05007613 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007614 break;
7615 }
7616 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007617 gen_jmp_im(s, pc_start - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007618 gen_helper_clgi(cpu_env);
7619 break;
7620
7621 case 0xde: /* SKINIT */
Richard Henderson5d223882021-05-14 10:13:22 -05007622 if ((!SVME(s) && !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT))
Richard Hendersond75f9122021-05-14 10:12:58 -05007623 || !PE(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007624 goto illegal_op;
7625 }
Richard Hendersonb53605d2021-05-14 10:13:29 -05007626 gen_svm_check_intercept(s, SVM_EXIT_SKINIT);
Richard Hendersone6aeb942021-05-14 10:13:24 -05007627 /* If not intercepted, not implemented -- raise #UD. */
7628 goto illegal_op;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007629
7630 case 0xdf: /* INVLPGA */
Richard Henderson5d223882021-05-14 10:13:22 -05007631 if (!SVME(s) || !PE(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007632 goto illegal_op;
7633 }
Richard Hendersonbc19f502021-05-14 10:12:54 -05007634 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007635 break;
7636 }
Richard Henderson35e5a5d2021-05-14 10:13:34 -05007637 gen_svm_check_intercept(s, SVM_EXIT_INVLPGA);
7638 if (s->aflag == MO_64) {
7639 tcg_gen_mov_tl(s->A0, cpu_regs[R_EAX]);
7640 } else {
7641 tcg_gen_ext32u_tl(s->A0, cpu_regs[R_EAX]);
7642 }
7643 gen_helper_flush_page(cpu_env, s->A0);
7644 gen_jmp_im(s, s->pc - s->cs_base);
7645 gen_eob(s);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007646 break;
7647
Paolo Bonzini880f8482016-03-01 16:12:14 +01007648 CASE_MODRM_MEM_OP(2): /* lgdt */
Richard Hendersonbc19f502021-05-14 10:12:54 -05007649 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007650 break;
7651 }
Richard Hendersonb53605d2021-05-14 10:13:29 -05007652 gen_svm_check_intercept(s, SVM_EXIT_GDTR_WRITE);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007653 gen_lea_modrm(env, s, modrm);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04007654 gen_op_ld_v(s, MO_16, s->T1, s->A0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007655 gen_add_A0_im(s, 2);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007656 gen_op_ld_v(s, CODE64(s) + MO_32, s->T0, s->A0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007657 if (dflag == MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007658 tcg_gen_andi_tl(s->T0, s->T0, 0xffffff);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007659 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007660 tcg_gen_st_tl(s->T0, cpu_env, offsetof(CPUX86State, gdt.base));
Emilio G. Cotab48597b2018-09-11 14:50:46 -04007661 tcg_gen_st32_tl(s->T1, cpu_env, offsetof(CPUX86State, gdt.limit));
Richard Henderson1906b2a2015-07-02 13:59:21 +01007662 break;
7663
Paolo Bonzini880f8482016-03-01 16:12:14 +01007664 CASE_MODRM_MEM_OP(3): /* lidt */
Richard Hendersonbc19f502021-05-14 10:12:54 -05007665 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007666 break;
7667 }
Richard Hendersonb53605d2021-05-14 10:13:29 -05007668 gen_svm_check_intercept(s, SVM_EXIT_IDTR_WRITE);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007669 gen_lea_modrm(env, s, modrm);
Emilio G. Cotab48597b2018-09-11 14:50:46 -04007670 gen_op_ld_v(s, MO_16, s->T1, s->A0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007671 gen_add_A0_im(s, 2);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007672 gen_op_ld_v(s, CODE64(s) + MO_32, s->T0, s->A0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007673 if (dflag == MO_16) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007674 tcg_gen_andi_tl(s->T0, s->T0, 0xffffff);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007675 }
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007676 tcg_gen_st_tl(s->T0, cpu_env, offsetof(CPUX86State, idt.base));
Emilio G. Cotab48597b2018-09-11 14:50:46 -04007677 tcg_gen_st32_tl(s->T1, cpu_env, offsetof(CPUX86State, idt.limit));
Richard Henderson1906b2a2015-07-02 13:59:21 +01007678 break;
7679
Paolo Bonzini880f8482016-03-01 16:12:14 +01007680 CASE_MODRM_OP(4): /* smsw */
Richard Hendersonb53605d2021-05-14 10:13:29 -05007681 gen_svm_check_intercept(s, SVM_EXIT_READ_CR0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007682 tcg_gen_ld_tl(s->T0, cpu_env, offsetof(CPUX86State, cr[0]));
Paolo Bonzinic0c84452020-06-26 05:53:36 -04007683 /*
7684 * In 32-bit mode, the higher 16 bits of the destination
7685 * register are undefined. In practice CR0[31:0] is stored
7686 * just like in 64-bit mode.
7687 */
7688 mod = (modrm >> 6) & 3;
7689 ot = (mod != 3 ? MO_16 : s->dflag);
Richard Hendersona657f792016-03-01 08:59:32 -08007690 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
bellard2c0262a2003-09-30 20:34:21 +00007691 break;
Paolo Bonzini0f70ed42016-02-09 14:14:28 +01007692 case 0xee: /* rdpkru */
7693 if (prefixes & PREFIX_LOCK) {
7694 goto illegal_op;
7695 }
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007696 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
Emilio G. Cota776678b2018-09-11 14:22:31 -04007697 gen_helper_rdpkru(s->tmp1_i64, cpu_env, s->tmp2_i32);
7698 tcg_gen_extr_i64_tl(cpu_regs[R_EAX], cpu_regs[R_EDX], s->tmp1_i64);
Paolo Bonzini0f70ed42016-02-09 14:14:28 +01007699 break;
7700 case 0xef: /* wrpkru */
7701 if (prefixes & PREFIX_LOCK) {
7702 goto illegal_op;
7703 }
Emilio G. Cota776678b2018-09-11 14:22:31 -04007704 tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
Paolo Bonzini0f70ed42016-02-09 14:14:28 +01007705 cpu_regs[R_EDX]);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04007706 tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_ECX]);
Emilio G. Cota776678b2018-09-11 14:22:31 -04007707 gen_helper_wrpkru(cpu_env, s->tmp2_i32, s->tmp1_i64);
Paolo Bonzini0f70ed42016-02-09 14:14:28 +01007708 break;
Richard Henderson7eff2e72021-05-14 10:13:31 -05007709
Paolo Bonzini880f8482016-03-01 16:12:14 +01007710 CASE_MODRM_OP(6): /* lmsw */
Richard Hendersonbc19f502021-05-14 10:12:54 -05007711 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007712 break;
bellard2c0262a2003-09-30 20:34:21 +00007713 }
Richard Hendersonb53605d2021-05-14 10:13:29 -05007714 gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007715 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
Richard Henderson7eff2e72021-05-14 10:13:31 -05007716 /*
7717 * Only the 4 lower bits of CR0 are modified.
7718 * PE cannot be set to zero if already set to one.
7719 */
7720 tcg_gen_ld_tl(s->T1, cpu_env, offsetof(CPUX86State, cr[0]));
7721 tcg_gen_andi_tl(s->T0, s->T0, 0xf);
7722 tcg_gen_andi_tl(s->T1, s->T1, ~0xe);
7723 tcg_gen_or_tl(s->T0, s->T0, s->T1);
7724 gen_helper_write_crN(cpu_env, tcg_constant_i32(0), s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007725 gen_jmp_im(s, s->pc - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007726 gen_eob(s);
bellard2c0262a2003-09-30 20:34:21 +00007727 break;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007728
Paolo Bonzini880f8482016-03-01 16:12:14 +01007729 CASE_MODRM_MEM_OP(7): /* invlpg */
Richard Hendersonbc19f502021-05-14 10:12:54 -05007730 if (!check_cpl0(s)) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007731 break;
7732 }
Richard Henderson35e5a5d2021-05-14 10:13:34 -05007733 gen_svm_check_intercept(s, SVM_EXIT_INVLPG);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007734 gen_lea_modrm(env, s, modrm);
Richard Henderson35e5a5d2021-05-14 10:13:34 -05007735 gen_helper_flush_page(cpu_env, s->A0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007736 gen_jmp_im(s, s->pc - s->cs_base);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007737 gen_eob(s);
7738 break;
7739
7740 case 0xf8: /* swapgs */
7741#ifdef TARGET_X86_64
7742 if (CODE64(s)) {
Richard Hendersonbc19f502021-05-14 10:12:54 -05007743 if (check_cpl0(s)) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007744 tcg_gen_mov_tl(s->T0, cpu_seg_base[R_GS]);
Richard Henderson1906b2a2015-07-02 13:59:21 +01007745 tcg_gen_ld_tl(cpu_seg_base[R_GS], cpu_env,
7746 offsetof(CPUX86State, kernelgsbase));
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007747 tcg_gen_st_tl(s->T0, cpu_env,
Richard Henderson1906b2a2015-07-02 13:59:21 +01007748 offsetof(CPUX86State, kernelgsbase));
bellard14ce26e2005-01-03 23:50:08 +00007749 }
Richard Henderson1906b2a2015-07-02 13:59:21 +01007750 break;
7751 }
Richard Henderson3558f802015-12-17 11:19:21 -08007752#endif
Richard Henderson1906b2a2015-07-02 13:59:21 +01007753 goto illegal_op;
7754
7755 case 0xf9: /* rdtscp */
7756 if (!(s->cpuid_ext2_features & CPUID_EXT2_RDTSCP)) {
7757 goto illegal_op;
7758 }
7759 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007760 gen_jmp_im(s, pc_start - s->cs_base);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04007761 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007762 gen_io_start();
7763 }
7764 gen_helper_rdtscp(cpu_env);
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04007765 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
Richard Henderson1906b2a2015-07-02 13:59:21 +01007766 gen_jmp(s, s->pc - s->cs_base);
bellard2c0262a2003-09-30 20:34:21 +00007767 }
7768 break;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007769
bellard2c0262a2003-09-30 20:34:21 +00007770 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08007771 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00007772 }
7773 break;
Richard Henderson1906b2a2015-07-02 13:59:21 +01007774
bellard3415a4d2004-01-04 15:21:33 +00007775 case 0x108: /* invd */
7776 case 0x109: /* wbinvd */
Richard Hendersonbc19f502021-05-14 10:12:54 -05007777 if (check_cpl0(s)) {
Richard Hendersonb53605d2021-05-14 10:13:29 -05007778 gen_svm_check_intercept(s, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD);
bellard3415a4d2004-01-04 15:21:33 +00007779 /* nothing to do */
7780 }
7781 break;
bellard14ce26e2005-01-03 23:50:08 +00007782 case 0x63: /* arpl or movslS (x86_64) */
7783#ifdef TARGET_X86_64
7784 if (CODE64(s)) {
7785 int d_ot;
7786 /* d_ot is the size of destination */
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007787 d_ot = dflag;
bellard14ce26e2005-01-03 23:50:08 +00007788
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007789 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05007790 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard14ce26e2005-01-03 23:50:08 +00007791 mod = (modrm >> 6) & 3;
7792 rm = (modrm & 7) | REX_B(s);
ths3b46e622007-09-17 08:09:54 +00007793
bellard14ce26e2005-01-03 23:50:08 +00007794 if (mod == 3) {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007795 gen_op_mov_v_reg(s, MO_32, s->T0, rm);
bellard14ce26e2005-01-03 23:50:08 +00007796 /* sign extend */
Richard Henderson4ba99382013-11-02 09:54:47 -07007797 if (d_ot == MO_64) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007798 tcg_gen_ext32s_tl(s->T0, s->T0);
Richard Henderson4ba99382013-11-02 09:54:47 -07007799 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007800 gen_op_mov_reg_v(s, d_ot, reg, s->T0);
bellard14ce26e2005-01-03 23:50:08 +00007801 } else {
Richard Henderson4eeb3932013-11-02 08:55:59 -10007802 gen_lea_modrm(env, s, modrm);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007803 gen_op_ld_v(s, MO_32 | MO_SIGN, s->T0, s->A0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007804 gen_op_mov_reg_v(s, d_ot, reg, s->T0);
bellard14ce26e2005-01-03 23:50:08 +00007805 }
ths5fafdf22007-09-16 21:08:06 +00007806 } else
bellard14ce26e2005-01-03 23:50:08 +00007807#endif
7808 {
Richard Henderson42a268c2015-02-13 12:51:55 -08007809 TCGLabel *label1;
Laurent Desnogues49d9fdc2009-10-06 10:14:29 +02007810 TCGv t0, t1, t2, a0;
bellard1e4840b2008-05-25 17:26:41 +00007811
Richard Hendersonf8a35842021-05-14 10:13:01 -05007812 if (!PE(s) || VM86(s))
bellard14ce26e2005-01-03 23:50:08 +00007813 goto illegal_op;
pbrooka7812ae2008-11-17 14:43:54 +00007814 t0 = tcg_temp_local_new();
7815 t1 = tcg_temp_local_new();
7816 t2 = tcg_temp_local_new();
Richard Henderson4ba99382013-11-02 09:54:47 -07007817 ot = MO_16;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007818 modrm = x86_ldub_code(env, s);
bellard14ce26e2005-01-03 23:50:08 +00007819 reg = (modrm >> 3) & 7;
7820 mod = (modrm >> 6) & 3;
7821 rm = modrm & 7;
7822 if (mod != 3) {
Richard Henderson4eeb3932013-11-02 08:55:59 -10007823 gen_lea_modrm(env, s, modrm);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007824 gen_op_ld_v(s, ot, t0, s->A0);
Laurent Desnogues49d9fdc2009-10-06 10:14:29 +02007825 a0 = tcg_temp_local_new();
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007826 tcg_gen_mov_tl(a0, s->A0);
bellard14ce26e2005-01-03 23:50:08 +00007827 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007828 gen_op_mov_v_reg(s, ot, t0, rm);
Richard Hendersonf7647182017-11-02 12:47:37 +01007829 a0 = NULL;
bellard14ce26e2005-01-03 23:50:08 +00007830 }
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007831 gen_op_mov_v_reg(s, ot, t1, reg);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007832 tcg_gen_andi_tl(s->tmp0, t0, 3);
bellard1e4840b2008-05-25 17:26:41 +00007833 tcg_gen_andi_tl(t1, t1, 3);
7834 tcg_gen_movi_tl(t2, 0);
bellard3bd7da92008-05-21 16:34:06 +00007835 label1 = gen_new_label();
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007836 tcg_gen_brcond_tl(TCG_COND_GE, s->tmp0, t1, label1);
bellard1e4840b2008-05-25 17:26:41 +00007837 tcg_gen_andi_tl(t0, t0, ~3);
7838 tcg_gen_or_tl(t0, t0, t1);
7839 tcg_gen_movi_tl(t2, CC_Z);
bellard3bd7da92008-05-21 16:34:06 +00007840 gen_set_label(label1);
bellard14ce26e2005-01-03 23:50:08 +00007841 if (mod != 3) {
Richard Henderson323d1872013-10-30 22:04:05 -07007842 gen_op_st_v(s, ot, t0, a0);
Laurent Desnogues49d9fdc2009-10-06 10:14:29 +02007843 tcg_temp_free(a0);
7844 } else {
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007845 gen_op_mov_reg_v(s, ot, rm, t0);
bellard14ce26e2005-01-03 23:50:08 +00007846 }
Richard Hendersond229edc2013-01-23 13:03:26 -08007847 gen_compute_eflags(s);
bellard3bd7da92008-05-21 16:34:06 +00007848 tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z);
bellard1e4840b2008-05-25 17:26:41 +00007849 tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2);
bellard1e4840b2008-05-25 17:26:41 +00007850 tcg_temp_free(t0);
7851 tcg_temp_free(t1);
7852 tcg_temp_free(t2);
bellardf115e912003-11-13 01:43:28 +00007853 }
bellardf115e912003-11-13 01:43:28 +00007854 break;
bellard2c0262a2003-09-30 20:34:21 +00007855 case 0x102: /* lar */
7856 case 0x103: /* lsl */
bellardcec68432008-05-21 16:25:27 +00007857 {
Richard Henderson42a268c2015-02-13 12:51:55 -08007858 TCGLabel *label1;
bellard1e4840b2008-05-25 17:26:41 +00007859 TCGv t0;
Richard Hendersonf8a35842021-05-14 10:13:01 -05007860 if (!PE(s) || VM86(s))
bellardcec68432008-05-21 16:25:27 +00007861 goto illegal_op;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10007862 ot = dflag != MO_16 ? MO_32 : MO_16;
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007863 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05007864 reg = ((modrm >> 3) & 7) | REX_R(s);
Richard Henderson4ba99382013-11-02 09:54:47 -07007865 gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
pbrooka7812ae2008-11-17 14:43:54 +00007866 t0 = tcg_temp_local_new();
Richard Henderson773cdfc2013-01-23 12:43:12 -08007867 gen_update_cc_op(s);
Blue Swirl2999a0b2012-04-29 19:47:06 +00007868 if (b == 0x102) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007869 gen_helper_lar(t0, cpu_env, s->T0);
Blue Swirl2999a0b2012-04-29 19:47:06 +00007870 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007871 gen_helper_lsl(t0, cpu_env, s->T0);
Blue Swirl2999a0b2012-04-29 19:47:06 +00007872 }
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007873 tcg_gen_andi_tl(s->tmp0, cpu_cc_src, CC_Z);
bellardcec68432008-05-21 16:25:27 +00007874 label1 = gen_new_label();
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04007875 tcg_gen_brcondi_tl(TCG_COND_EQ, s->tmp0, 0, label1);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04007876 gen_op_mov_reg_v(s, ot, reg, t0);
bellardcec68432008-05-21 16:25:27 +00007877 gen_set_label(label1);
Richard Henderson3ca51d02013-01-23 12:30:52 -08007878 set_cc_op(s, CC_OP_EFLAGS);
bellard1e4840b2008-05-25 17:26:41 +00007879 tcg_temp_free(t0);
bellardcec68432008-05-21 16:25:27 +00007880 }
bellard2c0262a2003-09-30 20:34:21 +00007881 break;
7882 case 0x118:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007883 modrm = x86_ldub_code(env, s);
bellard2c0262a2003-09-30 20:34:21 +00007884 mod = (modrm >> 6) & 3;
7885 op = (modrm >> 3) & 7;
7886 switch(op) {
7887 case 0: /* prefetchnta */
7888 case 1: /* prefetchnt0 */
7889 case 2: /* prefetchnt0 */
7890 case 3: /* prefetchnt0 */
7891 if (mod == 3)
7892 goto illegal_op;
Richard Henderson26317692016-03-02 10:31:35 -08007893 gen_nop_modrm(env, s, modrm);
bellard2c0262a2003-09-30 20:34:21 +00007894 /* nothing more to do */
7895 break;
bellarde17a36c2006-09-03 17:09:02 +00007896 default: /* nop (multi byte) */
Blue Swirl0af10c82012-09-08 13:26:02 +00007897 gen_nop_modrm(env, s, modrm);
bellarde17a36c2006-09-03 17:09:02 +00007898 break;
bellard2c0262a2003-09-30 20:34:21 +00007899 }
7900 break;
Richard Henderson62b58ba2015-07-06 19:10:23 +01007901 case 0x11a:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007902 modrm = x86_ldub_code(env, s);
Richard Henderson62b58ba2015-07-06 19:10:23 +01007903 if (s->flags & HF_MPX_EN_MASK) {
7904 mod = (modrm >> 6) & 3;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05007905 reg = ((modrm >> 3) & 7) | REX_R(s);
Richard Henderson523e28d2015-07-06 19:37:00 +01007906 if (prefixes & PREFIX_REPZ) {
7907 /* bndcl */
7908 if (reg >= 4
7909 || (prefixes & PREFIX_LOCK)
7910 || s->aflag == MO_16) {
7911 goto illegal_op;
7912 }
7913 gen_bndck(env, s, modrm, TCG_COND_LTU, cpu_bndl[reg]);
7914 } else if (prefixes & PREFIX_REPNZ) {
7915 /* bndcu */
7916 if (reg >= 4
7917 || (prefixes & PREFIX_LOCK)
7918 || s->aflag == MO_16) {
7919 goto illegal_op;
7920 }
7921 TCGv_i64 notu = tcg_temp_new_i64();
7922 tcg_gen_not_i64(notu, cpu_bndu[reg]);
7923 gen_bndck(env, s, modrm, TCG_COND_GTU, notu);
7924 tcg_temp_free_i64(notu);
7925 } else if (prefixes & PREFIX_DATA) {
Richard Henderson62b58ba2015-07-06 19:10:23 +01007926 /* bndmov -- from reg/mem */
7927 if (reg >= 4 || s->aflag == MO_16) {
7928 goto illegal_op;
7929 }
7930 if (mod == 3) {
7931 int reg2 = (modrm & 7) | REX_B(s);
7932 if (reg2 >= 4 || (prefixes & PREFIX_LOCK)) {
7933 goto illegal_op;
7934 }
7935 if (s->flags & HF_MPX_IU_MASK) {
7936 tcg_gen_mov_i64(cpu_bndl[reg], cpu_bndl[reg2]);
7937 tcg_gen_mov_i64(cpu_bndu[reg], cpu_bndu[reg2]);
7938 }
7939 } else {
7940 gen_lea_modrm(env, s, modrm);
7941 if (CODE64(s)) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007942 tcg_gen_qemu_ld_i64(cpu_bndl[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01007943 s->mem_index, MO_LEQ);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007944 tcg_gen_addi_tl(s->A0, s->A0, 8);
7945 tcg_gen_qemu_ld_i64(cpu_bndu[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01007946 s->mem_index, MO_LEQ);
7947 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007948 tcg_gen_qemu_ld_i64(cpu_bndl[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01007949 s->mem_index, MO_LEUL);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007950 tcg_gen_addi_tl(s->A0, s->A0, 4);
7951 tcg_gen_qemu_ld_i64(cpu_bndu[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01007952 s->mem_index, MO_LEUL);
7953 }
7954 /* bnd registers are now in-use */
7955 gen_set_hflag(s, HF_MPX_IU_MASK);
7956 }
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007957 } else if (mod != 3) {
7958 /* bndldx */
7959 AddressParts a = gen_lea_modrm_0(env, s, modrm);
7960 if (reg >= 4
7961 || (prefixes & PREFIX_LOCK)
7962 || s->aflag == MO_16
7963 || a.base < -1) {
7964 goto illegal_op;
7965 }
7966 if (a.base >= 0) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007967 tcg_gen_addi_tl(s->A0, cpu_regs[a.base], a.disp);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007968 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007969 tcg_gen_movi_tl(s->A0, 0);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007970 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04007971 gen_lea_v_seg(s, s->aflag, s->A0, a.def_seg, s->override);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007972 if (a.index >= 0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007973 tcg_gen_mov_tl(s->T0, cpu_regs[a.index]);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007974 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007975 tcg_gen_movi_tl(s->T0, 0);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007976 }
7977 if (CODE64(s)) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007978 gen_helper_bndldx64(cpu_bndl[reg], cpu_env, s->A0, s->T0);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007979 tcg_gen_ld_i64(cpu_bndu[reg], cpu_env,
7980 offsetof(CPUX86State, mmx_t0.MMX_Q(0)));
7981 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04007982 gen_helper_bndldx32(cpu_bndu[reg], cpu_env, s->A0, s->T0);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01007983 tcg_gen_ext32u_i64(cpu_bndl[reg], cpu_bndu[reg]);
7984 tcg_gen_shri_i64(cpu_bndu[reg], cpu_bndu[reg], 32);
7985 }
7986 gen_set_hflag(s, HF_MPX_IU_MASK);
Richard Henderson62b58ba2015-07-06 19:10:23 +01007987 }
7988 }
7989 gen_nop_modrm(env, s, modrm);
7990 break;
Richard Henderson149b4272015-07-09 08:22:46 +01007991 case 0x11b:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02007992 modrm = x86_ldub_code(env, s);
Richard Henderson149b4272015-07-09 08:22:46 +01007993 if (s->flags & HF_MPX_EN_MASK) {
7994 mod = (modrm >> 6) & 3;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05007995 reg = ((modrm >> 3) & 7) | REX_R(s);
Richard Henderson149b4272015-07-09 08:22:46 +01007996 if (mod != 3 && (prefixes & PREFIX_REPZ)) {
7997 /* bndmk */
7998 if (reg >= 4
7999 || (prefixes & PREFIX_LOCK)
8000 || s->aflag == MO_16) {
8001 goto illegal_op;
8002 }
8003 AddressParts a = gen_lea_modrm_0(env, s, modrm);
8004 if (a.base >= 0) {
8005 tcg_gen_extu_tl_i64(cpu_bndl[reg], cpu_regs[a.base]);
8006 if (!CODE64(s)) {
8007 tcg_gen_ext32u_i64(cpu_bndl[reg], cpu_bndl[reg]);
8008 }
8009 } else if (a.base == -1) {
8010 /* no base register has lower bound of 0 */
8011 tcg_gen_movi_i64(cpu_bndl[reg], 0);
8012 } else {
8013 /* rip-relative generates #ud */
8014 goto illegal_op;
8015 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008016 tcg_gen_not_tl(s->A0, gen_lea_modrm_1(s, a));
Richard Henderson149b4272015-07-09 08:22:46 +01008017 if (!CODE64(s)) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008018 tcg_gen_ext32u_tl(s->A0, s->A0);
Richard Henderson149b4272015-07-09 08:22:46 +01008019 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008020 tcg_gen_extu_tl_i64(cpu_bndu[reg], s->A0);
Richard Henderson149b4272015-07-09 08:22:46 +01008021 /* bnd registers are now in-use */
8022 gen_set_hflag(s, HF_MPX_IU_MASK);
8023 break;
Richard Henderson523e28d2015-07-06 19:37:00 +01008024 } else if (prefixes & PREFIX_REPNZ) {
8025 /* bndcn */
8026 if (reg >= 4
8027 || (prefixes & PREFIX_LOCK)
8028 || s->aflag == MO_16) {
8029 goto illegal_op;
8030 }
8031 gen_bndck(env, s, modrm, TCG_COND_GTU, cpu_bndu[reg]);
Richard Henderson62b58ba2015-07-06 19:10:23 +01008032 } else if (prefixes & PREFIX_DATA) {
8033 /* bndmov -- to reg/mem */
8034 if (reg >= 4 || s->aflag == MO_16) {
8035 goto illegal_op;
8036 }
8037 if (mod == 3) {
8038 int reg2 = (modrm & 7) | REX_B(s);
8039 if (reg2 >= 4 || (prefixes & PREFIX_LOCK)) {
8040 goto illegal_op;
8041 }
8042 if (s->flags & HF_MPX_IU_MASK) {
8043 tcg_gen_mov_i64(cpu_bndl[reg2], cpu_bndl[reg]);
8044 tcg_gen_mov_i64(cpu_bndu[reg2], cpu_bndu[reg]);
8045 }
8046 } else {
8047 gen_lea_modrm(env, s, modrm);
8048 if (CODE64(s)) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008049 tcg_gen_qemu_st_i64(cpu_bndl[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01008050 s->mem_index, MO_LEQ);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008051 tcg_gen_addi_tl(s->A0, s->A0, 8);
8052 tcg_gen_qemu_st_i64(cpu_bndu[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01008053 s->mem_index, MO_LEQ);
8054 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008055 tcg_gen_qemu_st_i64(cpu_bndl[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01008056 s->mem_index, MO_LEUL);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008057 tcg_gen_addi_tl(s->A0, s->A0, 4);
8058 tcg_gen_qemu_st_i64(cpu_bndu[reg], s->A0,
Richard Henderson62b58ba2015-07-06 19:10:23 +01008059 s->mem_index, MO_LEUL);
8060 }
8061 }
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008062 } else if (mod != 3) {
8063 /* bndstx */
8064 AddressParts a = gen_lea_modrm_0(env, s, modrm);
8065 if (reg >= 4
8066 || (prefixes & PREFIX_LOCK)
8067 || s->aflag == MO_16
8068 || a.base < -1) {
8069 goto illegal_op;
8070 }
8071 if (a.base >= 0) {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008072 tcg_gen_addi_tl(s->A0, cpu_regs[a.base], a.disp);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008073 } else {
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008074 tcg_gen_movi_tl(s->A0, 0);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008075 }
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008076 gen_lea_v_seg(s, s->aflag, s->A0, a.def_seg, s->override);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008077 if (a.index >= 0) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04008078 tcg_gen_mov_tl(s->T0, cpu_regs[a.index]);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008079 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04008080 tcg_gen_movi_tl(s->T0, 0);
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008081 }
8082 if (CODE64(s)) {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04008083 gen_helper_bndstx64(cpu_env, s->A0, s->T0,
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008084 cpu_bndl[reg], cpu_bndu[reg]);
8085 } else {
Emilio G. Cotac66f9722018-09-11 14:48:41 -04008086 gen_helper_bndstx32(cpu_env, s->A0, s->T0,
Richard Hendersonbdd87b32015-07-07 14:08:41 +01008087 cpu_bndl[reg], cpu_bndu[reg]);
8088 }
Richard Henderson149b4272015-07-09 08:22:46 +01008089 }
8090 }
8091 gen_nop_modrm(env, s, modrm);
8092 break;
Richard Henderson62b58ba2015-07-06 19:10:23 +01008093 case 0x119: case 0x11c ... 0x11f: /* nop (multi byte) */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02008094 modrm = x86_ldub_code(env, s);
Blue Swirl0af10c82012-09-08 13:26:02 +00008095 gen_nop_modrm(env, s, modrm);
bellarde17a36c2006-09-03 17:09:02 +00008096 break;
Richard Henderson7eff2e72021-05-14 10:13:31 -05008097
bellard2c0262a2003-09-30 20:34:21 +00008098 case 0x120: /* mov reg, crN */
8099 case 0x122: /* mov crN, reg */
Richard Henderson7eff2e72021-05-14 10:13:31 -05008100 if (!check_cpl0(s)) {
8101 break;
8102 }
8103 modrm = x86_ldub_code(env, s);
8104 /*
8105 * Ignore the mod bits (assume (modrm&0xc0)==0xc0).
8106 * AMD documentation (24594.pdf) and testing of Intel 386 and 486
8107 * processors all show that the mod bits are assumed to be 1's,
8108 * regardless of actual values.
8109 */
8110 rm = (modrm & 7) | REX_B(s);
8111 reg = ((modrm >> 3) & 7) | REX_R(s);
8112 switch (reg) {
8113 case 0:
8114 if ((prefixes & PREFIX_LOCK) &&
Andre Przywaraccd59d02009-09-19 00:30:47 +02008115 (s->cpuid_ext3_features & CPUID_EXT3_CR8LEG)) {
8116 reg = 8;
8117 }
Richard Henderson7eff2e72021-05-14 10:13:31 -05008118 break;
8119 case 2:
8120 case 3:
8121 case 4:
Richard Hendersone18a6ec2021-06-01 20:55:11 -07008122 case 8:
Richard Henderson7eff2e72021-05-14 10:13:31 -05008123 break;
8124 default:
8125 goto unknown_op;
8126 }
8127 ot = (CODE64(s) ? MO_64 : MO_32);
8128
8129 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
8130 gen_io_start();
8131 }
8132 if (b & 2) {
8133 gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0 + reg);
8134 gen_op_mov_v_reg(s, ot, s->T0, rm);
8135 gen_helper_write_crN(cpu_env, tcg_constant_i32(reg), s->T0);
8136 gen_jmp_im(s, s->pc - s->cs_base);
8137 gen_eob(s);
8138 } else {
8139 gen_svm_check_intercept(s, SVM_EXIT_READ_CR0 + reg);
8140 gen_helper_read_crN(s->T0, cpu_env, tcg_constant_i32(reg));
8141 gen_op_mov_reg_v(s, ot, rm, s->T0);
8142 if (tb_cflags(s->base.tb) & CF_USE_ICOUNT) {
8143 gen_jmp(s, s->pc - s->cs_base);
bellard2c0262a2003-09-30 20:34:21 +00008144 }
8145 }
8146 break;
Richard Henderson7eff2e72021-05-14 10:13:31 -05008147
bellard2c0262a2003-09-30 20:34:21 +00008148 case 0x121: /* mov reg, drN */
8149 case 0x123: /* mov drN, reg */
Richard Hendersonbc19f502021-05-14 10:12:54 -05008150 if (check_cpl0(s)) {
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02008151 modrm = x86_ldub_code(env, s);
Matthew Ogilvie5c73b752012-08-23 00:24:39 -06008152 /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
8153 * AMD documentation (24594.pdf) and testing of
8154 * intel 386 and 486 processors all show that the mod bits
8155 * are assumed to be 1's, regardless of actual values.
8156 */
bellard14ce26e2005-01-03 23:50:08 +00008157 rm = (modrm & 7) | REX_B(s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05008158 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard14ce26e2005-01-03 23:50:08 +00008159 if (CODE64(s))
Richard Henderson4ba99382013-11-02 09:54:47 -07008160 ot = MO_64;
bellard14ce26e2005-01-03 23:50:08 +00008161 else
Richard Henderson4ba99382013-11-02 09:54:47 -07008162 ot = MO_32;
Richard Hendersond0052332015-09-15 11:45:13 -07008163 if (reg >= 8) {
bellard2c0262a2003-09-30 20:34:21 +00008164 goto illegal_op;
Richard Hendersond0052332015-09-15 11:45:13 -07008165 }
bellard2c0262a2003-09-30 20:34:21 +00008166 if (b & 2) {
Richard Hendersonb53605d2021-05-14 10:13:29 -05008167 gen_svm_check_intercept(s, SVM_EXIT_WRITE_DR0 + reg);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04008168 gen_op_mov_v_reg(s, ot, s->T0, rm);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04008169 tcg_gen_movi_i32(s->tmp2_i32, reg);
8170 gen_helper_set_dr(cpu_env, s->tmp2_i32, s->T0);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04008171 gen_jmp_im(s, s->pc - s->cs_base);
bellard2c0262a2003-09-30 20:34:21 +00008172 gen_eob(s);
8173 } else {
Richard Hendersonb53605d2021-05-14 10:13:29 -05008174 gen_svm_check_intercept(s, SVM_EXIT_READ_DR0 + reg);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04008175 tcg_gen_movi_i32(s->tmp2_i32, reg);
8176 gen_helper_get_dr(s->T0, cpu_env, s->tmp2_i32);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04008177 gen_op_mov_reg_v(s, ot, rm, s->T0);
bellard2c0262a2003-09-30 20:34:21 +00008178 }
8179 }
8180 break;
8181 case 0x106: /* clts */
Richard Hendersonbc19f502021-05-14 10:12:54 -05008182 if (check_cpl0(s)) {
Richard Hendersonb53605d2021-05-14 10:13:29 -05008183 gen_svm_check_intercept(s, SVM_EXIT_WRITE_CR0);
Blue Swirlf0967a12012-04-29 12:45:34 +00008184 gen_helper_clts(cpu_env);
bellard7eee2a52004-02-25 23:17:58 +00008185 /* abort block because static cpu state changed */
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04008186 gen_jmp_im(s, s->pc - s->cs_base);
bellard7eee2a52004-02-25 23:17:58 +00008187 gen_eob(s);
bellard2c0262a2003-09-30 20:34:21 +00008188 }
8189 break;
balrog222a3332008-10-04 03:27:44 +00008190 /* MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4 support */
bellard664e0f12005-01-08 18:58:29 +00008191 case 0x1c3: /* MOVNTI reg, mem */
8192 if (!(s->cpuid_features & CPUID_SSE2))
8193 goto illegal_op;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10008194 ot = mo_64_32(dflag);
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02008195 modrm = x86_ldub_code(env, s);
bellard664e0f12005-01-08 18:58:29 +00008196 mod = (modrm >> 6) & 3;
8197 if (mod == 3)
8198 goto illegal_op;
Richard Hendersonbbdb4232021-05-14 10:13:09 -05008199 reg = ((modrm >> 3) & 7) | REX_R(s);
bellard664e0f12005-01-08 18:58:29 +00008200 /* generate a generic store */
Blue Swirl0af10c82012-09-08 13:26:02 +00008201 gen_ldst_modrm(env, s, modrm, ot, reg, 1);
bellard664e0f12005-01-08 18:58:29 +00008202 break;
8203 case 0x1ae:
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02008204 modrm = x86_ldub_code(env, s);
Richard Henderson121f3152015-11-17 15:08:57 +01008205 switch (modrm) {
Paolo Bonzini880f8482016-03-01 16:12:14 +01008206 CASE_MODRM_MEM_OP(0): /* fxsave */
Richard Henderson121f3152015-11-17 15:08:57 +01008207 if (!(s->cpuid_features & CPUID_FXSR)
8208 || (prefixes & PREFIX_LOCK)) {
bellard14ce26e2005-01-03 23:50:08 +00008209 goto illegal_op;
Richard Henderson121f3152015-11-17 15:08:57 +01008210 }
Kevin Wolf09d85fb2009-10-02 22:28:57 +02008211 if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
bellard0fd14b72006-02-04 17:40:20 +00008212 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
8213 break;
8214 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10008215 gen_lea_modrm(env, s, modrm);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008216 gen_helper_fxsave(cpu_env, s->A0);
bellard664e0f12005-01-08 18:58:29 +00008217 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008218
Paolo Bonzini880f8482016-03-01 16:12:14 +01008219 CASE_MODRM_MEM_OP(1): /* fxrstor */
Richard Henderson121f3152015-11-17 15:08:57 +01008220 if (!(s->cpuid_features & CPUID_FXSR)
8221 || (prefixes & PREFIX_LOCK)) {
bellard664e0f12005-01-08 18:58:29 +00008222 goto illegal_op;
Richard Henderson121f3152015-11-17 15:08:57 +01008223 }
Kevin Wolf09d85fb2009-10-02 22:28:57 +02008224 if ((s->flags & HF_EM_MASK) || (s->flags & HF_TS_MASK)) {
bellard0fd14b72006-02-04 17:40:20 +00008225 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
8226 break;
8227 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10008228 gen_lea_modrm(env, s, modrm);
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008229 gen_helper_fxrstor(cpu_env, s->A0);
bellard664e0f12005-01-08 18:58:29 +00008230 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008231
Paolo Bonzini880f8482016-03-01 16:12:14 +01008232 CASE_MODRM_MEM_OP(2): /* ldmxcsr */
Richard Henderson121f3152015-11-17 15:08:57 +01008233 if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) {
8234 goto illegal_op;
8235 }
bellard664e0f12005-01-08 18:58:29 +00008236 if (s->flags & HF_TS_MASK) {
8237 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
8238 break;
bellard14ce26e2005-01-03 23:50:08 +00008239 }
Richard Henderson4eeb3932013-11-02 08:55:59 -10008240 gen_lea_modrm(env, s, modrm);
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04008241 tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL);
8242 gen_helper_ldmxcsr(cpu_env, s->tmp2_i32);
bellard664e0f12005-01-08 18:58:29 +00008243 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008244
Paolo Bonzini880f8482016-03-01 16:12:14 +01008245 CASE_MODRM_MEM_OP(3): /* stmxcsr */
Richard Henderson121f3152015-11-17 15:08:57 +01008246 if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) {
bellard664e0f12005-01-08 18:58:29 +00008247 goto illegal_op;
Richard Henderson121f3152015-11-17 15:08:57 +01008248 }
8249 if (s->flags & HF_TS_MASK) {
8250 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
8251 break;
8252 }
Joseph Myers418b0f92020-06-25 23:58:31 +00008253 gen_helper_update_mxcsr(cpu_env);
Richard Henderson121f3152015-11-17 15:08:57 +01008254 gen_lea_modrm(env, s, modrm);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04008255 tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, mxcsr));
8256 gen_op_st_v(s, MO_32, s->T0, s->A0);
bellard664e0f12005-01-08 18:58:29 +00008257 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008258
Paolo Bonzini880f8482016-03-01 16:12:14 +01008259 CASE_MODRM_MEM_OP(4): /* xsave */
Richard Henderson19dc85d2015-07-02 14:53:40 +01008260 if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
8261 || (prefixes & (PREFIX_LOCK | PREFIX_DATA
8262 | PREFIX_REPZ | PREFIX_REPNZ))) {
8263 goto illegal_op;
8264 }
8265 gen_lea_modrm(env, s, modrm);
Emilio G. Cota776678b2018-09-11 14:22:31 -04008266 tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
Richard Henderson19dc85d2015-07-02 14:53:40 +01008267 cpu_regs[R_EDX]);
Emilio G. Cota776678b2018-09-11 14:22:31 -04008268 gen_helper_xsave(cpu_env, s->A0, s->tmp1_i64);
Richard Henderson19dc85d2015-07-02 14:53:40 +01008269 break;
8270
Paolo Bonzini880f8482016-03-01 16:12:14 +01008271 CASE_MODRM_MEM_OP(5): /* xrstor */
Richard Henderson19dc85d2015-07-02 14:53:40 +01008272 if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
8273 || (prefixes & (PREFIX_LOCK | PREFIX_DATA
8274 | PREFIX_REPZ | PREFIX_REPNZ))) {
8275 goto illegal_op;
8276 }
8277 gen_lea_modrm(env, s, modrm);
Emilio G. Cota776678b2018-09-11 14:22:31 -04008278 tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
Richard Henderson19dc85d2015-07-02 14:53:40 +01008279 cpu_regs[R_EDX]);
Emilio G. Cota776678b2018-09-11 14:22:31 -04008280 gen_helper_xrstor(cpu_env, s->A0, s->tmp1_i64);
Richard Hendersonf4f11102015-07-02 15:57:14 +01008281 /* XRSTOR is how MPX is enabled, which changes how
8282 we translate. Thus we need to end the TB. */
8283 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04008284 gen_jmp_im(s, s->pc - s->cs_base);
Richard Hendersonf4f11102015-07-02 15:57:14 +01008285 gen_eob(s);
Richard Henderson19dc85d2015-07-02 14:53:40 +01008286 break;
8287
Paolo Bonzini880f8482016-03-01 16:12:14 +01008288 CASE_MODRM_MEM_OP(6): /* xsaveopt / clwb */
Richard Henderson121f3152015-11-17 15:08:57 +01008289 if (prefixes & PREFIX_LOCK) {
8290 goto illegal_op;
8291 }
8292 if (prefixes & PREFIX_DATA) {
Eduardo Habkost5e1fac22015-11-04 19:24:45 -02008293 /* clwb */
Richard Henderson121f3152015-11-17 15:08:57 +01008294 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_CLWB)) {
Eduardo Habkost5e1fac22015-11-04 19:24:45 -02008295 goto illegal_op;
Richard Henderson121f3152015-11-17 15:08:57 +01008296 }
Eduardo Habkost5e1fac22015-11-04 19:24:45 -02008297 gen_nop_modrm(env, s, modrm);
Richard Hendersonc9cfe8f2015-07-02 15:21:23 +01008298 } else {
8299 /* xsaveopt */
8300 if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
8301 || (s->cpuid_xsave_features & CPUID_XSAVE_XSAVEOPT) == 0
8302 || (prefixes & (PREFIX_REPZ | PREFIX_REPNZ))) {
8303 goto illegal_op;
8304 }
8305 gen_lea_modrm(env, s, modrm);
Emilio G. Cota776678b2018-09-11 14:22:31 -04008306 tcg_gen_concat_tl_i64(s->tmp1_i64, cpu_regs[R_EAX],
Richard Hendersonc9cfe8f2015-07-02 15:21:23 +01008307 cpu_regs[R_EDX]);
Emilio G. Cota776678b2018-09-11 14:22:31 -04008308 gen_helper_xsaveopt(cpu_env, s->A0, s->tmp1_i64);
Richard Henderson121f3152015-11-17 15:08:57 +01008309 }
Richard Hendersonc9cfe8f2015-07-02 15:21:23 +01008310 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008311
Paolo Bonzini880f8482016-03-01 16:12:14 +01008312 CASE_MODRM_MEM_OP(7): /* clflush / clflushopt */
Richard Henderson121f3152015-11-17 15:08:57 +01008313 if (prefixes & PREFIX_LOCK) {
8314 goto illegal_op;
8315 }
8316 if (prefixes & PREFIX_DATA) {
8317 /* clflushopt */
8318 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_CLFLUSHOPT)) {
Eduardo Habkost5e1fac22015-11-04 19:24:45 -02008319 goto illegal_op;
Eduardo Habkost891bc822015-11-04 19:24:46 -02008320 }
bellard8f091a52005-07-23 17:41:26 +00008321 } else {
Richard Henderson121f3152015-11-17 15:08:57 +01008322 /* clflush */
8323 if ((s->prefix & (PREFIX_REPZ | PREFIX_REPNZ))
8324 || !(s->cpuid_features & CPUID_CLFLUSH)) {
8325 goto illegal_op;
Eduardo Habkost891bc822015-11-04 19:24:46 -02008326 }
Richard Henderson121f3152015-11-17 15:08:57 +01008327 }
8328 gen_nop_modrm(env, s, modrm);
8329 break;
8330
Richard Henderson07929f22015-11-18 12:55:47 +01008331 case 0xc0 ... 0xc7: /* rdfsbase (f3 0f ae /0) */
Todd Eisenbergere0dd5fd2017-09-28 10:17:06 -07008332 case 0xc8 ... 0xcf: /* rdgsbase (f3 0f ae /1) */
Richard Henderson07929f22015-11-18 12:55:47 +01008333 case 0xd0 ... 0xd7: /* wrfsbase (f3 0f ae /2) */
Todd Eisenbergere0dd5fd2017-09-28 10:17:06 -07008334 case 0xd8 ... 0xdf: /* wrgsbase (f3 0f ae /3) */
Richard Henderson07929f22015-11-18 12:55:47 +01008335 if (CODE64(s)
8336 && (prefixes & PREFIX_REPZ)
8337 && !(prefixes & PREFIX_LOCK)
8338 && (s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_FSGSBASE)) {
8339 TCGv base, treg, src, dst;
8340
8341 /* Preserve hflags bits by testing CR4 at runtime. */
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04008342 tcg_gen_movi_i32(s->tmp2_i32, CR4_FSGSBASE_MASK);
8343 gen_helper_cr4_testbit(cpu_env, s->tmp2_i32);
Richard Henderson07929f22015-11-18 12:55:47 +01008344
8345 base = cpu_seg_base[modrm & 8 ? R_GS : R_FS];
8346 treg = cpu_regs[(modrm & 7) | REX_B(s)];
8347
8348 if (modrm & 0x10) {
8349 /* wr*base */
8350 dst = base, src = treg;
8351 } else {
8352 /* rd*base */
8353 dst = treg, src = base;
8354 }
8355
8356 if (s->dflag == MO_32) {
8357 tcg_gen_ext32u_tl(dst, src);
8358 } else {
8359 tcg_gen_mov_tl(dst, src);
8360 }
8361 break;
8362 }
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08008363 goto unknown_op;
Richard Henderson07929f22015-11-18 12:55:47 +01008364
Richard Henderson121f3152015-11-17 15:08:57 +01008365 case 0xf8: /* sfence / pcommit */
8366 if (prefixes & PREFIX_DATA) {
8367 /* pcommit */
8368 if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_PCOMMIT)
8369 || (prefixes & PREFIX_LOCK)) {
8370 goto illegal_op;
8371 }
8372 break;
8373 }
8374 /* fallthru */
8375 case 0xf9 ... 0xff: /* sfence */
Paolo Bonzini14cb9492016-05-16 11:11:29 +02008376 if (!(s->cpuid_features & CPUID_SSE)
8377 || (prefixes & PREFIX_LOCK)) {
8378 goto illegal_op;
8379 }
Pranith Kumarcc19e492016-07-14 16:20:26 -04008380 tcg_gen_mb(TCG_MO_ST_ST | TCG_BAR_SC);
Paolo Bonzini14cb9492016-05-16 11:11:29 +02008381 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008382 case 0xe8 ... 0xef: /* lfence */
Pranith Kumarcc19e492016-07-14 16:20:26 -04008383 if (!(s->cpuid_features & CPUID_SSE)
8384 || (prefixes & PREFIX_LOCK)) {
8385 goto illegal_op;
8386 }
8387 tcg_gen_mb(TCG_MO_LD_LD | TCG_BAR_SC);
8388 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008389 case 0xf0 ... 0xf7: /* mfence */
8390 if (!(s->cpuid_features & CPUID_SSE2)
8391 || (prefixes & PREFIX_LOCK)) {
8392 goto illegal_op;
bellard8f091a52005-07-23 17:41:26 +00008393 }
Pranith Kumarcc19e492016-07-14 16:20:26 -04008394 tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
bellard8f091a52005-07-23 17:41:26 +00008395 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008396
bellard664e0f12005-01-08 18:58:29 +00008397 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08008398 goto unknown_op;
bellard14ce26e2005-01-03 23:50:08 +00008399 }
8400 break;
Richard Henderson121f3152015-11-17 15:08:57 +01008401
aurel32a35f3ec2008-04-08 19:51:29 +00008402 case 0x10d: /* 3DNow! prefetch(w) */
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02008403 modrm = x86_ldub_code(env, s);
aurel32a35f3ec2008-04-08 19:51:29 +00008404 mod = (modrm >> 6) & 3;
8405 if (mod == 3)
8406 goto illegal_op;
Richard Henderson26317692016-03-02 10:31:35 -08008407 gen_nop_modrm(env, s, modrm);
bellard8f091a52005-07-23 17:41:26 +00008408 break;
bellard3b21e032006-09-24 18:41:56 +00008409 case 0x1aa: /* rsm */
Richard Hendersonb53605d2021-05-14 10:13:29 -05008410 gen_svm_check_intercept(s, SVM_EXIT_RSM);
bellard3b21e032006-09-24 18:41:56 +00008411 if (!(s->flags & HF_SMM_MASK))
8412 goto illegal_op;
Claudio Fontanaa93b55e2021-03-22 14:27:47 +01008413#ifdef CONFIG_USER_ONLY
8414 /* we should not be in SMM mode */
8415 g_assert_not_reached();
8416#else
Jun Koi728d8032010-07-25 12:30:03 +09008417 gen_update_cc_op(s);
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04008418 gen_jmp_im(s, s->pc - s->cs_base);
Blue Swirl608badf2012-04-29 17:54:21 +00008419 gen_helper_rsm(cpu_env);
Claudio Fontanaa93b55e2021-03-22 14:27:47 +01008420#endif /* CONFIG_USER_ONLY */
bellard3b21e032006-09-24 18:41:56 +00008421 gen_eob(s);
8422 break;
balrog222a3332008-10-04 03:27:44 +00008423 case 0x1b8: /* SSE4.2 popcnt */
8424 if ((prefixes & (PREFIX_REPZ | PREFIX_LOCK | PREFIX_REPNZ)) !=
8425 PREFIX_REPZ)
8426 goto illegal_op;
8427 if (!(s->cpuid_ext_features & CPUID_EXT_POPCNT))
8428 goto illegal_op;
8429
Paolo Bonzinie3af7c72017-04-26 13:59:34 +02008430 modrm = x86_ldub_code(env, s);
Richard Hendersonbbdb4232021-05-14 10:13:09 -05008431 reg = ((modrm >> 3) & 7) | REX_R(s);
balrog222a3332008-10-04 03:27:44 +00008432
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10008433 if (s->prefix & PREFIX_DATA) {
Richard Henderson4ba99382013-11-02 09:54:47 -07008434 ot = MO_16;
Richard Hendersonab4e4ae2013-11-06 09:37:57 +10008435 } else {
8436 ot = mo_64_32(dflag);
8437 }
balrog222a3332008-10-04 03:27:44 +00008438
Blue Swirl0af10c82012-09-08 13:26:02 +00008439 gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 0);
Emilio G. Cotac66f9722018-09-11 14:48:41 -04008440 gen_extu(ot, s->T0);
8441 tcg_gen_mov_tl(cpu_cc_src, s->T0);
8442 tcg_gen_ctpop_tl(s->T0, s->T0);
Emilio G. Cota1dbe15e2018-09-11 16:07:54 -04008443 gen_op_mov_reg_v(s, ot, reg, s->T0);
balrogfdb0d092008-10-04 03:32:00 +00008444
Richard Henderson4885c3c2016-11-21 12:18:53 +01008445 set_cc_op(s, CC_OP_POPCNT);
balrog222a3332008-10-04 03:27:44 +00008446 break;
aurel32a35f3ec2008-04-08 19:51:29 +00008447 case 0x10e ... 0x10f:
8448 /* 3DNow! instructions, ignore prefixes */
8449 s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA);
Paolo Bonziniedd75412018-08-01 17:14:09 +02008450 /* fall through */
bellard664e0f12005-01-08 18:58:29 +00008451 case 0x110 ... 0x117:
8452 case 0x128 ... 0x12f:
balrog4242b1b2008-09-25 18:01:46 +00008453 case 0x138 ... 0x13a:
Andre Przywarad9f4bb22009-09-19 00:30:48 +02008454 case 0x150 ... 0x179:
bellard664e0f12005-01-08 18:58:29 +00008455 case 0x17c ... 0x17f:
8456 case 0x1c2:
8457 case 0x1c4 ... 0x1c6:
8458 case 0x1d0 ... 0x1fe:
Richard Hendersonbbdb4232021-05-14 10:13:09 -05008459 gen_sse(env, s, b, pc_start);
bellard14ce26e2005-01-03 23:50:08 +00008460 break;
bellard2c0262a2003-09-30 20:34:21 +00008461 default:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08008462 goto unknown_op;
bellard2c0262a2003-09-30 20:34:21 +00008463 }
bellard2c0262a2003-09-30 20:34:21 +00008464 return s->pc;
8465 illegal_op:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08008466 gen_illegal_opcode(s);
8467 return s->pc;
8468 unknown_op:
Richard Hendersonb9f9c5b2016-03-01 16:53:18 -08008469 gen_unknown_opcode(env, s);
bellard2c0262a2003-09-30 20:34:21 +00008470 return s->pc;
8471}
8472
Eduardo Habkost63618b42015-03-05 12:38:48 -03008473void tcg_x86_init(void)
bellard2c0262a2003-09-30 20:34:21 +00008474{
Richard Hendersonfac0aff2013-11-06 16:38:38 +10008475 static const char reg_names[CPU_NB_REGS][4] = {
8476#ifdef TARGET_X86_64
8477 [R_EAX] = "rax",
8478 [R_EBX] = "rbx",
8479 [R_ECX] = "rcx",
8480 [R_EDX] = "rdx",
8481 [R_ESI] = "rsi",
8482 [R_EDI] = "rdi",
8483 [R_EBP] = "rbp",
8484 [R_ESP] = "rsp",
8485 [8] = "r8",
8486 [9] = "r9",
8487 [10] = "r10",
8488 [11] = "r11",
8489 [12] = "r12",
8490 [13] = "r13",
8491 [14] = "r14",
8492 [15] = "r15",
8493#else
8494 [R_EAX] = "eax",
8495 [R_EBX] = "ebx",
8496 [R_ECX] = "ecx",
8497 [R_EDX] = "edx",
8498 [R_ESI] = "esi",
8499 [R_EDI] = "edi",
8500 [R_EBP] = "ebp",
8501 [R_ESP] = "esp",
8502#endif
8503 };
Richard Henderson3558f802015-12-17 11:19:21 -08008504 static const char seg_base_names[6][8] = {
8505 [R_CS] = "cs_base",
8506 [R_DS] = "ds_base",
8507 [R_ES] = "es_base",
8508 [R_FS] = "fs_base",
8509 [R_GS] = "gs_base",
8510 [R_SS] = "ss_base",
8511 };
Richard Henderson149b4272015-07-09 08:22:46 +01008512 static const char bnd_regl_names[4][8] = {
8513 "bnd0_lb", "bnd1_lb", "bnd2_lb", "bnd3_lb"
8514 };
8515 static const char bnd_regu_names[4][8] = {
8516 "bnd0_ub", "bnd1_ub", "bnd2_ub", "bnd3_ub"
8517 };
Richard Hendersonfac0aff2013-11-06 16:38:38 +10008518 int i;
8519
Richard Hendersone1ccc052013-09-18 12:53:09 -07008520 cpu_cc_op = tcg_global_mem_new_i32(cpu_env,
Andreas Färber317ac622012-03-14 01:38:21 +01008521 offsetof(CPUX86State, cc_op), "cc_op");
Richard Hendersone1ccc052013-09-18 12:53:09 -07008522 cpu_cc_dst = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, cc_dst),
pbrooka7812ae2008-11-17 14:43:54 +00008523 "cc_dst");
Richard Hendersone1ccc052013-09-18 12:53:09 -07008524 cpu_cc_src = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, cc_src),
Richard Hendersona3251182013-01-23 15:43:03 -08008525 "cc_src");
Richard Hendersone1ccc052013-09-18 12:53:09 -07008526 cpu_cc_src2 = tcg_global_mem_new(cpu_env, offsetof(CPUX86State, cc_src2),
Richard Henderson988c3eb2013-01-23 16:03:16 -08008527 "cc_src2");
bellard437a88a2008-05-22 16:11:04 +00008528
Richard Hendersonfac0aff2013-11-06 16:38:38 +10008529 for (i = 0; i < CPU_NB_REGS; ++i) {
Richard Hendersone1ccc052013-09-18 12:53:09 -07008530 cpu_regs[i] = tcg_global_mem_new(cpu_env,
Richard Hendersonfac0aff2013-11-06 16:38:38 +10008531 offsetof(CPUX86State, regs[i]),
8532 reg_names[i]);
8533 }
KONRAD Frederic677ef622015-08-10 17:27:02 +02008534
Richard Henderson3558f802015-12-17 11:19:21 -08008535 for (i = 0; i < 6; ++i) {
8536 cpu_seg_base[i]
8537 = tcg_global_mem_new(cpu_env,
8538 offsetof(CPUX86State, segs[i].base),
8539 seg_base_names[i]);
8540 }
8541
Richard Henderson149b4272015-07-09 08:22:46 +01008542 for (i = 0; i < 4; ++i) {
8543 cpu_bndl[i]
8544 = tcg_global_mem_new_i64(cpu_env,
8545 offsetof(CPUX86State, bnd_regs[i].lb),
8546 bnd_regl_names[i]);
8547 cpu_bndu[i]
8548 = tcg_global_mem_new_i64(cpu_env,
8549 offsetof(CPUX86State, bnd_regs[i].ub),
8550 bnd_regu_names[i]);
8551 }
bellard2c0262a2003-09-30 20:34:21 +00008552}
8553
Emilio G. Cotab5426832018-02-19 20:51:58 -05008554static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
bellard2c0262a2003-09-30 20:34:21 +00008555{
Lluís Vilanova9761d392017-07-14 11:33:44 +03008556 DisasContext *dc = container_of(dcbase, DisasContext, base);
8557 CPUX86State *env = cpu->env_ptr;
8558 uint32_t flags = dc->base.tb->flags;
Richard Henderson01b9d8c2021-05-14 10:12:59 -05008559 int cpl = (flags >> HF_CPL_SHIFT) & 3;
Richard Henderson0ab011c2021-05-14 10:13:00 -05008560 int iopl = (flags >> IOPL_SHIFT) & 3;
bellard3a1d9b82004-02-16 22:10:33 +00008561
Richard Hendersond75f9122021-05-14 10:12:58 -05008562 dc->cs_base = dc->base.tb->cs_base;
8563 dc->flags = flags;
Richard Henderson01b9d8c2021-05-14 10:12:59 -05008564#ifndef CONFIG_USER_ONLY
8565 dc->cpl = cpl;
Richard Henderson0ab011c2021-05-14 10:13:00 -05008566 dc->iopl = iopl;
Richard Henderson01b9d8c2021-05-14 10:12:59 -05008567#endif
Richard Hendersond75f9122021-05-14 10:12:58 -05008568
8569 /* We make some simplifying assumptions; validate they're correct. */
8570 g_assert(PE(dc) == ((flags & HF_PE_MASK) != 0));
Richard Henderson01b9d8c2021-05-14 10:12:59 -05008571 g_assert(CPL(dc) == cpl);
Richard Henderson0ab011c2021-05-14 10:13:00 -05008572 g_assert(IOPL(dc) == iopl);
Richard Hendersonf8a35842021-05-14 10:13:01 -05008573 g_assert(VM86(dc) == ((flags & HF_VM_MASK) != 0));
Richard Henderson9996dcf2021-05-14 10:13:02 -05008574 g_assert(CODE32(dc) == ((flags & HF_CS32_MASK) != 0));
Richard Hendersoneec7d0f2021-05-14 10:13:04 -05008575 g_assert(CODE64(dc) == ((flags & HF_CS64_MASK) != 0));
Richard Hendersonb40a47a2021-05-14 10:13:03 -05008576 g_assert(SS32(dc) == ((flags & HF_SS32_MASK) != 0));
Richard Henderson73e90dc2021-05-14 10:13:05 -05008577 g_assert(LMA(dc) == ((flags & HF_LMA_MASK) != 0));
Richard Hendersonbeedb932021-05-14 10:13:06 -05008578 g_assert(ADDSEG(dc) == ((flags & HF_ADDSEG_MASK) != 0));
Richard Henderson5d223882021-05-14 10:13:22 -05008579 g_assert(SVME(dc) == ((flags & HF_SVME_MASK) != 0));
Richard Hendersonb322b3a2021-05-14 10:13:23 -05008580 g_assert(GUEST(dc) == ((flags & HF_GUEST_MASK) != 0));
Richard Hendersond75f9122021-05-14 10:12:58 -05008581
bellard2c0262a2003-09-30 20:34:21 +00008582 dc->cc_op = CC_OP_DYNAMIC;
Richard Hendersone2075822013-01-23 12:34:26 -08008583 dc->cc_op_dirty = false;
bellard2c0262a2003-09-30 20:34:21 +00008584 dc->popl_esp_hack = 0;
8585 /* select memory access functions */
8586 dc->mem_index = 0;
Sergey Fedorovda6d48e2016-07-15 20:58:45 +03008587#ifdef CONFIG_SOFTMMU
8588 dc->mem_index = cpu_mmu_index(env, false);
8589#endif
Eduardo Habkost0514ef22013-04-22 16:00:15 -03008590 dc->cpuid_features = env->features[FEAT_1_EDX];
8591 dc->cpuid_ext_features = env->features[FEAT_1_ECX];
8592 dc->cpuid_ext2_features = env->features[FEAT_8000_0001_EDX];
8593 dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
8594 dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
Richard Hendersonc9cfe8f2015-07-02 15:21:23 +01008595 dc->cpuid_xsave_features = env->features[FEAT_XSAVE];
Richard Hendersonc1de1a12021-05-14 10:13:17 -05008596 dc->jmp_opt = !(dc->base.singlestep_enabled ||
8597 (flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)));
Richard Henderson3236c2a2021-05-14 10:13:19 -05008598 /*
8599 * If jmp_opt, we want to handle each string instruction individually.
8600 * For icount also disable repz optimization so that each iteration
8601 * is accounted separately.
Pavel Dovgalyukc4d45252014-12-05 12:11:13 +03008602 */
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04008603 dc->repz_opt = !dc->jmp_opt && !(tb_cflags(dc->base.tb) & CF_USE_ICOUNT);
bellard4f319162004-01-04 17:35:00 +00008604
Emilio G. Cotac66f9722018-09-11 14:48:41 -04008605 dc->T0 = tcg_temp_new();
Emilio G. Cotab48597b2018-09-11 14:50:46 -04008606 dc->T1 = tcg_temp_new();
Emilio G. Cota6b672b52018-09-11 14:41:57 -04008607 dc->A0 = tcg_temp_new();
bellard1e4840b2008-05-25 17:26:41 +00008608
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04008609 dc->tmp0 = tcg_temp_new();
Emilio G. Cota776678b2018-09-11 14:22:31 -04008610 dc->tmp1_i64 = tcg_temp_new_i64();
Emilio G. Cota6bd48f62018-09-11 14:17:18 -04008611 dc->tmp2_i32 = tcg_temp_new_i32();
Emilio G. Cota4f824462018-09-11 14:17:56 -04008612 dc->tmp3_i32 = tcg_temp_new_i32();
Emilio G. Cota5022f282018-09-11 14:10:21 -04008613 dc->tmp4 = tcg_temp_new();
Emilio G. Cota2ee26462018-09-11 14:11:35 -04008614 dc->ptr0 = tcg_temp_new_ptr();
Emilio G. Cota6387e832018-09-11 14:14:06 -04008615 dc->ptr1 = tcg_temp_new_ptr();
Emilio G. Cota93a3e102018-09-11 14:38:47 -04008616 dc->cc_srcT = tcg_temp_local_new();
Lluís Vilanova9761d392017-07-14 11:33:44 +03008617}
8618
Lluís Vilanovad2e6eed2017-07-14 11:57:57 +03008619static void i386_tr_tb_start(DisasContextBase *db, CPUState *cpu)
8620{
8621}
8622
Lluís Vilanova9d75f522017-07-14 11:37:46 +03008623static void i386_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
8624{
8625 DisasContext *dc = container_of(dcbase, DisasContext, base);
8626
8627 tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
8628}
8629
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008630static void i386_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
8631{
8632 DisasContext *dc = container_of(dcbase, DisasContext, base);
Richard Hendersonb26491b2020-02-12 19:22:21 -08008633 target_ulong pc_next;
8634
8635#ifdef TARGET_VSYSCALL_PAGE
8636 /*
8637 * Detect entry into the vsyscall page and invoke the syscall.
8638 */
8639 if ((dc->base.pc_next & TARGET_PAGE_MASK) == TARGET_VSYSCALL_PAGE) {
8640 gen_exception(dc, EXCP_VSYSCALL, dc->base.pc_next);
Ilya Leoshkevich9b210492021-05-19 06:57:37 +02008641 dc->base.pc_next = dc->pc + 1;
Richard Hendersonb26491b2020-02-12 19:22:21 -08008642 return;
8643 }
8644#endif
8645
8646 pc_next = disas_insn(dc, cpu);
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008647
Richard Hendersonc1de1a12021-05-14 10:13:17 -05008648 if (dc->flags & (HF_TF_MASK | HF_INHIBIT_IRQ_MASK)) {
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008649 /* if single step mode, we generate only one instruction and
8650 generate an exception */
8651 /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
8652 the flag and abort the translation to give the irqs a
8653 chance to happen */
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008654 dc->base.is_jmp = DISAS_TOO_MANY;
Emilio G. Cotac5a49c62017-07-18 20:46:52 -04008655 } else if ((tb_cflags(dc->base.tb) & CF_USE_ICOUNT)
Pavel Dovgalyuk41d54dc2018-09-20 10:17:03 +03008656 && ((pc_next & TARGET_PAGE_MASK)
8657 != ((pc_next + TARGET_MAX_INSN_SIZE - 1)
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008658 & TARGET_PAGE_MASK)
Pavel Dovgalyuk41d54dc2018-09-20 10:17:03 +03008659 || (pc_next & ~TARGET_PAGE_MASK) == 0)) {
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008660 /* Do not cross the boundary of the pages in icount mode,
8661 it can cause an exception. Do it only when boundary is
8662 crossed by the first instruction in the block.
8663 If current instruction already crossed the bound - it's ok,
8664 because an exception hasn't stopped this code.
8665 */
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008666 dc->base.is_jmp = DISAS_TOO_MANY;
8667 } else if ((pc_next - dc->base.pc_first) >= (TARGET_PAGE_SIZE - 32)) {
Lluís Vilanova2c2f8ca2017-07-14 11:45:50 +03008668 dc->base.is_jmp = DISAS_TOO_MANY;
8669 }
8670
8671 dc->base.pc_next = pc_next;
8672}
8673
Lluís Vilanova47e981b2017-07-14 11:49:53 +03008674static void i386_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
8675{
8676 DisasContext *dc = container_of(dcbase, DisasContext, base);
8677
8678 if (dc->base.is_jmp == DISAS_TOO_MANY) {
Emilio G. Cotafbd80f02018-09-11 14:07:57 -04008679 gen_jmp_im(dc, dc->base.pc_next - dc->cs_base);
Lluís Vilanova47e981b2017-07-14 11:49:53 +03008680 gen_eob(dc);
8681 }
8682}
8683
Lluís Vilanovae0d110d2017-07-14 11:53:55 +03008684static void i386_tr_disas_log(const DisasContextBase *dcbase,
8685 CPUState *cpu)
8686{
8687 DisasContext *dc = container_of(dcbase, DisasContext, base);
Lluís Vilanovae0d110d2017-07-14 11:53:55 +03008688
8689 qemu_log("IN: %s\n", lookup_symbol(dc->base.pc_first));
Richard Henderson1d484742017-09-14 08:38:35 -07008690 log_target_disas(cpu, dc->base.pc_first, dc->base.tb->size);
Lluís Vilanovae0d110d2017-07-14 11:53:55 +03008691}
8692
Lluís Vilanovad2e6eed2017-07-14 11:57:57 +03008693static const TranslatorOps i386_tr_ops = {
8694 .init_disas_context = i386_tr_init_disas_context,
8695 .tb_start = i386_tr_tb_start,
8696 .insn_start = i386_tr_insn_start,
Lluís Vilanovad2e6eed2017-07-14 11:57:57 +03008697 .translate_insn = i386_tr_translate_insn,
8698 .tb_stop = i386_tr_tb_stop,
8699 .disas_log = i386_tr_disas_log,
8700};
8701
Lluís Vilanova9761d392017-07-14 11:33:44 +03008702/* generate intermediate code for basic block 'tb'. */
Richard Henderson8b86d6d2019-04-15 20:54:54 -10008703void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int max_insns)
Lluís Vilanova9761d392017-07-14 11:33:44 +03008704{
Lluís Vilanovad2e6eed2017-07-14 11:57:57 +03008705 DisasContext dc;
Lluís Vilanova9761d392017-07-14 11:33:44 +03008706
Richard Henderson8b86d6d2019-04-15 20:54:54 -10008707 translator_loop(&i386_tr_ops, &dc.base, cpu, tb, max_insns);
bellard2c0262a2003-09-30 20:34:21 +00008708}
8709
Richard Hendersonbad729e2015-09-01 15:51:12 -07008710void restore_state_to_opc(CPUX86State *env, TranslationBlock *tb,
8711 target_ulong *data)
aurel32d2856f12008-04-28 00:32:32 +00008712{
Richard Hendersonbad729e2015-09-01 15:51:12 -07008713 int cc_op = data[1];
8714 env->eip = data[0] - tb->cs_base;
8715 if (cc_op != CC_OP_DYNAMIC) {
aurel32d2856f12008-04-28 00:32:32 +00008716 env->cc_op = cc_op;
Richard Hendersonbad729e2015-09-01 15:51:12 -07008717 }
aurel32d2856f12008-04-28 00:32:32 +00008718}