target/i386: validate VEX prefixes via the instructions' exception classes
[qemu.git] / target / i386 / tcg / emit.c.inc
blob85b0aeac602d3eb9c399bbe2c90ce66084ba4f2d
1 /*
2  * New-style TCG opcode generator for i386 instructions
3  *
4  *  Copyright (c) 2022 Red Hat, Inc.
5  *
6  * Author: Paolo Bonzini <pbonzini@redhat.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20  */
22 static void gen_NM_exception(DisasContext *s)
24     gen_exception(s, EXCP07_PREX);
27 static void gen_illegal(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode)
29     gen_illegal_opcode(s);
32 static void gen_load_ea(DisasContext *s, AddressParts *mem, bool is_vsib)
34     TCGv ea = gen_lea_modrm_1(s, *mem, is_vsib);
35     gen_lea_v_seg(s, s->aflag, ea, mem->def_seg, s->override);
38 static inline int mmx_offset(MemOp ot)
40     switch (ot) {
41     case MO_8:
42         return offsetof(MMXReg, MMX_B(0));
43     case MO_16:
44         return offsetof(MMXReg, MMX_W(0));
45     case MO_32:
46         return offsetof(MMXReg, MMX_L(0));
47     case MO_64:
48         return offsetof(MMXReg, MMX_Q(0));
49     default:
50         g_assert_not_reached();
51     }
54 static inline int xmm_offset(MemOp ot)
56     switch (ot) {
57     case MO_8:
58         return offsetof(ZMMReg, ZMM_B(0));
59     case MO_16:
60         return offsetof(ZMMReg, ZMM_W(0));
61     case MO_32:
62         return offsetof(ZMMReg, ZMM_L(0));
63     case MO_64:
64         return offsetof(ZMMReg, ZMM_Q(0));
65     case MO_128:
66         return offsetof(ZMMReg, ZMM_X(0));
67     case MO_256:
68         return offsetof(ZMMReg, ZMM_Y(0));
69     default:
70         g_assert_not_reached();
71     }
74 static void compute_mmx_offset(X86DecodedOp *op)
76     if (!op->has_ea) {
77         op->offset = offsetof(CPUX86State, fpregs[op->n].mmx) + mmx_offset(op->ot);
78     } else {
79         op->offset = offsetof(CPUX86State, mmx_t0) + mmx_offset(op->ot);
80     }
83 static void compute_xmm_offset(X86DecodedOp *op)
85     if (!op->has_ea) {
86         op->offset = ZMM_OFFSET(op->n) + xmm_offset(op->ot);
87     } else {
88         op->offset = offsetof(CPUX86State, xmm_t0) + xmm_offset(op->ot);
89     }
92 static void gen_load_sse(DisasContext *s, TCGv temp, MemOp ot, int dest_ofs, bool aligned)
94     switch(ot) {
95     case MO_8:
96         gen_op_ld_v(s, MO_8, temp, s->A0);
97         tcg_gen_st8_tl(temp, cpu_env, dest_ofs);
98         break;
99     case MO_16:
100         gen_op_ld_v(s, MO_16, temp, s->A0);
101         tcg_gen_st16_tl(temp, cpu_env, dest_ofs);
102         break;
103     case MO_32:
104         gen_op_ld_v(s, MO_32, temp, s->A0);
105         tcg_gen_st32_tl(temp, cpu_env, dest_ofs);
106         break;
107     case MO_64:
108         gen_ldq_env_A0(s, dest_ofs);
109         break;
110     case MO_128:
111         gen_ldo_env_A0(s, dest_ofs, aligned);
112         break;
113     case MO_256:
114         gen_ldy_env_A0(s, dest_ofs, aligned);
115         break;
116     default:
117         g_assert_not_reached();
118     }
121 static bool sse_needs_alignment(DisasContext *s, X86DecodedInsn *decode, MemOp ot)
123     switch (decode->e.vex_class) {
124     case 2:
125     case 4:
126         if ((s->prefix & PREFIX_VEX) ||
127             decode->e.vex_special == X86_VEX_SSEUnaligned) {
128             /* MOST legacy SSE instructions require aligned memory operands, but not all.  */
129             return false;
130         }
131         /* fall through */
132     case 1:
133         return ot >= MO_128;
135     default:
136         return false;
137     }
140 static void gen_load(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv v)
142     X86DecodedOp *op = &decode->op[opn];
144     switch (op->unit) {
145     case X86_OP_SKIP:
146         return;
147     case X86_OP_SEG:
148         tcg_gen_ld32u_tl(v, cpu_env,
149                          offsetof(CPUX86State,segs[op->n].selector));
150         break;
151     case X86_OP_CR:
152         tcg_gen_ld_tl(v, cpu_env, offsetof(CPUX86State, cr[op->n]));
153         break;
154     case X86_OP_DR:
155         tcg_gen_ld_tl(v, cpu_env, offsetof(CPUX86State, dr[op->n]));
156         break;
157     case X86_OP_INT:
158         if (op->has_ea) {
159             gen_op_ld_v(s, op->ot, v, s->A0);
160         } else {
161             gen_op_mov_v_reg(s, op->ot, v, op->n);
162         }
163         break;
164     case X86_OP_IMM:
165         tcg_gen_movi_tl(v, decode->immediate);
166         break;
168     case X86_OP_MMX:
169         compute_mmx_offset(op);
170         goto load_vector;
172     case X86_OP_SSE:
173         compute_xmm_offset(op);
174     load_vector:
175         if (op->has_ea) {
176             bool aligned = sse_needs_alignment(s, decode, op->ot);
177             gen_load_sse(s, v, op->ot, op->offset, aligned);
178         }
179         break;
181     default:
182         g_assert_not_reached();
183     }
186 static void gen_writeback(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv v)
188     X86DecodedOp *op = &decode->op[opn];
189     switch (op->unit) {
190     case X86_OP_SKIP:
191         break;
192     case X86_OP_SEG:
193         /* Note that gen_movl_seg_T0 takes care of interrupt shadow and TF.  */
194         gen_movl_seg_T0(s, op->n);
195         break;
196     case X86_OP_INT:
197         if (op->has_ea) {
198             gen_op_st_v(s, op->ot, v, s->A0);
199         } else {
200             gen_op_mov_reg_v(s, op->ot, op->n, v);
201         }
202         break;
203     case X86_OP_MMX:
204         break;
205     case X86_OP_SSE:
206         if ((s->prefix & PREFIX_VEX) && op->ot == MO_128) {
207             tcg_gen_gvec_dup_imm(MO_64,
208                                  offsetof(CPUX86State, xmm_regs[op->n].ZMM_X(1)),
209                                  16, 16, 0);
210         }
211         break;
212     case X86_OP_CR:
213     case X86_OP_DR:
214     default:
215         g_assert_not_reached();
216     }