]> git.proxmox.com Git - qemu.git/blame - translate-i386.c
update
[qemu.git] / translate-i386.c
CommitLineData
7d13299d
FB
1/*
2 * i386 translation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
3ef693a0
FB
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
9 * version 2 of the License, or (at your option) any later version.
7d13299d 10 *
3ef693a0
FB
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.
7d13299d 15 *
3ef693a0
FB
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
7d13299d 19 */
367e86e8
FB
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
9de5e440 25#include <signal.h>
367e86e8 26#include <assert.h>
717fc2ad 27#include <sys/mman.h>
367e86e8 28
586314f2 29#include "cpu-i386.h"
d4e8164f 30#include "exec.h"
d19893da 31#include "disas.h"
586314f2 32
717fc2ad
FB
33//#define DEBUG_MMU
34
04369ff2 35/* XXX: move that elsewhere */
dc99065b
FB
36static uint16_t *gen_opc_ptr;
37static uint32_t *gen_opparam_ptr;
0ecfa993 38
9c605cb1
FB
39#define PREFIX_REPZ 0x01
40#define PREFIX_REPNZ 0x02
41#define PREFIX_LOCK 0x04
42#define PREFIX_DATA 0x08
43#define PREFIX_ADR 0x10
367e86e8
FB
44
45typedef struct DisasContext {
46 /* current insn context */
9c605cb1 47 int override; /* -1 if no override */
367e86e8
FB
48 int prefix;
49 int aflag, dflag;
dab2ed99 50 uint8_t *pc; /* pc = eip + cs_base */
6dbad63e
FB
51 int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
52 static state change (stop translation) */
53 /* current block context */
dab2ed99 54 uint8_t *cs_base; /* base of CS segment */
6dbad63e 55 int code32; /* 32 bit code segment */
dab2ed99 56 int ss32; /* 32 bit stack segment */
6dbad63e
FB
57 int cc_op; /* current CC operation */
58 int addseg; /* non zero if either DS/ES/SS have a non zero base */
59 int f_st; /* currently unused */
9c605cb1 60 int vm86; /* vm86 mode */
982b4315
FB
61 int cpl;
62 int iopl;
c50c0c3f 63 int tf; /* TF cpu flag */
d19893da 64 struct TranslationBlock *tb;
717fc2ad 65 int popl_esp_hack; /* for correct popl with esp base handling */
367e86e8
FB
66} DisasContext;
67
68/* i386 arith/logic operations */
69enum {
70 OP_ADDL,
71 OP_ORL,
72 OP_ADCL,
73 OP_SBBL,
74 OP_ANDL,
75 OP_SUBL,
76 OP_XORL,
77 OP_CMPL,
78};
79
80/* i386 shift ops */
81enum {
82 OP_ROL,
83 OP_ROR,
84 OP_RCL,
85 OP_RCR,
86 OP_SHL,
87 OP_SHR,
88 OP_SHL1, /* undocumented */
89 OP_SAR = 7,
90};
91
dc99065b 92enum {
5a91de8c 93#define DEF(s, n, copy_size) INDEX_op_ ## s,
dc99065b
FB
94#include "opc-i386.h"
95#undef DEF
96 NB_OPS,
97};
98
d19893da 99#include "gen-op-i386.h"
367e86e8
FB
100
101/* operand size */
102enum {
103 OT_BYTE = 0,
104 OT_WORD,
105 OT_LONG,
106 OT_QUAD,
107};
108
109enum {
110 /* I386 int registers */
111 OR_EAX, /* MUST be even numbered */
112 OR_ECX,
113 OR_EDX,
114 OR_EBX,
115 OR_ESP,
116 OR_EBP,
117 OR_ESI,
118 OR_EDI,
367e86e8
FB
119 OR_TMP0, /* temporary operand register */
120 OR_TMP1,
121 OR_A0, /* temporary register used when doing address evaluation */
367e86e8 122 OR_ZERO, /* fixed zero register */
367e86e8
FB
123 NB_OREGS,
124};
125
367e86e8
FB
126typedef void (GenOpFunc)(void);
127typedef void (GenOpFunc1)(long);
128typedef void (GenOpFunc2)(long, long);
d4e8164f 129typedef void (GenOpFunc3)(long, long, long);
367e86e8
FB
130
131static GenOpFunc *gen_op_mov_reg_T0[3][8] = {
132 [OT_BYTE] = {
133 gen_op_movb_EAX_T0,
134 gen_op_movb_ECX_T0,
135 gen_op_movb_EDX_T0,
136 gen_op_movb_EBX_T0,
137 gen_op_movh_EAX_T0,
138 gen_op_movh_ECX_T0,
139 gen_op_movh_EDX_T0,
140 gen_op_movh_EBX_T0,
141 },
142 [OT_WORD] = {
143 gen_op_movw_EAX_T0,
144 gen_op_movw_ECX_T0,
145 gen_op_movw_EDX_T0,
146 gen_op_movw_EBX_T0,
147 gen_op_movw_ESP_T0,
148 gen_op_movw_EBP_T0,
149 gen_op_movw_ESI_T0,
150 gen_op_movw_EDI_T0,
151 },
152 [OT_LONG] = {
153 gen_op_movl_EAX_T0,
154 gen_op_movl_ECX_T0,
155 gen_op_movl_EDX_T0,
156 gen_op_movl_EBX_T0,
157 gen_op_movl_ESP_T0,
158 gen_op_movl_EBP_T0,
159 gen_op_movl_ESI_T0,
160 gen_op_movl_EDI_T0,
161 },
162};
163
164static GenOpFunc *gen_op_mov_reg_T1[3][8] = {
165 [OT_BYTE] = {
166 gen_op_movb_EAX_T1,
167 gen_op_movb_ECX_T1,
168 gen_op_movb_EDX_T1,
169 gen_op_movb_EBX_T1,
170 gen_op_movh_EAX_T1,
171 gen_op_movh_ECX_T1,
172 gen_op_movh_EDX_T1,
173 gen_op_movh_EBX_T1,
174 },
175 [OT_WORD] = {
176 gen_op_movw_EAX_T1,
177 gen_op_movw_ECX_T1,
178 gen_op_movw_EDX_T1,
179 gen_op_movw_EBX_T1,
180 gen_op_movw_ESP_T1,
181 gen_op_movw_EBP_T1,
182 gen_op_movw_ESI_T1,
183 gen_op_movw_EDI_T1,
184 },
185 [OT_LONG] = {
186 gen_op_movl_EAX_T1,
187 gen_op_movl_ECX_T1,
188 gen_op_movl_EDX_T1,
189 gen_op_movl_EBX_T1,
190 gen_op_movl_ESP_T1,
191 gen_op_movl_EBP_T1,
192 gen_op_movl_ESI_T1,
193 gen_op_movl_EDI_T1,
194 },
195};
196
197static GenOpFunc *gen_op_mov_reg_A0[2][8] = {
198 [0] = {
199 gen_op_movw_EAX_A0,
200 gen_op_movw_ECX_A0,
201 gen_op_movw_EDX_A0,
202 gen_op_movw_EBX_A0,
203 gen_op_movw_ESP_A0,
204 gen_op_movw_EBP_A0,
205 gen_op_movw_ESI_A0,
206 gen_op_movw_EDI_A0,
207 },
208 [1] = {
209 gen_op_movl_EAX_A0,
210 gen_op_movl_ECX_A0,
211 gen_op_movl_EDX_A0,
212 gen_op_movl_EBX_A0,
213 gen_op_movl_ESP_A0,
214 gen_op_movl_EBP_A0,
215 gen_op_movl_ESI_A0,
216 gen_op_movl_EDI_A0,
217 },
218};
219
220static GenOpFunc *gen_op_mov_TN_reg[3][2][8] =
221{
222 [OT_BYTE] = {
223 {
224 gen_op_movl_T0_EAX,
225 gen_op_movl_T0_ECX,
226 gen_op_movl_T0_EDX,
227 gen_op_movl_T0_EBX,
228 gen_op_movh_T0_EAX,
229 gen_op_movh_T0_ECX,
230 gen_op_movh_T0_EDX,
231 gen_op_movh_T0_EBX,
232 },
233 {
234 gen_op_movl_T1_EAX,
235 gen_op_movl_T1_ECX,
236 gen_op_movl_T1_EDX,
237 gen_op_movl_T1_EBX,
238 gen_op_movh_T1_EAX,
239 gen_op_movh_T1_ECX,
240 gen_op_movh_T1_EDX,
241 gen_op_movh_T1_EBX,
242 },
243 },
244 [OT_WORD] = {
245 {
246 gen_op_movl_T0_EAX,
247 gen_op_movl_T0_ECX,
248 gen_op_movl_T0_EDX,
249 gen_op_movl_T0_EBX,
250 gen_op_movl_T0_ESP,
251 gen_op_movl_T0_EBP,
252 gen_op_movl_T0_ESI,
253 gen_op_movl_T0_EDI,
254 },
255 {
256 gen_op_movl_T1_EAX,
257 gen_op_movl_T1_ECX,
258 gen_op_movl_T1_EDX,
259 gen_op_movl_T1_EBX,
260 gen_op_movl_T1_ESP,
261 gen_op_movl_T1_EBP,
262 gen_op_movl_T1_ESI,
263 gen_op_movl_T1_EDI,
264 },
265 },
266 [OT_LONG] = {
267 {
268 gen_op_movl_T0_EAX,
269 gen_op_movl_T0_ECX,
270 gen_op_movl_T0_EDX,
271 gen_op_movl_T0_EBX,
272 gen_op_movl_T0_ESP,
273 gen_op_movl_T0_EBP,
274 gen_op_movl_T0_ESI,
275 gen_op_movl_T0_EDI,
276 },
277 {
278 gen_op_movl_T1_EAX,
279 gen_op_movl_T1_ECX,
280 gen_op_movl_T1_EDX,
281 gen_op_movl_T1_EBX,
282 gen_op_movl_T1_ESP,
283 gen_op_movl_T1_EBP,
284 gen_op_movl_T1_ESI,
285 gen_op_movl_T1_EDI,
286 },
287 },
288};
289
290static GenOpFunc *gen_op_movl_A0_reg[8] = {
291 gen_op_movl_A0_EAX,
292 gen_op_movl_A0_ECX,
293 gen_op_movl_A0_EDX,
294 gen_op_movl_A0_EBX,
295 gen_op_movl_A0_ESP,
296 gen_op_movl_A0_EBP,
297 gen_op_movl_A0_ESI,
298 gen_op_movl_A0_EDI,
299};
300
301static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = {
302 [0] = {
303 gen_op_addl_A0_EAX,
304 gen_op_addl_A0_ECX,
305 gen_op_addl_A0_EDX,
306 gen_op_addl_A0_EBX,
307 gen_op_addl_A0_ESP,
308 gen_op_addl_A0_EBP,
309 gen_op_addl_A0_ESI,
310 gen_op_addl_A0_EDI,
311 },
312 [1] = {
313 gen_op_addl_A0_EAX_s1,
314 gen_op_addl_A0_ECX_s1,
315 gen_op_addl_A0_EDX_s1,
316 gen_op_addl_A0_EBX_s1,
317 gen_op_addl_A0_ESP_s1,
318 gen_op_addl_A0_EBP_s1,
319 gen_op_addl_A0_ESI_s1,
320 gen_op_addl_A0_EDI_s1,
321 },
322 [2] = {
323 gen_op_addl_A0_EAX_s2,
324 gen_op_addl_A0_ECX_s2,
325 gen_op_addl_A0_EDX_s2,
326 gen_op_addl_A0_EBX_s2,
327 gen_op_addl_A0_ESP_s2,
328 gen_op_addl_A0_EBP_s2,
329 gen_op_addl_A0_ESI_s2,
330 gen_op_addl_A0_EDI_s2,
331 },
332 [3] = {
333 gen_op_addl_A0_EAX_s3,
334 gen_op_addl_A0_ECX_s3,
335 gen_op_addl_A0_EDX_s3,
336 gen_op_addl_A0_EBX_s3,
337 gen_op_addl_A0_ESP_s3,
338 gen_op_addl_A0_EBP_s3,
339 gen_op_addl_A0_ESI_s3,
340 gen_op_addl_A0_EDI_s3,
341 },
342};
343
5dd9488c
FB
344static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = {
345 [0] = {
346 gen_op_cmovw_EAX_T1_T0,
347 gen_op_cmovw_ECX_T1_T0,
348 gen_op_cmovw_EDX_T1_T0,
349 gen_op_cmovw_EBX_T1_T0,
350 gen_op_cmovw_ESP_T1_T0,
351 gen_op_cmovw_EBP_T1_T0,
352 gen_op_cmovw_ESI_T1_T0,
353 gen_op_cmovw_EDI_T1_T0,
354 },
355 [1] = {
356 gen_op_cmovl_EAX_T1_T0,
357 gen_op_cmovl_ECX_T1_T0,
358 gen_op_cmovl_EDX_T1_T0,
359 gen_op_cmovl_EBX_T1_T0,
360 gen_op_cmovl_ESP_T1_T0,
361 gen_op_cmovl_EBP_T1_T0,
362 gen_op_cmovl_ESI_T1_T0,
363 gen_op_cmovl_EDI_T1_T0,
364 },
365};
366
367e86e8
FB
367static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
368 gen_op_addl_T0_T1_cc,
369 gen_op_orl_T0_T1_cc,
4b74fe1f
FB
370 NULL,
371 NULL,
367e86e8
FB
372 gen_op_andl_T0_T1_cc,
373 gen_op_subl_T0_T1_cc,
374 gen_op_xorl_T0_T1_cc,
375 gen_op_cmpl_T0_T1_cc,
376};
377
4b74fe1f
FB
378static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
379 [OT_BYTE] = {
380 gen_op_adcb_T0_T1_cc,
381 gen_op_sbbb_T0_T1_cc,
382 },
383 [OT_WORD] = {
384 gen_op_adcw_T0_T1_cc,
385 gen_op_sbbw_T0_T1_cc,
386 },
387 [OT_LONG] = {
388 gen_op_adcl_T0_T1_cc,
389 gen_op_sbbl_T0_T1_cc,
390 },
391};
392
367e86e8
FB
393static const int cc_op_arithb[8] = {
394 CC_OP_ADDB,
395 CC_OP_LOGICB,
396 CC_OP_ADDB,
397 CC_OP_SUBB,
398 CC_OP_LOGICB,
399 CC_OP_SUBB,
400 CC_OP_LOGICB,
401 CC_OP_SUBB,
402};
403
1a9353d2
FB
404static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = {
405 gen_op_cmpxchgb_T0_T1_EAX_cc,
406 gen_op_cmpxchgw_T0_T1_EAX_cc,
407 gen_op_cmpxchgl_T0_T1_EAX_cc,
408};
409
367e86e8
FB
410static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
411 [OT_BYTE] = {
412 gen_op_rolb_T0_T1_cc,
413 gen_op_rorb_T0_T1_cc,
414 gen_op_rclb_T0_T1_cc,
415 gen_op_rcrb_T0_T1_cc,
416 gen_op_shlb_T0_T1_cc,
417 gen_op_shrb_T0_T1_cc,
418 gen_op_shlb_T0_T1_cc,
419 gen_op_sarb_T0_T1_cc,
420 },
421 [OT_WORD] = {
422 gen_op_rolw_T0_T1_cc,
423 gen_op_rorw_T0_T1_cc,
424 gen_op_rclw_T0_T1_cc,
425 gen_op_rcrw_T0_T1_cc,
426 gen_op_shlw_T0_T1_cc,
427 gen_op_shrw_T0_T1_cc,
428 gen_op_shlw_T0_T1_cc,
429 gen_op_sarw_T0_T1_cc,
430 },
431 [OT_LONG] = {
432 gen_op_roll_T0_T1_cc,
433 gen_op_rorl_T0_T1_cc,
434 gen_op_rcll_T0_T1_cc,
435 gen_op_rcrl_T0_T1_cc,
436 gen_op_shll_T0_T1_cc,
437 gen_op_shrl_T0_T1_cc,
438 gen_op_shll_T0_T1_cc,
439 gen_op_sarl_T0_T1_cc,
440 },
441};
442
d57c4e01
FB
443static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = {
444 [0] = {
445 gen_op_shldw_T0_T1_im_cc,
446 gen_op_shrdw_T0_T1_im_cc,
447 },
448 [1] = {
449 gen_op_shldl_T0_T1_im_cc,
450 gen_op_shrdl_T0_T1_im_cc,
451 },
452};
453
454static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = {
455 [0] = {
456 gen_op_shldw_T0_T1_ECX_cc,
457 gen_op_shrdw_T0_T1_ECX_cc,
458 },
459 [1] = {
460 gen_op_shldl_T0_T1_ECX_cc,
461 gen_op_shrdl_T0_T1_ECX_cc,
462 },
463};
464
4b74fe1f
FB
465static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = {
466 [0] = {
467 gen_op_btw_T0_T1_cc,
468 gen_op_btsw_T0_T1_cc,
469 gen_op_btrw_T0_T1_cc,
470 gen_op_btcw_T0_T1_cc,
471 },
472 [1] = {
473 gen_op_btl_T0_T1_cc,
474 gen_op_btsl_T0_T1_cc,
475 gen_op_btrl_T0_T1_cc,
476 gen_op_btcl_T0_T1_cc,
477 },
478};
479
77f8dd5a
FB
480static GenOpFunc *gen_op_bsx_T0_cc[2][2] = {
481 [0] = {
482 gen_op_bsfw_T0_cc,
483 gen_op_bsrw_T0_cc,
484 },
485 [1] = {
486 gen_op_bsfl_T0_cc,
487 gen_op_bsrl_T0_cc,
488 },
489};
490
367e86e8
FB
491static GenOpFunc *gen_op_lds_T0_A0[3] = {
492 gen_op_ldsb_T0_A0,
493 gen_op_ldsw_T0_A0,
494};
495
496static GenOpFunc *gen_op_ldu_T0_A0[3] = {
497 gen_op_ldub_T0_A0,
498 gen_op_lduw_T0_A0,
499};
500
501/* sign does not matter */
502static GenOpFunc *gen_op_ld_T0_A0[3] = {
503 gen_op_ldub_T0_A0,
504 gen_op_lduw_T0_A0,
505 gen_op_ldl_T0_A0,
506};
507
508static GenOpFunc *gen_op_ld_T1_A0[3] = {
509 gen_op_ldub_T1_A0,
510 gen_op_lduw_T1_A0,
511 gen_op_ldl_T1_A0,
512};
513
514static GenOpFunc *gen_op_st_T0_A0[3] = {
515 gen_op_stb_T0_A0,
516 gen_op_stw_T0_A0,
517 gen_op_stl_T0_A0,
518};
519
9c605cb1
FB
520/* the _a32 and _a16 string operations use A0 as the base register. */
521
522#define STRINGOP(x) \
523 gen_op_ ## x ## b_fast, \
524 gen_op_ ## x ## w_fast, \
525 gen_op_ ## x ## l_fast, \
526 gen_op_ ## x ## b_a32, \
527 gen_op_ ## x ## w_a32, \
528 gen_op_ ## x ## l_a32, \
529 gen_op_ ## x ## b_a16, \
530 gen_op_ ## x ## w_a16, \
531 gen_op_ ## x ## l_a16,
532
533static GenOpFunc *gen_op_movs[9 * 2] = {
534 STRINGOP(movs)
535 STRINGOP(rep_movs)
367e86e8
FB
536};
537
9c605cb1
FB
538static GenOpFunc *gen_op_stos[9 * 2] = {
539 STRINGOP(stos)
540 STRINGOP(rep_stos)
367e86e8
FB
541};
542
9c605cb1
FB
543static GenOpFunc *gen_op_lods[9 * 2] = {
544 STRINGOP(lods)
545 STRINGOP(rep_lods)
367e86e8
FB
546};
547
9c605cb1
FB
548static GenOpFunc *gen_op_scas[9 * 3] = {
549 STRINGOP(scas)
550 STRINGOP(repz_scas)
551 STRINGOP(repnz_scas)
367e86e8
FB
552};
553
9c605cb1
FB
554static GenOpFunc *gen_op_cmps[9 * 3] = {
555 STRINGOP(cmps)
556 STRINGOP(repz_cmps)
557 STRINGOP(repnz_cmps)
367e86e8
FB
558};
559
9c605cb1
FB
560static GenOpFunc *gen_op_ins[9 * 2] = {
561 STRINGOP(ins)
562 STRINGOP(rep_ins)
367e86e8
FB
563};
564
565
9c605cb1
FB
566static GenOpFunc *gen_op_outs[9 * 2] = {
567 STRINGOP(outs)
568 STRINGOP(rep_outs)
367e86e8
FB
569};
570
9c605cb1
FB
571
572static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
573{
574 int index, override;
575
576 override = s->override;
577 if (s->aflag) {
578 /* 32 bit address */
579 if (s->addseg && override < 0)
580 override = R_DS;
581 if (override >= 0) {
d8bc1fd0 582 gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
9c605cb1
FB
583 index = 3 + ot;
584 } else {
585 index = ot;
586 }
587 } else {
588 if (override < 0)
589 override = R_DS;
d8bc1fd0 590 gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
9c605cb1
FB
591 /* 16 address, always override */
592 index = 6 + ot;
593 }
594 func[index]();
595}
596
597static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func)
598{
599 int index;
600
601 if (s->aflag) {
602 if (s->addseg) {
603 index = 3 + ot;
604 } else {
605 index = ot;
606 }
607 } else {
608 index = 6 + ot;
609 }
610 func[index]();
611}
612
613
ba1c6e37
FB
614static GenOpFunc *gen_op_in[3] = {
615 gen_op_inb_T0_T1,
616 gen_op_inw_T0_T1,
617 gen_op_inl_T0_T1,
618};
619
620static GenOpFunc *gen_op_out[3] = {
621 gen_op_outb_T0_T1,
622 gen_op_outw_T0_T1,
623 gen_op_outl_T0_T1,
624};
625
367e86e8
FB
626enum {
627 JCC_O,
628 JCC_B,
629 JCC_Z,
630 JCC_BE,
631 JCC_S,
632 JCC_P,
633 JCC_L,
634 JCC_LE,
635};
636
d4e8164f 637static GenOpFunc3 *gen_jcc_sub[3][8] = {
367e86e8
FB
638 [OT_BYTE] = {
639 NULL,
640 gen_op_jb_subb,
641 gen_op_jz_subb,
642 gen_op_jbe_subb,
643 gen_op_js_subb,
644 NULL,
645 gen_op_jl_subb,
646 gen_op_jle_subb,
647 },
648 [OT_WORD] = {
649 NULL,
650 gen_op_jb_subw,
651 gen_op_jz_subw,
652 gen_op_jbe_subw,
653 gen_op_js_subw,
654 NULL,
655 gen_op_jl_subw,
656 gen_op_jle_subw,
657 },
658 [OT_LONG] = {
659 NULL,
660 gen_op_jb_subl,
661 gen_op_jz_subl,
662 gen_op_jbe_subl,
663 gen_op_js_subl,
664 NULL,
665 gen_op_jl_subl,
666 gen_op_jle_subl,
667 },
668};
1a9353d2
FB
669static GenOpFunc2 *gen_op_loop[2][4] = {
670 [0] = {
671 gen_op_loopnzw,
672 gen_op_loopzw,
673 gen_op_loopw,
674 gen_op_jecxzw,
675 },
676 [1] = {
677 gen_op_loopnzl,
678 gen_op_loopzl,
679 gen_op_loopl,
680 gen_op_jecxzl,
681 },
682};
367e86e8
FB
683
684static GenOpFunc *gen_setcc_slow[8] = {
685 gen_op_seto_T0_cc,
686 gen_op_setb_T0_cc,
687 gen_op_setz_T0_cc,
688 gen_op_setbe_T0_cc,
689 gen_op_sets_T0_cc,
690 gen_op_setp_T0_cc,
691 gen_op_setl_T0_cc,
692 gen_op_setle_T0_cc,
693};
694
695static GenOpFunc *gen_setcc_sub[3][8] = {
696 [OT_BYTE] = {
697 NULL,
698 gen_op_setb_T0_subb,
699 gen_op_setz_T0_subb,
700 gen_op_setbe_T0_subb,
701 gen_op_sets_T0_subb,
702 NULL,
703 gen_op_setl_T0_subb,
704 gen_op_setle_T0_subb,
705 },
706 [OT_WORD] = {
707 NULL,
708 gen_op_setb_T0_subw,
709 gen_op_setz_T0_subw,
710 gen_op_setbe_T0_subw,
711 gen_op_sets_T0_subw,
712 NULL,
713 gen_op_setl_T0_subw,
714 gen_op_setle_T0_subw,
715 },
716 [OT_LONG] = {
717 NULL,
718 gen_op_setb_T0_subl,
719 gen_op_setz_T0_subl,
720 gen_op_setbe_T0_subl,
721 gen_op_sets_T0_subl,
722 NULL,
723 gen_op_setl_T0_subl,
724 gen_op_setle_T0_subl,
725 },
726};
727
927f621e
FB
728static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = {
729 gen_op_fadd_ST0_FT0,
730 gen_op_fmul_ST0_FT0,
731 gen_op_fcom_ST0_FT0,
732 gen_op_fcom_ST0_FT0,
733 gen_op_fsub_ST0_FT0,
734 gen_op_fsubr_ST0_FT0,
735 gen_op_fdiv_ST0_FT0,
736 gen_op_fdivr_ST0_FT0,
737};
738
77f8dd5a 739/* NOTE the exception in "r" op ordering */
927f621e
FB
740static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = {
741 gen_op_fadd_STN_ST0,
742 gen_op_fmul_STN_ST0,
743 NULL,
744 NULL,
927f621e 745 gen_op_fsubr_STN_ST0,
77f8dd5a 746 gen_op_fsub_STN_ST0,
927f621e 747 gen_op_fdivr_STN_ST0,
77f8dd5a 748 gen_op_fdiv_STN_ST0,
927f621e
FB
749};
750
367e86e8
FB
751static void gen_op(DisasContext *s1, int op, int ot, int d, int s)
752{
753 if (d != OR_TMP0)
754 gen_op_mov_TN_reg[ot][0][d]();
755 if (s != OR_TMP1)
756 gen_op_mov_TN_reg[ot][1][s]();
4b74fe1f
FB
757 if (op == OP_ADCL || op == OP_SBBL) {
758 if (s1->cc_op != CC_OP_DYNAMIC)
759 gen_op_set_cc_op(s1->cc_op);
760 gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
761 s1->cc_op = CC_OP_DYNAMIC;
762 } else {
763 gen_op_arith_T0_T1_cc[op]();
764 s1->cc_op = cc_op_arithb[op] + ot;
765 }
367e86e8
FB
766 if (d != OR_TMP0 && op != OP_CMPL)
767 gen_op_mov_reg_T0[ot][d]();
367e86e8
FB
768}
769
770static void gen_opi(DisasContext *s1, int op, int ot, int d, int c)
771{
ba1c6e37 772 gen_op_movl_T1_im(c);
4b74fe1f 773 gen_op(s1, op, ot, d, OR_TMP1);
367e86e8
FB
774}
775
776static void gen_inc(DisasContext *s1, int ot, int d, int c)
777{
778 if (d != OR_TMP0)
779 gen_op_mov_TN_reg[ot][0][d]();
780 if (s1->cc_op != CC_OP_DYNAMIC)
781 gen_op_set_cc_op(s1->cc_op);
4b74fe1f 782 if (c > 0) {
367e86e8 783 gen_op_incl_T0_cc();
4b74fe1f
FB
784 s1->cc_op = CC_OP_INCB + ot;
785 } else {
367e86e8 786 gen_op_decl_T0_cc();
4b74fe1f
FB
787 s1->cc_op = CC_OP_DECB + ot;
788 }
367e86e8
FB
789 if (d != OR_TMP0)
790 gen_op_mov_reg_T0[ot][d]();
791}
792
793static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
794{
795 if (d != OR_TMP0)
796 gen_op_mov_TN_reg[ot][0][d]();
797 if (s != OR_TMP1)
798 gen_op_mov_TN_reg[ot][1][s]();
4b74fe1f
FB
799 /* for zero counts, flags are not updated, so must do it dynamically */
800 if (s1->cc_op != CC_OP_DYNAMIC)
801 gen_op_set_cc_op(s1->cc_op);
802
803 gen_op_shift_T0_T1_cc[ot][op]();
804
367e86e8
FB
805 if (d != OR_TMP0)
806 gen_op_mov_reg_T0[ot][d]();
807 s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
808}
809
810static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
811{
812 /* currently not optimized */
ba1c6e37 813 gen_op_movl_T1_im(c);
367e86e8
FB
814 gen_shift(s1, op, ot, d, OR_TMP1);
815}
816
817static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
818{
819 int havesib;
367e86e8 820 int base, disp;
6dbad63e
FB
821 int index;
822 int scale;
823 int opreg;
824 int mod, rm, code, override, must_add_seg;
825
9c605cb1 826 override = s->override;
6dbad63e 827 must_add_seg = s->addseg;
9c605cb1 828 if (override >= 0)
6dbad63e 829 must_add_seg = 1;
367e86e8
FB
830 mod = (modrm >> 6) & 3;
831 rm = modrm & 7;
832
833 if (s->aflag) {
834
835 havesib = 0;
367e86e8 836 base = rm;
6dbad63e
FB
837 index = 0;
838 scale = 0;
367e86e8
FB
839
840 if (base == 4) {
841 havesib = 1;
842 code = ldub(s->pc++);
843 scale = (code >> 6) & 3;
844 index = (code >> 3) & 7;
845 base = code & 7;
846 }
847
848 switch (mod) {
849 case 0:
850 if (base == 5) {
6dbad63e 851 base = -1;
367e86e8
FB
852 disp = ldl(s->pc);
853 s->pc += 4;
854 } else {
855 disp = 0;
856 }
857 break;
858 case 1:
859 disp = (int8_t)ldub(s->pc++);
860 break;
861 default:
862 case 2:
863 disp = ldl(s->pc);
864 s->pc += 4;
865 break;
866 }
6dbad63e
FB
867
868 if (base >= 0) {
717fc2ad
FB
869 /* for correct popl handling with esp */
870 if (base == 4 && s->popl_esp_hack)
871 disp += 4;
6dbad63e
FB
872 gen_op_movl_A0_reg[base]();
873 if (disp != 0)
874 gen_op_addl_A0_im(disp);
367e86e8 875 } else {
6dbad63e
FB
876 gen_op_movl_A0_im(disp);
877 }
717fc2ad 878 /* XXX: index == 4 is always invalid */
6dbad63e
FB
879 if (havesib && (index != 4 || scale != 0)) {
880 gen_op_addl_A0_reg_sN[scale][index]();
881 }
882 if (must_add_seg) {
883 if (override < 0) {
884 if (base == R_EBP || base == R_ESP)
885 override = R_SS;
886 else
887 override = R_DS;
367e86e8 888 }
d8bc1fd0 889 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
367e86e8 890 }
367e86e8 891 } else {
4b74fe1f
FB
892 switch (mod) {
893 case 0:
894 if (rm == 6) {
895 disp = lduw(s->pc);
896 s->pc += 2;
897 gen_op_movl_A0_im(disp);
6dbad63e 898 rm = 0; /* avoid SS override */
4b74fe1f
FB
899 goto no_rm;
900 } else {
901 disp = 0;
902 }
903 break;
904 case 1:
905 disp = (int8_t)ldub(s->pc++);
906 break;
907 default:
908 case 2:
909 disp = lduw(s->pc);
910 s->pc += 2;
911 break;
912 }
913 switch(rm) {
914 case 0:
915 gen_op_movl_A0_reg[R_EBX]();
916 gen_op_addl_A0_reg_sN[0][R_ESI]();
917 break;
918 case 1:
919 gen_op_movl_A0_reg[R_EBX]();
920 gen_op_addl_A0_reg_sN[0][R_EDI]();
921 break;
922 case 2:
923 gen_op_movl_A0_reg[R_EBP]();
924 gen_op_addl_A0_reg_sN[0][R_ESI]();
925 break;
926 case 3:
927 gen_op_movl_A0_reg[R_EBP]();
928 gen_op_addl_A0_reg_sN[0][R_EDI]();
929 break;
930 case 4:
931 gen_op_movl_A0_reg[R_ESI]();
932 break;
933 case 5:
934 gen_op_movl_A0_reg[R_EDI]();
935 break;
936 case 6:
937 gen_op_movl_A0_reg[R_EBP]();
938 break;
939 default:
940 case 7:
941 gen_op_movl_A0_reg[R_EBX]();
942 break;
943 }
944 if (disp != 0)
945 gen_op_addl_A0_im(disp);
946 gen_op_andl_A0_ffff();
6dbad63e
FB
947 no_rm:
948 if (must_add_seg) {
949 if (override < 0) {
950 if (rm == 2 || rm == 3 || rm == 6)
951 override = R_SS;
952 else
953 override = R_DS;
954 }
d8bc1fd0 955 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
6dbad63e 956 }
367e86e8 957 }
6dbad63e 958
4b74fe1f
FB
959 opreg = OR_A0;
960 disp = 0;
367e86e8
FB
961 *reg_ptr = opreg;
962 *offset_ptr = disp;
963}
964
965/* generate modrm memory load or store of 'reg'. TMP0 is used if reg !=
966 OR_TMP0 */
967static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store)
968{
969 int mod, rm, opreg, disp;
970
971 mod = (modrm >> 6) & 3;
972 rm = modrm & 7;
973 if (mod == 3) {
974 if (is_store) {
975 if (reg != OR_TMP0)
976 gen_op_mov_TN_reg[ot][0][reg]();
977 gen_op_mov_reg_T0[ot][rm]();
978 } else {
979 gen_op_mov_TN_reg[ot][0][rm]();
980 if (reg != OR_TMP0)
981 gen_op_mov_reg_T0[ot][reg]();
982 }
983 } else {
984 gen_lea_modrm(s, modrm, &opreg, &disp);
985 if (is_store) {
986 if (reg != OR_TMP0)
987 gen_op_mov_TN_reg[ot][0][reg]();
988 gen_op_st_T0_A0[ot]();
989 } else {
990 gen_op_ld_T0_A0[ot]();
991 if (reg != OR_TMP0)
992 gen_op_mov_reg_T0[ot][reg]();
993 }
994 }
995}
996
997static inline uint32_t insn_get(DisasContext *s, int ot)
998{
999 uint32_t ret;
1000
1001 switch(ot) {
1002 case OT_BYTE:
1003 ret = ldub(s->pc);
1004 s->pc++;
1005 break;
1006 case OT_WORD:
1007 ret = lduw(s->pc);
1008 s->pc += 2;
1009 break;
1010 default:
1011 case OT_LONG:
1012 ret = ldl(s->pc);
1013 s->pc += 4;
1014 break;
1015 }
1016 return ret;
1017}
1018
dab2ed99 1019static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
367e86e8 1020{
d4e8164f 1021 TranslationBlock *tb;
367e86e8 1022 int inv, jcc_op;
d4e8164f 1023 GenOpFunc3 *func;
367e86e8
FB
1024
1025 inv = b & 1;
1026 jcc_op = (b >> 1) & 7;
1027 switch(s->cc_op) {
1028 /* we optimize the cmp/jcc case */
1029 case CC_OP_SUBB:
1030 case CC_OP_SUBW:
1031 case CC_OP_SUBL:
1032 func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
367e86e8
FB
1033 break;
1034
1035 /* some jumps are easy to compute */
1036 case CC_OP_ADDB:
1037 case CC_OP_ADDW:
1038 case CC_OP_ADDL:
4b74fe1f
FB
1039 case CC_OP_ADCB:
1040 case CC_OP_ADCW:
1041 case CC_OP_ADCL:
1042 case CC_OP_SBBB:
1043 case CC_OP_SBBW:
1044 case CC_OP_SBBL:
367e86e8
FB
1045 case CC_OP_LOGICB:
1046 case CC_OP_LOGICW:
1047 case CC_OP_LOGICL:
1048 case CC_OP_INCB:
1049 case CC_OP_INCW:
1050 case CC_OP_INCL:
1051 case CC_OP_DECB:
1052 case CC_OP_DECW:
1053 case CC_OP_DECL:
1054 case CC_OP_SHLB:
1055 case CC_OP_SHLW:
1056 case CC_OP_SHLL:
4b74fe1f
FB
1057 case CC_OP_SARB:
1058 case CC_OP_SARW:
1059 case CC_OP_SARL:
367e86e8
FB
1060 switch(jcc_op) {
1061 case JCC_Z:
1062 func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1063 break;
1064 case JCC_S:
1065 func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1066 break;
1067 default:
d4e8164f
FB
1068 func = NULL;
1069 break;
367e86e8
FB
1070 }
1071 break;
1072 default:
d4e8164f 1073 func = NULL;
367e86e8
FB
1074 break;
1075 }
d4e8164f
FB
1076
1077 if (s->cc_op != CC_OP_DYNAMIC)
1078 gen_op_set_cc_op(s->cc_op);
1079
1080 if (!func) {
1081 gen_setcc_slow[jcc_op]();
1082 func = gen_op_jcc;
1083 }
1084
1085 tb = s->tb;
367e86e8 1086 if (!inv) {
d4e8164f 1087 func((long)tb, val, next_eip);
367e86e8 1088 } else {
d4e8164f 1089 func((long)tb, next_eip, val);
367e86e8 1090 }
d4e8164f 1091 s->is_jmp = 3;
367e86e8
FB
1092}
1093
1094static void gen_setcc(DisasContext *s, int b)
1095{
1096 int inv, jcc_op;
1097 GenOpFunc *func;
1098
1099 inv = b & 1;
1100 jcc_op = (b >> 1) & 7;
1101 switch(s->cc_op) {
1102 /* we optimize the cmp/jcc case */
1103 case CC_OP_SUBB:
1104 case CC_OP_SUBW:
1105 case CC_OP_SUBL:
1106 func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
1107 if (!func)
1108 goto slow_jcc;
1109 break;
1110
1111 /* some jumps are easy to compute */
1112 case CC_OP_ADDB:
1113 case CC_OP_ADDW:
1114 case CC_OP_ADDL:
1115 case CC_OP_LOGICB:
1116 case CC_OP_LOGICW:
1117 case CC_OP_LOGICL:
1118 case CC_OP_INCB:
1119 case CC_OP_INCW:
1120 case CC_OP_INCL:
1121 case CC_OP_DECB:
1122 case CC_OP_DECW:
1123 case CC_OP_DECL:
1124 case CC_OP_SHLB:
1125 case CC_OP_SHLW:
1126 case CC_OP_SHLL:
1127 switch(jcc_op) {
1128 case JCC_Z:
1017ebe9 1129 func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
367e86e8
FB
1130 break;
1131 case JCC_S:
1017ebe9 1132 func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
367e86e8
FB
1133 break;
1134 default:
1135 goto slow_jcc;
1136 }
1137 break;
1138 default:
1139 slow_jcc:
1140 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 1141 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
1142 func = gen_setcc_slow[jcc_op];
1143 break;
1144 }
1145 func();
1146 if (inv) {
1147 gen_op_xor_T0_1();
1148 }
1149}
1150
6dbad63e 1151/* move T0 to seg_reg and compute if the CPU state may change */
5a91de8c 1152static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
6dbad63e 1153{
5a91de8c
FB
1154 if (!s->vm86)
1155 gen_op_movl_seg_T0(seg_reg, cur_eip);
1156 else
d8bc1fd0 1157 gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]));
6dbad63e
FB
1158 if (!s->addseg && seg_reg < R_FS)
1159 s->is_jmp = 2; /* abort translation because the register may
1160 have a non zero base */
1161}
1162
dab2ed99
FB
1163/* generate a push. It depends on ss32, addseg and dflag */
1164static void gen_push_T0(DisasContext *s)
1165{
1166 if (s->ss32) {
1167 if (!s->addseg) {
1168 if (s->dflag)
1169 gen_op_pushl_T0();
1170 else
1171 gen_op_pushw_T0();
1172 } else {
1173 if (s->dflag)
1174 gen_op_pushl_ss32_T0();
1175 else
1176 gen_op_pushw_ss32_T0();
1177 }
1178 } else {
1179 if (s->dflag)
1180 gen_op_pushl_ss16_T0();
1181 else
1182 gen_op_pushw_ss16_T0();
1183 }
1184}
1185
1186/* two step pop is necessary for precise exceptions */
1187static void gen_pop_T0(DisasContext *s)
1188{
1189 if (s->ss32) {
1190 if (!s->addseg) {
1191 if (s->dflag)
1192 gen_op_popl_T0();
1193 else
1194 gen_op_popw_T0();
1195 } else {
1196 if (s->dflag)
1197 gen_op_popl_ss32_T0();
1198 else
1199 gen_op_popw_ss32_T0();
1200 }
1201 } else {
1202 if (s->dflag)
1203 gen_op_popl_ss16_T0();
1204 else
1205 gen_op_popw_ss16_T0();
1206 }
1207}
1208
d0a1ffc9 1209static inline void gen_stack_update(DisasContext *s, int addend)
dab2ed99
FB
1210{
1211 if (s->ss32) {
d0a1ffc9 1212 if (addend == 2)
dab2ed99 1213 gen_op_addl_ESP_2();
d0a1ffc9
FB
1214 else if (addend == 4)
1215 gen_op_addl_ESP_4();
1216 else
1217 gen_op_addl_ESP_im(addend);
dab2ed99 1218 } else {
d0a1ffc9
FB
1219 if (addend == 2)
1220 gen_op_addw_ESP_2();
1221 else if (addend == 4)
dab2ed99
FB
1222 gen_op_addw_ESP_4();
1223 else
d0a1ffc9 1224 gen_op_addw_ESP_im(addend);
dab2ed99
FB
1225 }
1226}
1227
d0a1ffc9
FB
1228static void gen_pop_update(DisasContext *s)
1229{
1230 gen_stack_update(s, 2 << s->dflag);
1231}
1232
1233static void gen_stack_A0(DisasContext *s)
1234{
1235 gen_op_movl_A0_ESP();
1236 if (!s->ss32)
1237 gen_op_andl_A0_ffff();
1238 gen_op_movl_T1_A0();
1239 if (s->addseg)
d8bc1fd0 1240 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
d0a1ffc9
FB
1241}
1242
dab2ed99
FB
1243/* NOTE: wrap around in 16 bit not fully handled */
1244static void gen_pusha(DisasContext *s)
1245{
1246 int i;
1247 gen_op_movl_A0_ESP();
1248 gen_op_addl_A0_im(-16 << s->dflag);
1249 if (!s->ss32)
1250 gen_op_andl_A0_ffff();
1251 gen_op_movl_T1_A0();
1252 if (s->addseg)
d8bc1fd0 1253 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
dab2ed99
FB
1254 for(i = 0;i < 8; i++) {
1255 gen_op_mov_TN_reg[OT_LONG][0][7 - i]();
1256 gen_op_st_T0_A0[OT_WORD + s->dflag]();
1257 gen_op_addl_A0_im(2 << s->dflag);
1258 }
1259 gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
1260}
1261
1262/* NOTE: wrap around in 16 bit not fully handled */
1263static void gen_popa(DisasContext *s)
1264{
1265 int i;
1266 gen_op_movl_A0_ESP();
1267 if (!s->ss32)
1268 gen_op_andl_A0_ffff();
1269 gen_op_movl_T1_A0();
1270 gen_op_addl_T1_im(16 << s->dflag);
1271 if (s->addseg)
d8bc1fd0 1272 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
dab2ed99
FB
1273 for(i = 0;i < 8; i++) {
1274 /* ESP is not reloaded */
1275 if (i != 3) {
1276 gen_op_ld_T0_A0[OT_WORD + s->dflag]();
1277 gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i]();
1278 }
1279 gen_op_addl_A0_im(2 << s->dflag);
1280 }
1281 gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
1282}
1283
1284/* NOTE: wrap around in 16 bit not fully handled */
1285/* XXX: check this */
1286static void gen_enter(DisasContext *s, int esp_addend, int level)
1287{
1288 int ot, level1, addend, opsize;
1289
1290 ot = s->dflag + OT_WORD;
1291 level &= 0x1f;
1292 level1 = level;
1293 opsize = 2 << s->dflag;
1294
1295 gen_op_movl_A0_ESP();
1296 gen_op_addl_A0_im(-opsize);
1297 if (!s->ss32)
1298 gen_op_andl_A0_ffff();
1299 gen_op_movl_T1_A0();
1300 if (s->addseg)
d8bc1fd0 1301 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
dab2ed99
FB
1302 /* push bp */
1303 gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
1304 gen_op_st_T0_A0[ot]();
1305 if (level) {
1306 while (level--) {
1307 gen_op_addl_A0_im(-opsize);
1308 gen_op_addl_T0_im(-opsize);
1309 gen_op_st_T0_A0[ot]();
1310 }
1311 gen_op_addl_A0_im(-opsize);
1312 /* XXX: add st_T1_A0 ? */
1313 gen_op_movl_T0_T1();
1314 gen_op_st_T0_A0[ot]();
1315 }
1316 gen_op_mov_reg_T1[ot][R_EBP]();
1317 addend = -esp_addend;
1318 if (level1)
1319 addend -= opsize * (level1 + 1);
1320 gen_op_addl_T1_im(addend);
1321 gen_op_mov_reg_T1[ot][R_ESP]();
1322}
1323
c50c0c3f
FB
1324static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip)
1325{
1326 if (s->cc_op != CC_OP_DYNAMIC)
1327 gen_op_set_cc_op(s->cc_op);
1328 gen_op_jmp_im(cur_eip);
1329 gen_op_raise_exception(trapno);
1330 s->is_jmp = 1;
1331}
1332
5a91de8c
FB
1333/* an interrupt is different from an exception because of the
1334 priviledge checks */
1335static void gen_interrupt(DisasContext *s, int intno,
1336 unsigned int cur_eip, unsigned int next_eip)
1337{
1338 if (s->cc_op != CC_OP_DYNAMIC)
1339 gen_op_set_cc_op(s->cc_op);
1340 gen_op_jmp_im(cur_eip);
1341 gen_op_raise_interrupt(intno, next_eip);
1342 s->is_jmp = 1;
1343}
1344
d4e8164f
FB
1345/* generate a jump to eip. No segment change must happen before as a
1346 direct call to the next block may occur */
1347static void gen_jmp(DisasContext *s, unsigned int eip)
1348{
1349 TranslationBlock *tb = s->tb;
1350
1351 if (s->cc_op != CC_OP_DYNAMIC)
1352 gen_op_set_cc_op(s->cc_op);
1353 gen_op_jmp_tb_next((long)tb, eip);
1354 s->is_jmp = 3;
1355}
1356
0ecfa993
FB
1357/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
1358 is set to true if the instruction sets the PC (last instruction of
1359 a basic block) */
6dbad63e 1360long disas_insn(DisasContext *s, uint8_t *pc_start)
367e86e8
FB
1361{
1362 int b, prefixes, aflag, dflag;
1363 int shift, ot;
1364 int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
dab2ed99 1365 unsigned int next_eip;
367e86e8
FB
1366
1367 s->pc = pc_start;
1368 prefixes = 0;
6dbad63e
FB
1369 aflag = s->code32;
1370 dflag = s->code32;
9c605cb1 1371 s->override = -1;
367e86e8
FB
1372 next_byte:
1373 b = ldub(s->pc);
367e86e8
FB
1374 s->pc++;
1375 /* check prefixes */
1376 switch (b) {
1377 case 0xf3:
1378 prefixes |= PREFIX_REPZ;
1379 goto next_byte;
1380 case 0xf2:
1381 prefixes |= PREFIX_REPNZ;
1382 goto next_byte;
1383 case 0xf0:
1384 prefixes |= PREFIX_LOCK;
1385 goto next_byte;
1386 case 0x2e:
9c605cb1 1387 s->override = R_CS;
367e86e8
FB
1388 goto next_byte;
1389 case 0x36:
9c605cb1 1390 s->override = R_SS;
367e86e8
FB
1391 goto next_byte;
1392 case 0x3e:
9c605cb1 1393 s->override = R_DS;
367e86e8
FB
1394 goto next_byte;
1395 case 0x26:
9c605cb1 1396 s->override = R_ES;
367e86e8
FB
1397 goto next_byte;
1398 case 0x64:
9c605cb1 1399 s->override = R_FS;
367e86e8
FB
1400 goto next_byte;
1401 case 0x65:
9c605cb1 1402 s->override = R_GS;
367e86e8
FB
1403 goto next_byte;
1404 case 0x66:
1405 prefixes |= PREFIX_DATA;
1406 goto next_byte;
1407 case 0x67:
1408 prefixes |= PREFIX_ADR;
1409 goto next_byte;
367e86e8
FB
1410 }
1411
1412 if (prefixes & PREFIX_DATA)
1413 dflag ^= 1;
1414 if (prefixes & PREFIX_ADR)
1415 aflag ^= 1;
1416
1417 s->prefix = prefixes;
1418 s->aflag = aflag;
1419 s->dflag = dflag;
1420
1b6b029e
FB
1421 /* lock generation */
1422 if (prefixes & PREFIX_LOCK)
1423 gen_op_lock();
1424
367e86e8
FB
1425 /* now check op code */
1426 reswitch:
1427 switch(b) {
1428 case 0x0f:
1429 /**************************/
1430 /* extended op code */
1431 b = ldub(s->pc++) | 0x100;
1432 goto reswitch;
1433
1434 /**************************/
1435 /* arith & logic */
1436 case 0x00 ... 0x05:
1437 case 0x08 ... 0x0d:
1438 case 0x10 ... 0x15:
1439 case 0x18 ... 0x1d:
1440 case 0x20 ... 0x25:
1441 case 0x28 ... 0x2d:
1442 case 0x30 ... 0x35:
1443 case 0x38 ... 0x3d:
1444 {
1445 int op, f, val;
1446 op = (b >> 3) & 7;
1447 f = (b >> 1) & 3;
1448
1449 if ((b & 1) == 0)
1450 ot = OT_BYTE;
1451 else
1452 ot = dflag ? OT_LONG : OT_WORD;
1453
1454 switch(f) {
1455 case 0: /* OP Ev, Gv */
1456 modrm = ldub(s->pc++);
1457 reg = ((modrm >> 3) & 7) + OR_EAX;
1458 mod = (modrm >> 6) & 3;
1459 rm = modrm & 7;
1460 if (mod != 3) {
1461 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1462 gen_op_ld_T0_A0[ot]();
1463 opreg = OR_TMP0;
1464 } else {
1465 opreg = OR_EAX + rm;
1466 }
1467 gen_op(s, op, ot, opreg, reg);
1468 if (mod != 3 && op != 7) {
1469 gen_op_st_T0_A0[ot]();
1470 }
1471 break;
1472 case 1: /* OP Gv, Ev */
1473 modrm = ldub(s->pc++);
1474 mod = (modrm >> 6) & 3;
1475 reg = ((modrm >> 3) & 7) + OR_EAX;
1476 rm = modrm & 7;
1477 if (mod != 3) {
1478 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1479 gen_op_ld_T1_A0[ot]();
1480 opreg = OR_TMP1;
1481 } else {
1482 opreg = OR_EAX + rm;
1483 }
1484 gen_op(s, op, ot, reg, opreg);
1485 break;
1486 case 2: /* OP A, Iv */
1487 val = insn_get(s, ot);
1488 gen_opi(s, op, ot, OR_EAX, val);
1489 break;
1490 }
1491 }
1492 break;
1493
1494 case 0x80: /* GRP1 */
1495 case 0x81:
1496 case 0x83:
1497 {
1498 int val;
1499
1500 if ((b & 1) == 0)
1501 ot = OT_BYTE;
1502 else
1503 ot = dflag ? OT_LONG : OT_WORD;
1504
1505 modrm = ldub(s->pc++);
1506 mod = (modrm >> 6) & 3;
1507 rm = modrm & 7;
1508 op = (modrm >> 3) & 7;
1509
1510 if (mod != 3) {
1511 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1512 gen_op_ld_T0_A0[ot]();
1513 opreg = OR_TMP0;
1514 } else {
1515 opreg = rm + OR_EAX;
1516 }
1517
1518 switch(b) {
1519 default:
1520 case 0x80:
1521 case 0x81:
1522 val = insn_get(s, ot);
1523 break;
1524 case 0x83:
1525 val = (int8_t)insn_get(s, OT_BYTE);
1526 break;
1527 }
1528
1529 gen_opi(s, op, ot, opreg, val);
1530 if (op != 7 && mod != 3) {
1531 gen_op_st_T0_A0[ot]();
1532 }
1533 }
1534 break;
1535
1536 /**************************/
1537 /* inc, dec, and other misc arith */
1538 case 0x40 ... 0x47: /* inc Gv */
1539 ot = dflag ? OT_LONG : OT_WORD;
1540 gen_inc(s, ot, OR_EAX + (b & 7), 1);
1541 break;
1542 case 0x48 ... 0x4f: /* dec Gv */
1543 ot = dflag ? OT_LONG : OT_WORD;
1544 gen_inc(s, ot, OR_EAX + (b & 7), -1);
1545 break;
1546 case 0xf6: /* GRP3 */
1547 case 0xf7:
1548 if ((b & 1) == 0)
1549 ot = OT_BYTE;
1550 else
1551 ot = dflag ? OT_LONG : OT_WORD;
1552
1553 modrm = ldub(s->pc++);
1554 mod = (modrm >> 6) & 3;
1555 rm = modrm & 7;
1556 op = (modrm >> 3) & 7;
1557 if (mod != 3) {
1558 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1559 gen_op_ld_T0_A0[ot]();
1560 } else {
1561 gen_op_mov_TN_reg[ot][0][rm]();
1562 }
1563
1564 switch(op) {
1565 case 0: /* test */
1566 val = insn_get(s, ot);
ba1c6e37 1567 gen_op_movl_T1_im(val);
367e86e8
FB
1568 gen_op_testl_T0_T1_cc();
1569 s->cc_op = CC_OP_LOGICB + ot;
1570 break;
1571 case 2: /* not */
1572 gen_op_notl_T0();
1573 if (mod != 3) {
1574 gen_op_st_T0_A0[ot]();
1575 } else {
1576 gen_op_mov_reg_T0[ot][rm]();
1577 }
1578 break;
1579 case 3: /* neg */
1580 gen_op_negl_T0_cc();
1581 if (mod != 3) {
1582 gen_op_st_T0_A0[ot]();
1583 } else {
1584 gen_op_mov_reg_T0[ot][rm]();
1585 }
1586 s->cc_op = CC_OP_SUBB + ot;
1587 break;
1588 case 4: /* mul */
1589 switch(ot) {
1590 case OT_BYTE:
1591 gen_op_mulb_AL_T0();
1592 break;
1593 case OT_WORD:
1594 gen_op_mulw_AX_T0();
1595 break;
1596 default:
1597 case OT_LONG:
1598 gen_op_mull_EAX_T0();
1599 break;
1600 }
0ecfa993 1601 s->cc_op = CC_OP_MUL;
367e86e8
FB
1602 break;
1603 case 5: /* imul */
1604 switch(ot) {
1605 case OT_BYTE:
1606 gen_op_imulb_AL_T0();
1607 break;
1608 case OT_WORD:
1609 gen_op_imulw_AX_T0();
1610 break;
1611 default:
1612 case OT_LONG:
1613 gen_op_imull_EAX_T0();
1614 break;
1615 }
0ecfa993 1616 s->cc_op = CC_OP_MUL;
367e86e8
FB
1617 break;
1618 case 6: /* div */
1619 switch(ot) {
1620 case OT_BYTE:
5a91de8c 1621 gen_op_divb_AL_T0(pc_start - s->cs_base);
367e86e8
FB
1622 break;
1623 case OT_WORD:
5a91de8c 1624 gen_op_divw_AX_T0(pc_start - s->cs_base);
367e86e8
FB
1625 break;
1626 default:
1627 case OT_LONG:
5a91de8c 1628 gen_op_divl_EAX_T0(pc_start - s->cs_base);
367e86e8
FB
1629 break;
1630 }
1631 break;
1632 case 7: /* idiv */
1633 switch(ot) {
1634 case OT_BYTE:
5a91de8c 1635 gen_op_idivb_AL_T0(pc_start - s->cs_base);
367e86e8
FB
1636 break;
1637 case OT_WORD:
5a91de8c 1638 gen_op_idivw_AX_T0(pc_start - s->cs_base);
367e86e8
FB
1639 break;
1640 default:
1641 case OT_LONG:
5a91de8c 1642 gen_op_idivl_EAX_T0(pc_start - s->cs_base);
367e86e8
FB
1643 break;
1644 }
1645 break;
1646 default:
1a9353d2 1647 goto illegal_op;
367e86e8
FB
1648 }
1649 break;
1650
1651 case 0xfe: /* GRP4 */
1652 case 0xff: /* GRP5 */
1653 if ((b & 1) == 0)
1654 ot = OT_BYTE;
1655 else
1656 ot = dflag ? OT_LONG : OT_WORD;
1657
1658 modrm = ldub(s->pc++);
1659 mod = (modrm >> 6) & 3;
1660 rm = modrm & 7;
1661 op = (modrm >> 3) & 7;
1662 if (op >= 2 && b == 0xfe) {
1a9353d2 1663 goto illegal_op;
367e86e8
FB
1664 }
1665 if (mod != 3) {
1666 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
dab2ed99
FB
1667 if (op != 3 && op != 5)
1668 gen_op_ld_T0_A0[ot]();
367e86e8
FB
1669 } else {
1670 gen_op_mov_TN_reg[ot][0][rm]();
1671 }
1672
1673 switch(op) {
1674 case 0: /* inc Ev */
1675 gen_inc(s, ot, OR_TMP0, 1);
1676 if (mod != 3)
1677 gen_op_st_T0_A0[ot]();
4b74fe1f
FB
1678 else
1679 gen_op_mov_reg_T0[ot][rm]();
367e86e8
FB
1680 break;
1681 case 1: /* dec Ev */
1682 gen_inc(s, ot, OR_TMP0, -1);
1683 if (mod != 3)
1684 gen_op_st_T0_A0[ot]();
4b74fe1f
FB
1685 else
1686 gen_op_mov_reg_T0[ot][rm]();
367e86e8
FB
1687 break;
1688 case 2: /* call Ev */
dab2ed99
FB
1689 /* XXX: optimize if memory (no and is necessary) */
1690 if (s->dflag == 0)
1691 gen_op_andl_T0_ffff();
1692 gen_op_jmp_T0();
1693 next_eip = s->pc - s->cs_base;
1694 gen_op_movl_T0_im(next_eip);
1695 gen_push_T0(s);
1696 s->is_jmp = 1;
1697 break;
1698 case 3: /* lcall Ev */
1699 /* push return segment + offset */
1700 gen_op_movl_T0_seg(R_CS);
1701 gen_push_T0(s);
1702 next_eip = s->pc - s->cs_base;
1703 gen_op_movl_T0_im(next_eip);
1704 gen_push_T0(s);
1705
1706 gen_op_ld_T1_A0[ot]();
1707 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
1708 gen_op_lduw_T0_A0();
5a91de8c 1709 gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
dab2ed99 1710 gen_op_movl_T0_T1();
367e86e8 1711 gen_op_jmp_T0();
6dbad63e 1712 s->is_jmp = 1;
367e86e8
FB
1713 break;
1714 case 4: /* jmp Ev */
dab2ed99
FB
1715 if (s->dflag == 0)
1716 gen_op_andl_T0_ffff();
1717 gen_op_jmp_T0();
1718 s->is_jmp = 1;
1719 break;
1720 case 5: /* ljmp Ev */
1721 gen_op_ld_T1_A0[ot]();
1722 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
1723 gen_op_lduw_T0_A0();
d8bc1fd0
FB
1724 if (!s->vm86) {
1725 /* we compute EIP to handle the exception case */
1726 gen_op_jmp_im(pc_start - s->cs_base);
1727 gen_op_ljmp_T0_T1();
1728 } else {
1729 gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
1730 gen_op_movl_T0_T1();
1731 gen_op_jmp_T0();
1732 }
6dbad63e 1733 s->is_jmp = 1;
367e86e8
FB
1734 break;
1735 case 6: /* push Ev */
dab2ed99 1736 gen_push_T0(s);
367e86e8
FB
1737 break;
1738 default:
1a9353d2 1739 goto illegal_op;
367e86e8
FB
1740 }
1741 break;
1742
1743 case 0x84: /* test Ev, Gv */
1744 case 0x85:
1745 if ((b & 1) == 0)
1746 ot = OT_BYTE;
1747 else
1748 ot = dflag ? OT_LONG : OT_WORD;
1749
1750 modrm = ldub(s->pc++);
1751 mod = (modrm >> 6) & 3;
1752 rm = modrm & 7;
1753 reg = (modrm >> 3) & 7;
1754
1755 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1756 gen_op_mov_TN_reg[ot][1][reg + OR_EAX]();
1757 gen_op_testl_T0_T1_cc();
1758 s->cc_op = CC_OP_LOGICB + ot;
1759 break;
1760
1761 case 0xa8: /* test eAX, Iv */
1762 case 0xa9:
1763 if ((b & 1) == 0)
1764 ot = OT_BYTE;
1765 else
1766 ot = dflag ? OT_LONG : OT_WORD;
1767 val = insn_get(s, ot);
1768
1769 gen_op_mov_TN_reg[ot][0][OR_EAX]();
ba1c6e37 1770 gen_op_movl_T1_im(val);
367e86e8
FB
1771 gen_op_testl_T0_T1_cc();
1772 s->cc_op = CC_OP_LOGICB + ot;
1773 break;
1774
1775 case 0x98: /* CWDE/CBW */
1776 if (dflag)
1777 gen_op_movswl_EAX_AX();
1778 else
1779 gen_op_movsbw_AX_AL();
1780 break;
1781 case 0x99: /* CDQ/CWD */
1782 if (dflag)
1783 gen_op_movslq_EDX_EAX();
1784 else
1785 gen_op_movswl_DX_AX();
1786 break;
1787 case 0x1af: /* imul Gv, Ev */
1788 case 0x69: /* imul Gv, Ev, I */
1789 case 0x6b:
1790 ot = dflag ? OT_LONG : OT_WORD;
1791 modrm = ldub(s->pc++);
1792 reg = ((modrm >> 3) & 7) + OR_EAX;
367e86e8
FB
1793 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1794 if (b == 0x69) {
1795 val = insn_get(s, ot);
ba1c6e37 1796 gen_op_movl_T1_im(val);
367e86e8
FB
1797 } else if (b == 0x6b) {
1798 val = insn_get(s, OT_BYTE);
ba1c6e37 1799 gen_op_movl_T1_im(val);
367e86e8
FB
1800 } else {
1801 gen_op_mov_TN_reg[ot][1][reg]();
1802 }
1803
1804 if (ot == OT_LONG) {
4b74fe1f 1805 gen_op_imull_T0_T1();
367e86e8 1806 } else {
4b74fe1f 1807 gen_op_imulw_T0_T1();
367e86e8
FB
1808 }
1809 gen_op_mov_reg_T0[ot][reg]();
0ecfa993 1810 s->cc_op = CC_OP_MUL;
367e86e8 1811 break;
1a9353d2
FB
1812 case 0x1c0:
1813 case 0x1c1: /* xadd Ev, Gv */
1814 if ((b & 1) == 0)
1815 ot = OT_BYTE;
1816 else
1817 ot = dflag ? OT_LONG : OT_WORD;
1818 modrm = ldub(s->pc++);
1819 reg = (modrm >> 3) & 7;
1820 mod = (modrm >> 6) & 3;
1821 if (mod == 3) {
1822 rm = modrm & 7;
1823 gen_op_mov_TN_reg[ot][0][reg]();
1824 gen_op_mov_TN_reg[ot][1][rm]();
1825 gen_op_addl_T0_T1_cc();
1826 gen_op_mov_reg_T0[ot][rm]();
1827 gen_op_mov_reg_T1[ot][reg]();
1828 } else {
1829 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1830 gen_op_mov_TN_reg[ot][0][reg]();
1831 gen_op_ld_T1_A0[ot]();
1832 gen_op_addl_T0_T1_cc();
1833 gen_op_st_T0_A0[ot]();
1834 gen_op_mov_reg_T1[ot][reg]();
1835 }
1836 s->cc_op = CC_OP_ADDB + ot;
1837 break;
1838 case 0x1b0:
1839 case 0x1b1: /* cmpxchg Ev, Gv */
1840 if ((b & 1) == 0)
1841 ot = OT_BYTE;
1842 else
1843 ot = dflag ? OT_LONG : OT_WORD;
1844 modrm = ldub(s->pc++);
1845 reg = (modrm >> 3) & 7;
1846 mod = (modrm >> 6) & 3;
1847 gen_op_mov_TN_reg[ot][1][reg]();
1848 if (mod == 3) {
1849 rm = modrm & 7;
1850 gen_op_mov_TN_reg[ot][0][rm]();
1851 gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
1852 gen_op_mov_reg_T0[ot][rm]();
1853 } else {
1854 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1855 gen_op_ld_T0_A0[ot]();
1856 gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
1857 gen_op_st_T0_A0[ot]();
1858 }
1859 s->cc_op = CC_OP_SUBB + ot;
1860 break;
9c605cb1
FB
1861 case 0x1c7: /* cmpxchg8b */
1862 modrm = ldub(s->pc++);
1863 mod = (modrm >> 6) & 3;
1864 if (mod == 3)
1865 goto illegal_op;
1866 if (s->cc_op != CC_OP_DYNAMIC)
1867 gen_op_set_cc_op(s->cc_op);
1868 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1869 gen_op_cmpxchg8b();
1870 s->cc_op = CC_OP_EFLAGS;
1871 break;
367e86e8
FB
1872
1873 /**************************/
1874 /* push/pop */
1875 case 0x50 ... 0x57: /* push */
927f621e 1876 gen_op_mov_TN_reg[OT_LONG][0][b & 7]();
dab2ed99 1877 gen_push_T0(s);
367e86e8
FB
1878 break;
1879 case 0x58 ... 0x5f: /* pop */
dab2ed99
FB
1880 ot = dflag ? OT_LONG : OT_WORD;
1881 gen_pop_T0(s);
1882 gen_op_mov_reg_T0[ot][b & 7]();
1883 gen_pop_update(s);
367e86e8 1884 break;
27362c82 1885 case 0x60: /* pusha */
dab2ed99 1886 gen_pusha(s);
27362c82
FB
1887 break;
1888 case 0x61: /* popa */
dab2ed99 1889 gen_popa(s);
27362c82 1890 break;
367e86e8
FB
1891 case 0x68: /* push Iv */
1892 case 0x6a:
1893 ot = dflag ? OT_LONG : OT_WORD;
1894 if (b == 0x68)
1895 val = insn_get(s, ot);
1896 else
1897 val = (int8_t)insn_get(s, OT_BYTE);
ba1c6e37 1898 gen_op_movl_T0_im(val);
dab2ed99 1899 gen_push_T0(s);
367e86e8
FB
1900 break;
1901 case 0x8f: /* pop Ev */
1902 ot = dflag ? OT_LONG : OT_WORD;
1903 modrm = ldub(s->pc++);
dab2ed99 1904 gen_pop_T0(s);
717fc2ad 1905 s->popl_esp_hack = 1;
367e86e8 1906 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
717fc2ad 1907 s->popl_esp_hack = 0;
dab2ed99 1908 gen_pop_update(s);
367e86e8 1909 break;
27362c82
FB
1910 case 0xc8: /* enter */
1911 {
1912 int level;
1913 val = lduw(s->pc);
1914 s->pc += 2;
1915 level = ldub(s->pc++);
dab2ed99 1916 gen_enter(s, val, level);
27362c82
FB
1917 }
1918 break;
367e86e8 1919 case 0xc9: /* leave */
d0a1ffc9 1920 /* XXX: exception not precise (ESP is updated before potential exception) */
dab2ed99
FB
1921 if (s->ss32) {
1922 gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
1923 gen_op_mov_reg_T0[OT_LONG][R_ESP]();
1924 } else {
1925 gen_op_mov_TN_reg[OT_WORD][0][R_EBP]();
1926 gen_op_mov_reg_T0[OT_WORD][R_ESP]();
1927 }
1928 gen_pop_T0(s);
1929 ot = dflag ? OT_LONG : OT_WORD;
1930 gen_op_mov_reg_T0[ot][R_EBP]();
1931 gen_pop_update(s);
367e86e8 1932 break;
6dbad63e
FB
1933 case 0x06: /* push es */
1934 case 0x0e: /* push cs */
1935 case 0x16: /* push ss */
1936 case 0x1e: /* push ds */
1937 gen_op_movl_T0_seg(b >> 3);
dab2ed99 1938 gen_push_T0(s);
6dbad63e
FB
1939 break;
1940 case 0x1a0: /* push fs */
1941 case 0x1a8: /* push gs */
f631ef9b 1942 gen_op_movl_T0_seg((b >> 3) & 7);
dab2ed99 1943 gen_push_T0(s);
6dbad63e
FB
1944 break;
1945 case 0x07: /* pop es */
1946 case 0x17: /* pop ss */
1947 case 0x1f: /* pop ds */
dab2ed99 1948 gen_pop_T0(s);
5a91de8c 1949 gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base);
dab2ed99 1950 gen_pop_update(s);
6dbad63e
FB
1951 break;
1952 case 0x1a1: /* pop fs */
1953 case 0x1a9: /* pop gs */
dab2ed99 1954 gen_pop_T0(s);
5a91de8c 1955 gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base);
dab2ed99 1956 gen_pop_update(s);
6dbad63e
FB
1957 break;
1958
367e86e8
FB
1959 /**************************/
1960 /* mov */
1961 case 0x88:
1962 case 0x89: /* mov Gv, Ev */
1963 if ((b & 1) == 0)
1964 ot = OT_BYTE;
1965 else
1966 ot = dflag ? OT_LONG : OT_WORD;
1967 modrm = ldub(s->pc++);
1968 reg = (modrm >> 3) & 7;
1969
1970 /* generate a generic store */
1971 gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1);
1972 break;
1973 case 0xc6:
1974 case 0xc7: /* mov Ev, Iv */
1975 if ((b & 1) == 0)
1976 ot = OT_BYTE;
1977 else
1978 ot = dflag ? OT_LONG : OT_WORD;
1979 modrm = ldub(s->pc++);
1980 mod = (modrm >> 6) & 3;
0ecfa993
FB
1981 if (mod != 3)
1982 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
367e86e8 1983 val = insn_get(s, ot);
ba1c6e37 1984 gen_op_movl_T0_im(val);
0ecfa993
FB
1985 if (mod != 3)
1986 gen_op_st_T0_A0[ot]();
1987 else
1988 gen_op_mov_reg_T0[ot][modrm & 7]();
367e86e8
FB
1989 break;
1990 case 0x8a:
1991 case 0x8b: /* mov Ev, Gv */
1992 if ((b & 1) == 0)
1993 ot = OT_BYTE;
1994 else
1995 ot = dflag ? OT_LONG : OT_WORD;
1996 modrm = ldub(s->pc++);
1997 reg = (modrm >> 3) & 7;
1998
1999 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
2000 gen_op_mov_reg_T0[ot][reg]();
2001 break;
6dbad63e
FB
2002 case 0x8e: /* mov seg, Gv */
2003 ot = dflag ? OT_LONG : OT_WORD;
2004 modrm = ldub(s->pc++);
2005 reg = (modrm >> 3) & 7;
2006 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
dab2ed99 2007 if (reg >= 6 || reg == R_CS)
6dbad63e 2008 goto illegal_op;
5a91de8c 2009 gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
6dbad63e
FB
2010 break;
2011 case 0x8c: /* mov Gv, seg */
2012 ot = dflag ? OT_LONG : OT_WORD;
2013 modrm = ldub(s->pc++);
2014 reg = (modrm >> 3) & 7;
2015 if (reg >= 6)
2016 goto illegal_op;
2017 gen_op_movl_T0_seg(reg);
2018 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
2019 break;
367e86e8
FB
2020
2021 case 0x1b6: /* movzbS Gv, Eb */
2022 case 0x1b7: /* movzwS Gv, Eb */
2023 case 0x1be: /* movsbS Gv, Eb */
2024 case 0x1bf: /* movswS Gv, Eb */
2025 {
2026 int d_ot;
2027 /* d_ot is the size of destination */
2028 d_ot = dflag + OT_WORD;
2029 /* ot is the size of source */
2030 ot = (b & 1) + OT_BYTE;
2031 modrm = ldub(s->pc++);
2032 reg = ((modrm >> 3) & 7) + OR_EAX;
2033 mod = (modrm >> 6) & 3;
2034 rm = modrm & 7;
2035
2036 if (mod == 3) {
2037 gen_op_mov_TN_reg[ot][0][rm]();
2038 switch(ot | (b & 8)) {
2039 case OT_BYTE:
2040 gen_op_movzbl_T0_T0();
2041 break;
2042 case OT_BYTE | 8:
2043 gen_op_movsbl_T0_T0();
2044 break;
2045 case OT_WORD:
2046 gen_op_movzwl_T0_T0();
2047 break;
2048 default:
2049 case OT_WORD | 8:
2050 gen_op_movswl_T0_T0();
2051 break;
2052 }
2053 gen_op_mov_reg_T0[d_ot][reg]();
2054 } else {
2055 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2056 if (b & 8) {
2057 gen_op_lds_T0_A0[ot]();
2058 } else {
2059 gen_op_ldu_T0_A0[ot]();
2060 }
2061 gen_op_mov_reg_T0[d_ot][reg]();
2062 }
2063 }
2064 break;
2065
2066 case 0x8d: /* lea */
2067 ot = dflag ? OT_LONG : OT_WORD;
2068 modrm = ldub(s->pc++);
2069 reg = (modrm >> 3) & 7;
6dbad63e 2070 /* we must ensure that no segment is added */
9c605cb1 2071 s->override = -1;
6dbad63e
FB
2072 val = s->addseg;
2073 s->addseg = 0;
367e86e8 2074 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
6dbad63e 2075 s->addseg = val;
367e86e8
FB
2076 gen_op_mov_reg_A0[ot - OT_WORD][reg]();
2077 break;
2078
2079 case 0xa0: /* mov EAX, Ov */
2080 case 0xa1:
2081 case 0xa2: /* mov Ov, EAX */
2082 case 0xa3:
2083 if ((b & 1) == 0)
2084 ot = OT_BYTE;
2085 else
2086 ot = dflag ? OT_LONG : OT_WORD;
2087 if (s->aflag)
2088 offset_addr = insn_get(s, OT_LONG);
2089 else
2090 offset_addr = insn_get(s, OT_WORD);
4b74fe1f 2091 gen_op_movl_A0_im(offset_addr);
1a9353d2 2092 /* handle override */
1a9353d2
FB
2093 {
2094 int override, must_add_seg;
1a9353d2 2095 must_add_seg = s->addseg;
9c605cb1
FB
2096 if (s->override >= 0) {
2097 override = s->override;
1a9353d2 2098 must_add_seg = 1;
9c605cb1
FB
2099 } else {
2100 override = R_DS;
1a9353d2
FB
2101 }
2102 if (must_add_seg) {
d8bc1fd0 2103 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
1a9353d2
FB
2104 }
2105 }
367e86e8
FB
2106 if ((b & 2) == 0) {
2107 gen_op_ld_T0_A0[ot]();
2108 gen_op_mov_reg_T0[ot][R_EAX]();
2109 } else {
2110 gen_op_mov_TN_reg[ot][0][R_EAX]();
2111 gen_op_st_T0_A0[ot]();
2112 }
2113 break;
31bb950b 2114 case 0xd7: /* xlat */
31bb950b
FB
2115 gen_op_movl_A0_reg[R_EBX]();
2116 gen_op_addl_A0_AL();
2117 if (s->aflag == 0)
2118 gen_op_andl_A0_ffff();
9c605cb1 2119 /* handle override */
31bb950b
FB
2120 {
2121 int override, must_add_seg;
31bb950b 2122 must_add_seg = s->addseg;
9c605cb1
FB
2123 override = R_DS;
2124 if (s->override >= 0) {
2125 override = s->override;
31bb950b 2126 must_add_seg = 1;
9c605cb1
FB
2127 } else {
2128 override = R_DS;
31bb950b
FB
2129 }
2130 if (must_add_seg) {
d8bc1fd0 2131 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
31bb950b
FB
2132 }
2133 }
2134 gen_op_ldub_T0_A0();
2135 gen_op_mov_reg_T0[OT_BYTE][R_EAX]();
2136 break;
367e86e8
FB
2137 case 0xb0 ... 0xb7: /* mov R, Ib */
2138 val = insn_get(s, OT_BYTE);
ba1c6e37 2139 gen_op_movl_T0_im(val);
367e86e8
FB
2140 gen_op_mov_reg_T0[OT_BYTE][b & 7]();
2141 break;
2142 case 0xb8 ... 0xbf: /* mov R, Iv */
2143 ot = dflag ? OT_LONG : OT_WORD;
2144 val = insn_get(s, ot);
2145 reg = OR_EAX + (b & 7);
ba1c6e37 2146 gen_op_movl_T0_im(val);
367e86e8
FB
2147 gen_op_mov_reg_T0[ot][reg]();
2148 break;
2149
2150 case 0x91 ... 0x97: /* xchg R, EAX */
2151 ot = dflag ? OT_LONG : OT_WORD;
2152 reg = b & 7;
1a9353d2
FB
2153 rm = R_EAX;
2154 goto do_xchg_reg;
367e86e8
FB
2155 case 0x86:
2156 case 0x87: /* xchg Ev, Gv */
2157 if ((b & 1) == 0)
2158 ot = OT_BYTE;
2159 else
2160 ot = dflag ? OT_LONG : OT_WORD;
2161 modrm = ldub(s->pc++);
2162 reg = (modrm >> 3) & 7;
1a9353d2
FB
2163 mod = (modrm >> 6) & 3;
2164 if (mod == 3) {
2165 rm = modrm & 7;
2166 do_xchg_reg:
2167 gen_op_mov_TN_reg[ot][0][reg]();
2168 gen_op_mov_TN_reg[ot][1][rm]();
2169 gen_op_mov_reg_T0[ot][rm]();
2170 gen_op_mov_reg_T1[ot][reg]();
2171 } else {
2172 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2173 gen_op_mov_TN_reg[ot][0][reg]();
31bb950b
FB
2174 /* for xchg, lock is implicit */
2175 if (!(prefixes & PREFIX_LOCK))
2176 gen_op_lock();
1a9353d2
FB
2177 gen_op_ld_T1_A0[ot]();
2178 gen_op_st_T0_A0[ot]();
31bb950b
FB
2179 if (!(prefixes & PREFIX_LOCK))
2180 gen_op_unlock();
1a9353d2
FB
2181 gen_op_mov_reg_T1[ot][reg]();
2182 }
367e86e8 2183 break;
6dbad63e
FB
2184 case 0xc4: /* les Gv */
2185 op = R_ES;
2186 goto do_lxx;
2187 case 0xc5: /* lds Gv */
2188 op = R_DS;
2189 goto do_lxx;
2190 case 0x1b2: /* lss Gv */
2191 op = R_SS;
2192 goto do_lxx;
2193 case 0x1b4: /* lfs Gv */
2194 op = R_FS;
2195 goto do_lxx;
2196 case 0x1b5: /* lgs Gv */
2197 op = R_GS;
2198 do_lxx:
2199 ot = dflag ? OT_LONG : OT_WORD;
2200 modrm = ldub(s->pc++);
2201 reg = (modrm >> 3) & 7;
2202 mod = (modrm >> 6) & 3;
2203 if (mod == 3)
2204 goto illegal_op;
9c605cb1 2205 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
6dbad63e 2206 gen_op_ld_T1_A0[ot]();
dc99065b 2207 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
6dbad63e
FB
2208 /* load the segment first to handle exceptions properly */
2209 gen_op_lduw_T0_A0();
5a91de8c 2210 gen_movl_seg_T0(s, op, pc_start - s->cs_base);
6dbad63e
FB
2211 /* then put the data */
2212 gen_op_mov_reg_T1[ot][reg]();
2213 break;
367e86e8
FB
2214
2215 /************************/
2216 /* shifts */
2217 case 0xc0:
2218 case 0xc1:
2219 /* shift Ev,Ib */
2220 shift = 2;
2221 grp2:
2222 {
2223 if ((b & 1) == 0)
2224 ot = OT_BYTE;
2225 else
2226 ot = dflag ? OT_LONG : OT_WORD;
2227
2228 modrm = ldub(s->pc++);
2229 mod = (modrm >> 6) & 3;
2230 rm = modrm & 7;
2231 op = (modrm >> 3) & 7;
2232
2233 if (mod != 3) {
2234 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2235 gen_op_ld_T0_A0[ot]();
2236 opreg = OR_TMP0;
2237 } else {
2238 opreg = rm + OR_EAX;
2239 }
2240
2241 /* simpler op */
2242 if (shift == 0) {
2243 gen_shift(s, op, ot, opreg, OR_ECX);
2244 } else {
2245 if (shift == 2) {
2246 shift = ldub(s->pc++);
2247 }
2248 gen_shifti(s, op, ot, opreg, shift);
2249 }
2250
2251 if (mod != 3) {
2252 gen_op_st_T0_A0[ot]();
2253 }
2254 }
2255 break;
2256 case 0xd0:
2257 case 0xd1:
2258 /* shift Ev,1 */
2259 shift = 1;
2260 goto grp2;
2261 case 0xd2:
2262 case 0xd3:
2263 /* shift Ev,cl */
2264 shift = 0;
2265 goto grp2;
2266
d57c4e01
FB
2267 case 0x1a4: /* shld imm */
2268 op = 0;
2269 shift = 1;
2270 goto do_shiftd;
2271 case 0x1a5: /* shld cl */
2272 op = 0;
2273 shift = 0;
2274 goto do_shiftd;
2275 case 0x1ac: /* shrd imm */
2276 op = 1;
2277 shift = 1;
2278 goto do_shiftd;
2279 case 0x1ad: /* shrd cl */
2280 op = 1;
2281 shift = 0;
2282 do_shiftd:
2283 ot = dflag ? OT_LONG : OT_WORD;
2284 modrm = ldub(s->pc++);
2285 mod = (modrm >> 6) & 3;
2286 rm = modrm & 7;
2287 reg = (modrm >> 3) & 7;
2288
2289 if (mod != 3) {
2290 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2291 gen_op_ld_T0_A0[ot]();
2292 } else {
2293 gen_op_mov_TN_reg[ot][0][rm]();
2294 }
2295 gen_op_mov_TN_reg[ot][1][reg]();
2296
2297 if (shift) {
2298 val = ldub(s->pc++);
2299 val &= 0x1f;
2300 if (val) {
2301 gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);
2302 if (op == 0 && ot != OT_WORD)
2303 s->cc_op = CC_OP_SHLB + ot;
2304 else
2305 s->cc_op = CC_OP_SARB + ot;
2306 }
2307 } else {
2308 if (s->cc_op != CC_OP_DYNAMIC)
2309 gen_op_set_cc_op(s->cc_op);
2310 gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();
2311 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
2312 }
2313 if (mod != 3) {
2314 gen_op_st_T0_A0[ot]();
2315 } else {
2316 gen_op_mov_reg_T0[ot][rm]();
2317 }
2318 break;
2319
367e86e8
FB
2320 /************************/
2321 /* floats */
367e86e8
FB
2322 case 0xd8 ... 0xdf:
2323 modrm = ldub(s->pc++);
2324 mod = (modrm >> 6) & 3;
2325 rm = modrm & 7;
2326 op = ((b & 7) << 3) | ((modrm >> 3) & 7);
2327
2328 if (mod != 3) {
2329 /* memory op */
2330 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2331 switch(op) {
2332 case 0x00 ... 0x07: /* fxxxs */
2333 case 0x10 ... 0x17: /* fixxxl */
2334 case 0x20 ... 0x27: /* fxxxl */
2335 case 0x30 ... 0x37: /* fixxx */
2336 {
927f621e
FB
2337 int op1;
2338 op1 = op & 7;
367e86e8
FB
2339
2340 switch(op >> 4) {
2341 case 0:
927f621e 2342 gen_op_flds_FT0_A0();
367e86e8
FB
2343 break;
2344 case 1:
927f621e 2345 gen_op_fildl_FT0_A0();
367e86e8
FB
2346 break;
2347 case 2:
927f621e 2348 gen_op_fldl_FT0_A0();
367e86e8
FB
2349 break;
2350 case 3:
2351 default:
927f621e 2352 gen_op_fild_FT0_A0();
367e86e8
FB
2353 break;
2354 }
2355
927f621e
FB
2356 gen_op_fp_arith_ST0_FT0[op1]();
2357 if (op1 == 3) {
367e86e8 2358 /* fcomp needs pop */
927f621e 2359 gen_op_fpop();
367e86e8
FB
2360 }
2361 }
2362 break;
2363 case 0x08: /* flds */
2364 case 0x0a: /* fsts */
2365 case 0x0b: /* fstps */
2366 case 0x18: /* fildl */
2367 case 0x1a: /* fistl */
2368 case 0x1b: /* fistpl */
2369 case 0x28: /* fldl */
2370 case 0x2a: /* fstl */
2371 case 0x2b: /* fstpl */
2372 case 0x38: /* filds */
2373 case 0x3a: /* fists */
2374 case 0x3b: /* fistps */
2375
367e86e8
FB
2376 switch(op & 7) {
2377 case 0:
927f621e
FB
2378 gen_op_fpush();
2379 switch(op >> 4) {
2380 case 0:
2381 gen_op_flds_ST0_A0();
2382 break;
2383 case 1:
2384 gen_op_fildl_ST0_A0();
2385 break;
2386 case 2:
2387 gen_op_fldl_ST0_A0();
2388 break;
2389 case 3:
2390 default:
2391 gen_op_fild_ST0_A0();
2392 break;
367e86e8
FB
2393 }
2394 break;
2395 default:
927f621e
FB
2396 switch(op >> 4) {
2397 case 0:
2398 gen_op_fsts_ST0_A0();
2399 break;
2400 case 1:
2401 gen_op_fistl_ST0_A0();
2402 break;
2403 case 2:
2404 gen_op_fstl_ST0_A0();
2405 break;
2406 case 3:
2407 default:
2408 gen_op_fist_ST0_A0();
2409 break;
367e86e8
FB
2410 }
2411 if ((op & 7) == 3)
927f621e 2412 gen_op_fpop();
367e86e8
FB
2413 break;
2414 }
2415 break;
d0a1ffc9
FB
2416 case 0x0c: /* fldenv mem */
2417 gen_op_fldenv_A0(s->dflag);
2418 break;
4b74fe1f
FB
2419 case 0x0d: /* fldcw mem */
2420 gen_op_fldcw_A0();
2421 break;
d0a1ffc9
FB
2422 case 0x0e: /* fnstenv mem */
2423 gen_op_fnstenv_A0(s->dflag);
2424 break;
4b74fe1f
FB
2425 case 0x0f: /* fnstcw mem */
2426 gen_op_fnstcw_A0();
2427 break;
77f8dd5a
FB
2428 case 0x1d: /* fldt mem */
2429 gen_op_fpush();
2430 gen_op_fldt_ST0_A0();
2431 break;
2432 case 0x1f: /* fstpt mem */
2433 gen_op_fstt_ST0_A0();
2434 gen_op_fpop();
2435 break;
d0a1ffc9
FB
2436 case 0x2c: /* frstor mem */
2437 gen_op_frstor_A0(s->dflag);
2438 break;
2439 case 0x2e: /* fnsave mem */
2440 gen_op_fnsave_A0(s->dflag);
2441 break;
367e86e8 2442 case 0x2f: /* fnstsw mem */
4b74fe1f 2443 gen_op_fnstsw_A0();
367e86e8 2444 break;
367e86e8 2445 case 0x3c: /* fbld */
77f8dd5a 2446 gen_op_fpush();
1017ebe9 2447 gen_op_fbld_ST0_A0();
77f8dd5a 2448 break;
367e86e8 2449 case 0x3e: /* fbstp */
77f8dd5a
FB
2450 gen_op_fbst_ST0_A0();
2451 gen_op_fpop();
2452 break;
367e86e8 2453 case 0x3d: /* fildll */
927f621e
FB
2454 gen_op_fpush();
2455 gen_op_fildll_ST0_A0();
367e86e8
FB
2456 break;
2457 case 0x3f: /* fistpll */
927f621e
FB
2458 gen_op_fistll_ST0_A0();
2459 gen_op_fpop();
367e86e8
FB
2460 break;
2461 default:
1a9353d2 2462 goto illegal_op;
367e86e8
FB
2463 }
2464 } else {
2465 /* register float ops */
927f621e 2466 opreg = rm;
367e86e8
FB
2467
2468 switch(op) {
2469 case 0x08: /* fld sti */
927f621e
FB
2470 gen_op_fpush();
2471 gen_op_fmov_ST0_STN((opreg + 1) & 7);
367e86e8
FB
2472 break;
2473 case 0x09: /* fxchg sti */
77f8dd5a 2474 gen_op_fxchg_ST0_STN(opreg);
367e86e8
FB
2475 break;
2476 case 0x0a: /* grp d9/2 */
2477 switch(rm) {
2478 case 0: /* fnop */
367e86e8
FB
2479 break;
2480 default:
1a9353d2 2481 goto illegal_op;
367e86e8
FB
2482 }
2483 break;
2484 case 0x0c: /* grp d9/4 */
2485 switch(rm) {
2486 case 0: /* fchs */
927f621e 2487 gen_op_fchs_ST0();
367e86e8
FB
2488 break;
2489 case 1: /* fabs */
927f621e 2490 gen_op_fabs_ST0();
367e86e8
FB
2491 break;
2492 case 4: /* ftst */
927f621e
FB
2493 gen_op_fldz_FT0();
2494 gen_op_fcom_ST0_FT0();
367e86e8
FB
2495 break;
2496 case 5: /* fxam */
927f621e 2497 gen_op_fxam_ST0();
367e86e8
FB
2498 break;
2499 default:
1a9353d2 2500 goto illegal_op;
367e86e8
FB
2501 }
2502 break;
2503 case 0x0d: /* grp d9/5 */
2504 {
927f621e
FB
2505 switch(rm) {
2506 case 0:
77f8dd5a 2507 gen_op_fpush();
927f621e
FB
2508 gen_op_fld1_ST0();
2509 break;
2510 case 1:
77f8dd5a
FB
2511 gen_op_fpush();
2512 gen_op_fldl2t_ST0();
927f621e
FB
2513 break;
2514 case 2:
77f8dd5a
FB
2515 gen_op_fpush();
2516 gen_op_fldl2e_ST0();
927f621e
FB
2517 break;
2518 case 3:
77f8dd5a 2519 gen_op_fpush();
927f621e
FB
2520 gen_op_fldpi_ST0();
2521 break;
2522 case 4:
77f8dd5a 2523 gen_op_fpush();
927f621e
FB
2524 gen_op_fldlg2_ST0();
2525 break;
2526 case 5:
77f8dd5a 2527 gen_op_fpush();
927f621e
FB
2528 gen_op_fldln2_ST0();
2529 break;
2530 case 6:
77f8dd5a 2531 gen_op_fpush();
927f621e
FB
2532 gen_op_fldz_ST0();
2533 break;
2534 default:
1a9353d2 2535 goto illegal_op;
367e86e8 2536 }
367e86e8
FB
2537 }
2538 break;
2539 case 0x0e: /* grp d9/6 */
2540 switch(rm) {
2541 case 0: /* f2xm1 */
927f621e 2542 gen_op_f2xm1();
367e86e8
FB
2543 break;
2544 case 1: /* fyl2x */
927f621e 2545 gen_op_fyl2x();
367e86e8
FB
2546 break;
2547 case 2: /* fptan */
927f621e 2548 gen_op_fptan();
367e86e8
FB
2549 break;
2550 case 3: /* fpatan */
927f621e 2551 gen_op_fpatan();
367e86e8
FB
2552 break;
2553 case 4: /* fxtract */
927f621e 2554 gen_op_fxtract();
367e86e8
FB
2555 break;
2556 case 5: /* fprem1 */
927f621e 2557 gen_op_fprem1();
367e86e8
FB
2558 break;
2559 case 6: /* fdecstp */
927f621e 2560 gen_op_fdecstp();
367e86e8
FB
2561 break;
2562 default:
927f621e
FB
2563 case 7: /* fincstp */
2564 gen_op_fincstp();
367e86e8
FB
2565 break;
2566 }
2567 break;
2568 case 0x0f: /* grp d9/7 */
2569 switch(rm) {
2570 case 0: /* fprem */
927f621e 2571 gen_op_fprem();
367e86e8
FB
2572 break;
2573 case 1: /* fyl2xp1 */
927f621e
FB
2574 gen_op_fyl2xp1();
2575 break;
2576 case 2: /* fsqrt */
2577 gen_op_fsqrt();
367e86e8
FB
2578 break;
2579 case 3: /* fsincos */
927f621e 2580 gen_op_fsincos();
367e86e8
FB
2581 break;
2582 case 5: /* fscale */
927f621e 2583 gen_op_fscale();
367e86e8 2584 break;
367e86e8 2585 case 4: /* frndint */
927f621e
FB
2586 gen_op_frndint();
2587 break;
367e86e8 2588 case 6: /* fsin */
927f621e
FB
2589 gen_op_fsin();
2590 break;
367e86e8
FB
2591 default:
2592 case 7: /* fcos */
927f621e 2593 gen_op_fcos();
367e86e8
FB
2594 break;
2595 }
2596 break;
2597 case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
2598 case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
2599 case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
2600 {
927f621e 2601 int op1;
367e86e8 2602
927f621e 2603 op1 = op & 7;
367e86e8 2604 if (op >= 0x20) {
927f621e 2605 gen_op_fp_arith_STN_ST0[op1](opreg);
77f8dd5a
FB
2606 if (op >= 0x30)
2607 gen_op_fpop();
367e86e8 2608 } else {
927f621e
FB
2609 gen_op_fmov_FT0_STN(opreg);
2610 gen_op_fp_arith_ST0_FT0[op1]();
367e86e8 2611 }
367e86e8
FB
2612 }
2613 break;
2614 case 0x02: /* fcom */
927f621e
FB
2615 gen_op_fmov_FT0_STN(opreg);
2616 gen_op_fcom_ST0_FT0();
367e86e8
FB
2617 break;
2618 case 0x03: /* fcomp */
927f621e
FB
2619 gen_op_fmov_FT0_STN(opreg);
2620 gen_op_fcom_ST0_FT0();
2621 gen_op_fpop();
367e86e8
FB
2622 break;
2623 case 0x15: /* da/5 */
2624 switch(rm) {
2625 case 1: /* fucompp */
927f621e 2626 gen_op_fmov_FT0_STN(1);
77f8dd5a 2627 gen_op_fucom_ST0_FT0();
927f621e
FB
2628 gen_op_fpop();
2629 gen_op_fpop();
367e86e8
FB
2630 break;
2631 default:
1a9353d2
FB
2632 goto illegal_op;
2633 }
2634 break;
2635 case 0x1c:
2636 switch(rm) {
d8bc1fd0
FB
2637 case 0: /* feni (287 only, just do nop here) */
2638 break;
2639 case 1: /* fdisi (287 only, just do nop here) */
2640 break;
1a9353d2
FB
2641 case 2: /* fclex */
2642 gen_op_fclex();
2643 break;
2644 case 3: /* fninit */
2645 gen_op_fninit();
2646 break;
d8bc1fd0
FB
2647 case 4: /* fsetpm (287 only, just do nop here) */
2648 break;
1a9353d2
FB
2649 default:
2650 goto illegal_op;
367e86e8
FB
2651 }
2652 break;
d0a1ffc9
FB
2653 case 0x1d: /* fucomi */
2654 if (s->cc_op != CC_OP_DYNAMIC)
2655 gen_op_set_cc_op(s->cc_op);
2656 gen_op_fmov_FT0_STN(opreg);
2657 gen_op_fucomi_ST0_FT0();
2658 s->cc_op = CC_OP_EFLAGS;
2659 break;
2660 case 0x1e: /* fcomi */
2661 if (s->cc_op != CC_OP_DYNAMIC)
2662 gen_op_set_cc_op(s->cc_op);
2663 gen_op_fmov_FT0_STN(opreg);
2664 gen_op_fcomi_ST0_FT0();
2665 s->cc_op = CC_OP_EFLAGS;
2666 break;
367e86e8 2667 case 0x2a: /* fst sti */
927f621e 2668 gen_op_fmov_STN_ST0(opreg);
367e86e8
FB
2669 break;
2670 case 0x2b: /* fstp sti */
927f621e
FB
2671 gen_op_fmov_STN_ST0(opreg);
2672 gen_op_fpop();
367e86e8 2673 break;
77f8dd5a
FB
2674 case 0x2c: /* fucom st(i) */
2675 gen_op_fmov_FT0_STN(opreg);
2676 gen_op_fucom_ST0_FT0();
2677 break;
2678 case 0x2d: /* fucomp st(i) */
2679 gen_op_fmov_FT0_STN(opreg);
2680 gen_op_fucom_ST0_FT0();
2681 gen_op_fpop();
2682 break;
367e86e8
FB
2683 case 0x33: /* de/3 */
2684 switch(rm) {
2685 case 1: /* fcompp */
927f621e
FB
2686 gen_op_fmov_FT0_STN(1);
2687 gen_op_fcom_ST0_FT0();
2688 gen_op_fpop();
2689 gen_op_fpop();
367e86e8
FB
2690 break;
2691 default:
1a9353d2 2692 goto illegal_op;
367e86e8
FB
2693 }
2694 break;
2695 case 0x3c: /* df/4 */
2696 switch(rm) {
2697 case 0:
77f8dd5a 2698 gen_op_fnstsw_EAX();
367e86e8
FB
2699 break;
2700 default:
1a9353d2 2701 goto illegal_op;
367e86e8
FB
2702 }
2703 break;
d0a1ffc9
FB
2704 case 0x3d: /* fucomip */
2705 if (s->cc_op != CC_OP_DYNAMIC)
2706 gen_op_set_cc_op(s->cc_op);
2707 gen_op_fmov_FT0_STN(opreg);
2708 gen_op_fucomi_ST0_FT0();
2709 gen_op_fpop();
2710 s->cc_op = CC_OP_EFLAGS;
2711 break;
2712 case 0x3e: /* fcomip */
2713 if (s->cc_op != CC_OP_DYNAMIC)
2714 gen_op_set_cc_op(s->cc_op);
2715 gen_op_fmov_FT0_STN(opreg);
2716 gen_op_fcomi_ST0_FT0();
2717 gen_op_fpop();
2718 s->cc_op = CC_OP_EFLAGS;
2719 break;
367e86e8 2720 default:
1a9353d2 2721 goto illegal_op;
367e86e8
FB
2722 }
2723 }
2724 break;
367e86e8
FB
2725 /************************/
2726 /* string ops */
9c605cb1 2727
367e86e8
FB
2728 case 0xa4: /* movsS */
2729 case 0xa5:
2730 if ((b & 1) == 0)
2731 ot = OT_BYTE;
2732 else
2733 ot = dflag ? OT_LONG : OT_WORD;
9c605cb1 2734
367e86e8 2735 if (prefixes & PREFIX_REPZ) {
9c605cb1 2736 gen_string_ds(s, ot, gen_op_movs + 9);
367e86e8 2737 } else {
9c605cb1 2738 gen_string_ds(s, ot, gen_op_movs);
367e86e8
FB
2739 }
2740 break;
2741
2742 case 0xaa: /* stosS */
2743 case 0xab:
2744 if ((b & 1) == 0)
2745 ot = OT_BYTE;
2746 else
2747 ot = dflag ? OT_LONG : OT_WORD;
9c605cb1 2748
367e86e8 2749 if (prefixes & PREFIX_REPZ) {
9c605cb1 2750 gen_string_es(s, ot, gen_op_stos + 9);
367e86e8 2751 } else {
9c605cb1 2752 gen_string_es(s, ot, gen_op_stos);
367e86e8
FB
2753 }
2754 break;
2755 case 0xac: /* lodsS */
2756 case 0xad:
2757 if ((b & 1) == 0)
2758 ot = OT_BYTE;
2759 else
2760 ot = dflag ? OT_LONG : OT_WORD;
2761 if (prefixes & PREFIX_REPZ) {
9c605cb1 2762 gen_string_ds(s, ot, gen_op_lods + 9);
367e86e8 2763 } else {
9c605cb1 2764 gen_string_ds(s, ot, gen_op_lods);
367e86e8
FB
2765 }
2766 break;
2767 case 0xae: /* scasS */
2768 case 0xaf:
2769 if ((b & 1) == 0)
2770 ot = OT_BYTE;
2771 else
9c605cb1 2772 ot = dflag ? OT_LONG : OT_WORD;
367e86e8 2773 if (prefixes & PREFIX_REPNZ) {
4b74fe1f
FB
2774 if (s->cc_op != CC_OP_DYNAMIC)
2775 gen_op_set_cc_op(s->cc_op);
9c605cb1 2776 gen_string_es(s, ot, gen_op_scas + 9 * 2);
4b74fe1f 2777 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2778 } else if (prefixes & PREFIX_REPZ) {
4b74fe1f
FB
2779 if (s->cc_op != CC_OP_DYNAMIC)
2780 gen_op_set_cc_op(s->cc_op);
9c605cb1 2781 gen_string_es(s, ot, gen_op_scas + 9);
4b74fe1f 2782 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2783 } else {
9c605cb1 2784 gen_string_es(s, ot, gen_op_scas);
4b74fe1f 2785 s->cc_op = CC_OP_SUBB + ot;
367e86e8
FB
2786 }
2787 break;
2788
2789 case 0xa6: /* cmpsS */
2790 case 0xa7:
2791 if ((b & 1) == 0)
2792 ot = OT_BYTE;
2793 else
2794 ot = dflag ? OT_LONG : OT_WORD;
2795 if (prefixes & PREFIX_REPNZ) {
4b74fe1f
FB
2796 if (s->cc_op != CC_OP_DYNAMIC)
2797 gen_op_set_cc_op(s->cc_op);
9c605cb1 2798 gen_string_ds(s, ot, gen_op_cmps + 9 * 2);
4b74fe1f 2799 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2800 } else if (prefixes & PREFIX_REPZ) {
4b74fe1f
FB
2801 if (s->cc_op != CC_OP_DYNAMIC)
2802 gen_op_set_cc_op(s->cc_op);
9c605cb1 2803 gen_string_ds(s, ot, gen_op_cmps + 9);
4b74fe1f 2804 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2805 } else {
9c605cb1 2806 gen_string_ds(s, ot, gen_op_cmps);
4b74fe1f 2807 s->cc_op = CC_OP_SUBB + ot;
367e86e8
FB
2808 }
2809 break;
367e86e8
FB
2810 case 0x6c: /* insS */
2811 case 0x6d:
982b4315
FB
2812 if (s->cpl > s->iopl || s->vm86) {
2813 /* NOTE: even for (E)CX = 0 the exception is raised */
c50c0c3f 2814 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
367e86e8 2815 } else {
982b4315
FB
2816 if ((b & 1) == 0)
2817 ot = OT_BYTE;
2818 else
2819 ot = dflag ? OT_LONG : OT_WORD;
2820 if (prefixes & PREFIX_REPZ) {
2821 gen_string_es(s, ot, gen_op_ins + 9);
2822 } else {
2823 gen_string_es(s, ot, gen_op_ins);
2824 }
367e86e8
FB
2825 }
2826 break;
2827 case 0x6e: /* outsS */
2828 case 0x6f:
982b4315
FB
2829 if (s->cpl > s->iopl || s->vm86) {
2830 /* NOTE: even for (E)CX = 0 the exception is raised */
c50c0c3f 2831 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
367e86e8 2832 } else {
982b4315
FB
2833 if ((b & 1) == 0)
2834 ot = OT_BYTE;
2835 else
2836 ot = dflag ? OT_LONG : OT_WORD;
2837 if (prefixes & PREFIX_REPZ) {
2838 gen_string_ds(s, ot, gen_op_outs + 9);
2839 } else {
2840 gen_string_ds(s, ot, gen_op_outs);
2841 }
367e86e8
FB
2842 }
2843 break;
9c605cb1
FB
2844
2845 /************************/
2846 /* port I/O */
ba1c6e37
FB
2847 case 0xe4:
2848 case 0xe5:
982b4315 2849 if (s->cpl > s->iopl || s->vm86) {
c50c0c3f 2850 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
982b4315
FB
2851 } else {
2852 if ((b & 1) == 0)
2853 ot = OT_BYTE;
2854 else
2855 ot = dflag ? OT_LONG : OT_WORD;
2856 val = ldub(s->pc++);
2857 gen_op_movl_T0_im(val);
2858 gen_op_in[ot]();
2859 gen_op_mov_reg_T1[ot][R_EAX]();
2860 }
ba1c6e37
FB
2861 break;
2862 case 0xe6:
2863 case 0xe7:
982b4315 2864 if (s->cpl > s->iopl || s->vm86) {
c50c0c3f 2865 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
982b4315
FB
2866 } else {
2867 if ((b & 1) == 0)
2868 ot = OT_BYTE;
2869 else
2870 ot = dflag ? OT_LONG : OT_WORD;
2871 val = ldub(s->pc++);
2872 gen_op_movl_T0_im(val);
2873 gen_op_mov_TN_reg[ot][1][R_EAX]();
2874 gen_op_out[ot]();
2875 }
ba1c6e37
FB
2876 break;
2877 case 0xec:
2878 case 0xed:
982b4315 2879 if (s->cpl > s->iopl || s->vm86) {
c50c0c3f 2880 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
982b4315
FB
2881 } else {
2882 if ((b & 1) == 0)
2883 ot = OT_BYTE;
2884 else
2885 ot = dflag ? OT_LONG : OT_WORD;
2886 gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
2887 gen_op_in[ot]();
2888 gen_op_mov_reg_T1[ot][R_EAX]();
2889 }
ba1c6e37
FB
2890 break;
2891 case 0xee:
2892 case 0xef:
982b4315 2893 if (s->cpl > s->iopl || s->vm86) {
c50c0c3f 2894 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
982b4315
FB
2895 } else {
2896 if ((b & 1) == 0)
2897 ot = OT_BYTE;
2898 else
2899 ot = dflag ? OT_LONG : OT_WORD;
2900 gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
2901 gen_op_mov_TN_reg[ot][1][R_EAX]();
2902 gen_op_out[ot]();
2903 }
ba1c6e37 2904 break;
367e86e8
FB
2905
2906 /************************/
2907 /* control */
2908 case 0xc2: /* ret im */
367e86e8
FB
2909 val = ldsw(s->pc);
2910 s->pc += 2;
dab2ed99 2911 gen_pop_T0(s);
d0a1ffc9 2912 gen_stack_update(s, val + (2 << s->dflag));
dab2ed99
FB
2913 if (s->dflag == 0)
2914 gen_op_andl_T0_ffff();
367e86e8 2915 gen_op_jmp_T0();
6dbad63e 2916 s->is_jmp = 1;
367e86e8
FB
2917 break;
2918 case 0xc3: /* ret */
dab2ed99
FB
2919 gen_pop_T0(s);
2920 gen_pop_update(s);
2921 if (s->dflag == 0)
2922 gen_op_andl_T0_ffff();
367e86e8 2923 gen_op_jmp_T0();
6dbad63e 2924 s->is_jmp = 1;
367e86e8 2925 break;
dab2ed99
FB
2926 case 0xca: /* lret im */
2927 val = ldsw(s->pc);
2928 s->pc += 2;
d0a1ffc9
FB
2929 do_lret:
2930 gen_stack_A0(s);
dab2ed99 2931 /* pop offset */
d0a1ffc9 2932 gen_op_ld_T0_A0[1 + s->dflag]();
dab2ed99
FB
2933 if (s->dflag == 0)
2934 gen_op_andl_T0_ffff();
d0a1ffc9
FB
2935 /* NOTE: keeping EIP updated is not a problem in case of
2936 exception */
dab2ed99 2937 gen_op_jmp_T0();
dab2ed99 2938 /* pop selector */
d0a1ffc9
FB
2939 gen_op_addl_A0_im(2 << s->dflag);
2940 gen_op_ld_T0_A0[1 + s->dflag]();
5a91de8c 2941 gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
dab2ed99 2942 /* add stack offset */
d0a1ffc9 2943 gen_stack_update(s, val + (4 << s->dflag));
dab2ed99
FB
2944 s->is_jmp = 1;
2945 break;
2946 case 0xcb: /* lret */
d0a1ffc9
FB
2947 val = 0;
2948 goto do_lret;
f631ef9b 2949 case 0xcf: /* iret */
148dfc2a 2950 if (s->vm86 && s->iopl != 3) {
c50c0c3f 2951 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
f631ef9b 2952 } else {
717fc2ad
FB
2953 if (s->cc_op != CC_OP_DYNAMIC)
2954 gen_op_set_cc_op(s->cc_op);
2955 gen_op_jmp_im(pc_start - s->cs_base);
2956 gen_op_iret_protected(s->dflag);
148dfc2a 2957 s->cc_op = CC_OP_EFLAGS;
f631ef9b 2958 }
f631ef9b
FB
2959 s->is_jmp = 1;
2960 break;
dab2ed99
FB
2961 case 0xe8: /* call im */
2962 {
2963 unsigned int next_eip;
2964 ot = dflag ? OT_LONG : OT_WORD;
2965 val = insn_get(s, ot);
2966 next_eip = s->pc - s->cs_base;
2967 val += next_eip;
2968 if (s->dflag == 0)
2969 val &= 0xffff;
2970 gen_op_movl_T0_im(next_eip);
2971 gen_push_T0(s);
d4e8164f 2972 gen_jmp(s, val);
dab2ed99
FB
2973 }
2974 break;
2975 case 0x9a: /* lcall im */
2976 {
2977 unsigned int selector, offset;
d0a1ffc9 2978 /* XXX: not restartable */
dab2ed99
FB
2979
2980 ot = dflag ? OT_LONG : OT_WORD;
2981 offset = insn_get(s, ot);
2982 selector = insn_get(s, OT_WORD);
2983
2984 /* push return segment + offset */
2985 gen_op_movl_T0_seg(R_CS);
2986 gen_push_T0(s);
2987 next_eip = s->pc - s->cs_base;
2988 gen_op_movl_T0_im(next_eip);
2989 gen_push_T0(s);
2990
2991 /* change cs and pc */
2992 gen_op_movl_T0_im(selector);
5a91de8c 2993 gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
dab2ed99
FB
2994 gen_op_jmp_im((unsigned long)offset);
2995 s->is_jmp = 1;
2996 }
2997 break;
367e86e8 2998 case 0xe9: /* jmp */
dab2ed99
FB
2999 ot = dflag ? OT_LONG : OT_WORD;
3000 val = insn_get(s, ot);
3001 val += s->pc - s->cs_base;
3002 if (s->dflag == 0)
3003 val = val & 0xffff;
d4e8164f 3004 gen_jmp(s, val);
367e86e8 3005 break;
dab2ed99
FB
3006 case 0xea: /* ljmp im */
3007 {
3008 unsigned int selector, offset;
3009
3010 ot = dflag ? OT_LONG : OT_WORD;
3011 offset = insn_get(s, ot);
3012 selector = insn_get(s, OT_WORD);
3013
3014 /* change cs and pc */
3015 gen_op_movl_T0_im(selector);
d8bc1fd0
FB
3016 if (!s->vm86) {
3017 /* we compute EIP to handle the exception case */
3018 gen_op_jmp_im(pc_start - s->cs_base);
3019 gen_op_movl_T1_im(offset);
3020 gen_op_ljmp_T0_T1();
3021 } else {
3022 gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
3023 gen_op_jmp_im((unsigned long)offset);
3024 }
dab2ed99
FB
3025 s->is_jmp = 1;
3026 }
3027 break;
367e86e8
FB
3028 case 0xeb: /* jmp Jb */
3029 val = (int8_t)insn_get(s, OT_BYTE);
dab2ed99
FB
3030 val += s->pc - s->cs_base;
3031 if (s->dflag == 0)
3032 val = val & 0xffff;
d4e8164f 3033 gen_jmp(s, val);
367e86e8
FB
3034 break;
3035 case 0x70 ... 0x7f: /* jcc Jb */
3036 val = (int8_t)insn_get(s, OT_BYTE);
367e86e8
FB
3037 goto do_jcc;
3038 case 0x180 ... 0x18f: /* jcc Jv */
3039 if (dflag) {
3040 val = insn_get(s, OT_LONG);
3041 } else {
3042 val = (int16_t)insn_get(s, OT_WORD);
3043 }
367e86e8 3044 do_jcc:
dab2ed99
FB
3045 next_eip = s->pc - s->cs_base;
3046 val += next_eip;
3047 if (s->dflag == 0)
3048 val &= 0xffff;
3049 gen_jcc(s, b, val, next_eip);
367e86e8
FB
3050 break;
3051
5dd9488c 3052 case 0x190 ... 0x19f: /* setcc Gv */
367e86e8
FB
3053 modrm = ldub(s->pc++);
3054 gen_setcc(s, b);
3055 gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
3056 break;
5dd9488c
FB
3057 case 0x140 ... 0x14f: /* cmov Gv, Ev */
3058 ot = dflag ? OT_LONG : OT_WORD;
3059 modrm = ldub(s->pc++);
3060 reg = (modrm >> 3) & 7;
3061 mod = (modrm >> 6) & 3;
3062 gen_setcc(s, b);
3063 if (mod != 3) {
3064 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3065 gen_op_ld_T1_A0[ot]();
3066 } else {
3067 rm = modrm & 7;
3068 gen_op_mov_TN_reg[ot][1][rm]();
3069 }
3070 gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg]();
3071 break;
3072
367e86e8
FB
3073 /************************/
3074 /* flags */
3075 case 0x9c: /* pushf */
148dfc2a 3076 if (s->vm86 && s->iopl != 3) {
c50c0c3f 3077 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
148dfc2a
FB
3078 } else {
3079 if (s->cc_op != CC_OP_DYNAMIC)
3080 gen_op_set_cc_op(s->cc_op);
f631ef9b 3081 gen_op_movl_T0_eflags();
148dfc2a
FB
3082 gen_push_T0(s);
3083 }
367e86e8
FB
3084 break;
3085 case 0x9d: /* popf */
148dfc2a 3086 if (s->vm86 && s->iopl != 3) {
c50c0c3f 3087 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
f631ef9b 3088 } else {
148dfc2a 3089 gen_pop_T0(s);
717fc2ad
FB
3090 if (s->cpl == 0) {
3091 if (s->dflag) {
3092 gen_op_movl_eflags_T0_cpl0();
3093 } else {
3094 gen_op_movw_eflags_T0_cpl0();
3095 }
148dfc2a 3096 } else {
717fc2ad
FB
3097 if (s->dflag) {
3098 gen_op_movl_eflags_T0();
3099 } else {
3100 gen_op_movw_eflags_T0();
3101 }
148dfc2a
FB
3102 }
3103 gen_pop_update(s);
3104 s->cc_op = CC_OP_EFLAGS;
c0ad5542 3105 s->is_jmp = 2; /* abort translation because TF flag may change */
f631ef9b 3106 }
367e86e8
FB
3107 break;
3108 case 0x9e: /* sahf */
3109 gen_op_mov_TN_reg[OT_BYTE][0][R_AH]();
3110 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3111 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3112 gen_op_movb_eflags_T0();
3113 s->cc_op = CC_OP_EFLAGS;
3114 break;
3115 case 0x9f: /* lahf */
3116 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3117 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3118 gen_op_movl_T0_eflags();
3119 gen_op_mov_reg_T0[OT_BYTE][R_AH]();
3120 break;
3121 case 0xf5: /* cmc */
3122 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3123 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3124 gen_op_cmc();
3125 s->cc_op = CC_OP_EFLAGS;
3126 break;
3127 case 0xf8: /* clc */
3128 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3129 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3130 gen_op_clc();
3131 s->cc_op = CC_OP_EFLAGS;
3132 break;
3133 case 0xf9: /* stc */
3134 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3135 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3136 gen_op_stc();
3137 s->cc_op = CC_OP_EFLAGS;
3138 break;
3139 case 0xfc: /* cld */
3140 gen_op_cld();
3141 break;
3142 case 0xfd: /* std */
3143 gen_op_std();
3144 break;
3145
4b74fe1f
FB
3146 /************************/
3147 /* bit operations */
3148 case 0x1ba: /* bt/bts/btr/btc Gv, im */
3149 ot = dflag ? OT_LONG : OT_WORD;
3150 modrm = ldub(s->pc++);
3151 op = (modrm >> 3) & 7;
3152 mod = (modrm >> 6) & 3;
3153 rm = modrm & 7;
3154 if (mod != 3) {
3155 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3156 gen_op_ld_T0_A0[ot]();
3157 } else {
3158 gen_op_mov_TN_reg[ot][0][rm]();
3159 }
3160 /* load shift */
3161 val = ldub(s->pc++);
3162 gen_op_movl_T1_im(val);
3163 if (op < 4)
1a9353d2 3164 goto illegal_op;
4b74fe1f
FB
3165 op -= 4;
3166 gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
d57c4e01 3167 s->cc_op = CC_OP_SARB + ot;
4b74fe1f
FB
3168 if (op != 0) {
3169 if (mod != 3)
3170 gen_op_st_T0_A0[ot]();
3171 else
3172 gen_op_mov_reg_T0[ot][rm]();
3173 }
3174 break;
3175 case 0x1a3: /* bt Gv, Ev */
3176 op = 0;
3177 goto do_btx;
3178 case 0x1ab: /* bts */
3179 op = 1;
3180 goto do_btx;
3181 case 0x1b3: /* btr */
3182 op = 2;
3183 goto do_btx;
3184 case 0x1bb: /* btc */
3185 op = 3;
3186 do_btx:
3187 ot = dflag ? OT_LONG : OT_WORD;
3188 modrm = ldub(s->pc++);
3189 reg = (modrm >> 3) & 7;
3190 mod = (modrm >> 6) & 3;
3191 rm = modrm & 7;
3192 gen_op_mov_TN_reg[OT_LONG][1][reg]();
3193 if (mod != 3) {
3194 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3195 /* specific case: we need to add a displacement */
3196 if (ot == OT_WORD)
3197 gen_op_add_bitw_A0_T1();
3198 else
3199 gen_op_add_bitl_A0_T1();
3200 gen_op_ld_T0_A0[ot]();
3201 } else {
3202 gen_op_mov_TN_reg[ot][0][rm]();
3203 }
3204 gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
d57c4e01 3205 s->cc_op = CC_OP_SARB + ot;
4b74fe1f
FB
3206 if (op != 0) {
3207 if (mod != 3)
3208 gen_op_st_T0_A0[ot]();
3209 else
3210 gen_op_mov_reg_T0[ot][rm]();
3211 }
3212 break;
77f8dd5a
FB
3213 case 0x1bc: /* bsf */
3214 case 0x1bd: /* bsr */
3215 ot = dflag ? OT_LONG : OT_WORD;
3216 modrm = ldub(s->pc++);
3217 reg = (modrm >> 3) & 7;
3218 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
3219 gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();
3220 /* NOTE: we always write back the result. Intel doc says it is
3221 undefined if T0 == 0 */
3222 gen_op_mov_reg_T0[ot][reg]();
3223 s->cc_op = CC_OP_LOGICB + ot;
3224 break;
367e86e8 3225 /************************/
27362c82
FB
3226 /* bcd */
3227 case 0x27: /* daa */
3228 if (s->cc_op != CC_OP_DYNAMIC)
3229 gen_op_set_cc_op(s->cc_op);
3230 gen_op_daa();
3231 s->cc_op = CC_OP_EFLAGS;
3232 break;
3233 case 0x2f: /* das */
3234 if (s->cc_op != CC_OP_DYNAMIC)
3235 gen_op_set_cc_op(s->cc_op);
3236 gen_op_das();
3237 s->cc_op = CC_OP_EFLAGS;
3238 break;
3239 case 0x37: /* aaa */
3240 if (s->cc_op != CC_OP_DYNAMIC)
3241 gen_op_set_cc_op(s->cc_op);
3242 gen_op_aaa();
3243 s->cc_op = CC_OP_EFLAGS;
3244 break;
3245 case 0x3f: /* aas */
3246 if (s->cc_op != CC_OP_DYNAMIC)
3247 gen_op_set_cc_op(s->cc_op);
3248 gen_op_aas();
3249 s->cc_op = CC_OP_EFLAGS;
3250 break;
3251 case 0xd4: /* aam */
3252 val = ldub(s->pc++);
3253 gen_op_aam(val);
3254 s->cc_op = CC_OP_LOGICB;
3255 break;
3256 case 0xd5: /* aad */
3257 val = ldub(s->pc++);
3258 gen_op_aad(val);
3259 s->cc_op = CC_OP_LOGICB;
3260 break;
3261 /************************/
367e86e8
FB
3262 /* misc */
3263 case 0x90: /* nop */
3264 break;
a37904dd
FB
3265 case 0x9b: /* fwait */
3266 break;
0ecfa993 3267 case 0xcc: /* int3 */
5a91de8c 3268 gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
0ecfa993
FB
3269 break;
3270 case 0xcd: /* int N */
3271 val = ldub(s->pc++);
5a91de8c
FB
3272 /* XXX: add error code for vm86 GPF */
3273 if (!s->vm86)
3274 gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
3275 else
3276 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
0ecfa993
FB
3277 break;
3278 case 0xce: /* into */
3279 if (s->cc_op != CC_OP_DYNAMIC)
3280 gen_op_set_cc_op(s->cc_op);
78c34e98 3281 gen_op_into(s->pc - s->cs_base);
9c605cb1 3282 break;
f631ef9b 3283 case 0xfa: /* cli */
982b4315 3284 if (!s->vm86) {
148dfc2a 3285 if (s->cpl <= s->iopl) {
982b4315 3286 gen_op_cli();
148dfc2a 3287 } else {
c50c0c3f 3288 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
148dfc2a 3289 }
982b4315 3290 } else {
148dfc2a 3291 if (s->iopl == 3) {
982b4315 3292 gen_op_cli();
148dfc2a 3293 } else {
c50c0c3f 3294 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
148dfc2a 3295 }
982b4315 3296 }
f631ef9b
FB
3297 break;
3298 case 0xfb: /* sti */
982b4315 3299 if (!s->vm86) {
148dfc2a 3300 if (s->cpl <= s->iopl) {
982b4315 3301 gen_op_sti();
148dfc2a 3302 } else {
c50c0c3f 3303 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
148dfc2a 3304 }
982b4315 3305 } else {
148dfc2a 3306 if (s->iopl == 3) {
982b4315 3307 gen_op_sti();
148dfc2a 3308 } else {
c50c0c3f 3309 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
148dfc2a 3310 }
982b4315 3311 }
f631ef9b 3312 break;
9c605cb1
FB
3313 case 0x62: /* bound */
3314 ot = dflag ? OT_LONG : OT_WORD;
3315 modrm = ldub(s->pc++);
3316 reg = (modrm >> 3) & 7;
3317 mod = (modrm >> 6) & 3;
3318 if (mod == 3)
3319 goto illegal_op;
3320 gen_op_mov_reg_T0[ot][reg]();
3321 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3322 if (ot == OT_WORD)
5a91de8c 3323 gen_op_boundw(pc_start - s->cs_base);
9c605cb1 3324 else
5a91de8c 3325 gen_op_boundl(pc_start - s->cs_base);
0ecfa993 3326 break;
4b74fe1f 3327 case 0x1c8 ... 0x1cf: /* bswap reg */
27362c82
FB
3328 reg = b & 7;
3329 gen_op_mov_TN_reg[OT_LONG][0][reg]();
3330 gen_op_bswapl_T0();
3331 gen_op_mov_reg_T0[OT_LONG][reg]();
3332 break;
3333 case 0xd6: /* salc */
3334 if (s->cc_op != CC_OP_DYNAMIC)
3335 gen_op_set_cc_op(s->cc_op);
3336 gen_op_salc();
3337 break;
1a9353d2
FB
3338 case 0xe0: /* loopnz */
3339 case 0xe1: /* loopz */
3340 if (s->cc_op != CC_OP_DYNAMIC)
3341 gen_op_set_cc_op(s->cc_op);
3342 /* FALL THRU */
3343 case 0xe2: /* loop */
3344 case 0xe3: /* jecxz */
3345 val = (int8_t)insn_get(s, OT_BYTE);
dab2ed99
FB
3346 next_eip = s->pc - s->cs_base;
3347 val += next_eip;
3348 if (s->dflag == 0)
3349 val &= 0xffff;
3350 gen_op_loop[s->aflag][b & 3](val, next_eip);
1a9353d2
FB
3351 s->is_jmp = 1;
3352 break;
5dd9488c 3353 case 0x131: /* rdtsc */
27362c82
FB
3354 gen_op_rdtsc();
3355 break;
367e86e8 3356 case 0x1a2: /* cpuid */
9c605cb1 3357 gen_op_cpuid();
367e86e8 3358 break;
982b4315 3359 case 0xf4: /* hlt */
717fc2ad
FB
3360 if (s->cpl != 0) {
3361 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3362 } else {
3363 if (s->cc_op != CC_OP_DYNAMIC)
3364 gen_op_set_cc_op(s->cc_op);
3365 gen_op_jmp_im(s->pc - s->cs_base);
3366 gen_op_hlt();
3367 s->is_jmp = 1;
3368 }
982b4315 3369 break;
d8bc1fd0
FB
3370 case 0x100:
3371 modrm = ldub(s->pc++);
3372 mod = (modrm >> 6) & 3;
3373 op = (modrm >> 3) & 7;
3374 switch(op) {
3375 case 0: /* sldt */
3376 gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
3377 ot = OT_WORD;
3378 if (mod == 3)
3379 ot += s->dflag;
3380 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
3381 break;
3382 case 2: /* lldt */
3383 if (s->cpl != 0) {
3384 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3385 } else {
3386 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
3387 gen_op_jmp_im(pc_start - s->cs_base);
3388 gen_op_lldt_T0();
3389 }
3390 break;
3391 case 1: /* str */
3392 gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
3393 ot = OT_WORD;
3394 if (mod == 3)
3395 ot += s->dflag;
3396 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
3397 break;
3398 case 3: /* ltr */
3399 if (s->cpl != 0) {
3400 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3401 } else {
3402 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
3403 gen_op_jmp_im(pc_start - s->cs_base);
3404 gen_op_ltr_T0();
3405 }
3406 break;
3407 case 4: /* verr */
3408 case 5: /* verw */
3409 default:
3410 goto illegal_op;
3411 }
3412 break;
3413 case 0x101:
3414 modrm = ldub(s->pc++);
3415 mod = (modrm >> 6) & 3;
3416 op = (modrm >> 3) & 7;
3417 switch(op) {
3418 case 0: /* sgdt */
3419 case 1: /* sidt */
3420 if (mod == 3)
3421 goto illegal_op;
3422 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3423 if (op == 0)
3424 gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit));
3425 else
3426 gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit));
3427 gen_op_stw_T0_A0();
3428 gen_op_addl_A0_im(2);
3429 if (op == 0)
3430 gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base));
3431 else
3432 gen_op_movl_T0_env(offsetof(CPUX86State,idt.base));
3433 if (!s->dflag)
3434 gen_op_andl_T0_im(0xffffff);
3435 gen_op_stl_T0_A0();
3436 break;
3437 case 2: /* lgdt */
3438 case 3: /* lidt */
3439 if (mod == 3)
3440 goto illegal_op;
3441 if (s->cpl != 0) {
3442 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3443 } else {
3444 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3445 gen_op_lduw_T1_A0();
3446 gen_op_addl_A0_im(2);
3447 gen_op_ldl_T0_A0();
3448 if (!s->dflag)
3449 gen_op_andl_T0_im(0xffffff);
3450 if (op == 2) {
3451 gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base));
3452 gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit));
3453 } else {
3454 gen_op_movl_env_T0(offsetof(CPUX86State,idt.base));
3455 gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit));
3456 }
3457 }
3458 break;
3459 case 4: /* smsw */
3460 gen_op_movl_T0_env(offsetof(CPUX86State,cr[0]));
3461 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
3462 break;
3463 case 6: /* lmsw */
3464 if (s->cpl != 0) {
3465 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3466 } else {
3467 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
3468 gen_op_lmsw_T0();
3469 }
3470 break;
717fc2ad
FB
3471 case 7: /* invlpg */
3472 if (s->cpl != 0) {
3473 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3474 } else {
3475 if (mod == 3)
3476 goto illegal_op;
3477 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3478 gen_op_invlpg_A0();
3479 }
3480 break;
d8bc1fd0
FB
3481 default:
3482 goto illegal_op;
3483 }
3484 break;
78c34e98
FB
3485 case 0x102: /* lar */
3486 case 0x103: /* lsl */
3487 if (s->vm86)
3488 goto illegal_op;
3489 ot = dflag ? OT_LONG : OT_WORD;
3490 modrm = ldub(s->pc++);
3491 reg = (modrm >> 3) & 7;
3492 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
3493 gen_op_mov_TN_reg[ot][1][reg]();
3494 if (s->cc_op != CC_OP_DYNAMIC)
3495 gen_op_set_cc_op(s->cc_op);
3496 if (b == 0x102)
3497 gen_op_lar();
3498 else
3499 gen_op_lsl();
3500 s->cc_op = CC_OP_EFLAGS;
3501 gen_op_mov_reg_T1[ot][reg]();
3502 break;
d8bc1fd0
FB
3503 case 0x118:
3504 modrm = ldub(s->pc++);
3505 mod = (modrm >> 6) & 3;
3506 op = (modrm >> 3) & 7;
3507 switch(op) {
3508 case 0: /* prefetchnta */
3509 case 1: /* prefetchnt0 */
3510 case 2: /* prefetchnt0 */
3511 case 3: /* prefetchnt0 */
3512 if (mod == 3)
3513 goto illegal_op;
3514 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3515 /* nothing more to do */
3516 break;
3517 default:
3518 goto illegal_op;
3519 }
3520 break;
3521 case 0x120: /* mov reg, crN */
3522 case 0x122: /* mov crN, reg */
3523 if (s->cpl != 0) {
3524 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3525 } else {
3526 modrm = ldub(s->pc++);
3527 if ((modrm & 0xc0) != 0xc0)
3528 goto illegal_op;
3529 rm = modrm & 7;
3530 reg = (modrm >> 3) & 7;
3531 switch(reg) {
3532 case 0:
3533 case 2:
3534 case 3:
3535 case 4:
3536 if (b & 2) {
3537 gen_op_mov_TN_reg[OT_LONG][0][rm]();
3538 gen_op_movl_crN_T0(reg);
3539 s->is_jmp = 2;
3540 } else {
3541 gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg]));
3542 gen_op_mov_reg_T0[OT_LONG][rm]();
3543 }
3544 break;
3545 default:
3546 goto illegal_op;
3547 }
3548 }
3549 break;
3550 case 0x121: /* mov reg, drN */
3551 case 0x123: /* mov drN, reg */
3552 if (s->cpl != 0) {
3553 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3554 } else {
3555 modrm = ldub(s->pc++);
3556 if ((modrm & 0xc0) != 0xc0)
3557 goto illegal_op;
3558 rm = modrm & 7;
3559 reg = (modrm >> 3) & 7;
3560 /* XXX: do it dynamically with CR4.DE bit */
3561 if (reg == 4 || reg == 5)
3562 goto illegal_op;
3563 if (b & 2) {
3564 gen_op_mov_TN_reg[OT_LONG][0][rm]();
3565 gen_op_movl_drN_T0(reg);
3566 s->is_jmp = 2;
3567 } else {
3568 gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg]));
3569 gen_op_mov_reg_T0[OT_LONG][rm]();
3570 }
3571 }
3572 break;
3573 case 0x106: /* clts */
3574 if (s->cpl != 0) {
3575 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3576 } else {
3577 gen_op_clts();
3578 }
3579 break;
367e86e8 3580 default:
1a9353d2 3581 goto illegal_op;
367e86e8 3582 }
1b6b029e
FB
3583 /* lock generation */
3584 if (s->prefix & PREFIX_LOCK)
3585 gen_op_unlock();
367e86e8 3586 return (long)s->pc;
6dbad63e 3587 illegal_op:
1b6b029e 3588 /* XXX: ensure that no lock was generated */
6dbad63e 3589 return -1;
367e86e8
FB
3590}
3591
dc99065b
FB
3592#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C)
3593#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P)
3594
3595/* flags read by an operation */
3596static uint16_t opc_read_flags[NB_OPS] = {
3597 [INDEX_op_aas] = CC_A,
3598 [INDEX_op_aaa] = CC_A,
3599 [INDEX_op_das] = CC_A | CC_C,
3600 [INDEX_op_daa] = CC_A | CC_C,
3601
3602 [INDEX_op_adcb_T0_T1_cc] = CC_C,
3603 [INDEX_op_adcw_T0_T1_cc] = CC_C,
3604 [INDEX_op_adcl_T0_T1_cc] = CC_C,
3605 [INDEX_op_sbbb_T0_T1_cc] = CC_C,
3606 [INDEX_op_sbbw_T0_T1_cc] = CC_C,
3607 [INDEX_op_sbbl_T0_T1_cc] = CC_C,
3608
982b4315
FB
3609 /* subtle: due to the incl/decl implementation, C is used */
3610 [INDEX_op_incl_T0_cc] = CC_C,
3611 [INDEX_op_decl_T0_cc] = CC_C,
3612
dc99065b
FB
3613 [INDEX_op_into] = CC_O,
3614
dc99065b
FB
3615 [INDEX_op_jb_subb] = CC_C,
3616 [INDEX_op_jb_subw] = CC_C,
3617 [INDEX_op_jb_subl] = CC_C,
3618
3619 [INDEX_op_jz_subb] = CC_Z,
3620 [INDEX_op_jz_subw] = CC_Z,
3621 [INDEX_op_jz_subl] = CC_Z,
3622
3623 [INDEX_op_jbe_subb] = CC_Z | CC_C,
3624 [INDEX_op_jbe_subw] = CC_Z | CC_C,
3625 [INDEX_op_jbe_subl] = CC_Z | CC_C,
3626
3627 [INDEX_op_js_subb] = CC_S,
3628 [INDEX_op_js_subw] = CC_S,
3629 [INDEX_op_js_subl] = CC_S,
3630
3631 [INDEX_op_jl_subb] = CC_O | CC_S,
3632 [INDEX_op_jl_subw] = CC_O | CC_S,
3633 [INDEX_op_jl_subl] = CC_O | CC_S,
3634
3635 [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z,
3636 [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z,
3637 [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z,
3638
3639 [INDEX_op_loopnzw] = CC_Z,
3640 [INDEX_op_loopnzl] = CC_Z,
3641 [INDEX_op_loopzw] = CC_Z,
3642 [INDEX_op_loopzl] = CC_Z,
3643
3644 [INDEX_op_seto_T0_cc] = CC_O,
3645 [INDEX_op_setb_T0_cc] = CC_C,
3646 [INDEX_op_setz_T0_cc] = CC_Z,
3647 [INDEX_op_setbe_T0_cc] = CC_Z | CC_C,
3648 [INDEX_op_sets_T0_cc] = CC_S,
3649 [INDEX_op_setp_T0_cc] = CC_P,
3650 [INDEX_op_setl_T0_cc] = CC_O | CC_S,
3651 [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z,
3652
3653 [INDEX_op_setb_T0_subb] = CC_C,
3654 [INDEX_op_setb_T0_subw] = CC_C,
3655 [INDEX_op_setb_T0_subl] = CC_C,
3656
3657 [INDEX_op_setz_T0_subb] = CC_Z,
3658 [INDEX_op_setz_T0_subw] = CC_Z,
3659 [INDEX_op_setz_T0_subl] = CC_Z,
3660
3661 [INDEX_op_setbe_T0_subb] = CC_Z | CC_C,
3662 [INDEX_op_setbe_T0_subw] = CC_Z | CC_C,
3663 [INDEX_op_setbe_T0_subl] = CC_Z | CC_C,
3664
3665 [INDEX_op_sets_T0_subb] = CC_S,
3666 [INDEX_op_sets_T0_subw] = CC_S,
3667 [INDEX_op_sets_T0_subl] = CC_S,
3668
3669 [INDEX_op_setl_T0_subb] = CC_O | CC_S,
3670 [INDEX_op_setl_T0_subw] = CC_O | CC_S,
3671 [INDEX_op_setl_T0_subl] = CC_O | CC_S,
3672
3673 [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z,
3674 [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z,
3675 [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
3676
3677 [INDEX_op_movl_T0_eflags] = CC_OSZAPC,
3678 [INDEX_op_cmc] = CC_C,
3679 [INDEX_op_salc] = CC_C,
3680
3681 [INDEX_op_rclb_T0_T1_cc] = CC_C,
3682 [INDEX_op_rclw_T0_T1_cc] = CC_C,
3683 [INDEX_op_rcll_T0_T1_cc] = CC_C,
3684 [INDEX_op_rcrb_T0_T1_cc] = CC_C,
3685 [INDEX_op_rcrw_T0_T1_cc] = CC_C,
3686 [INDEX_op_rcrl_T0_T1_cc] = CC_C,
3687};
3688
3689/* flags written by an operation */
3690static uint16_t opc_write_flags[NB_OPS] = {
3691 [INDEX_op_addl_T0_T1_cc] = CC_OSZAPC,
3692 [INDEX_op_orl_T0_T1_cc] = CC_OSZAPC,
3693 [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC,
3694 [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC,
3695 [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC,
3696 [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC,
3697 [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC,
3698 [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC,
3699 [INDEX_op_andl_T0_T1_cc] = CC_OSZAPC,
3700 [INDEX_op_subl_T0_T1_cc] = CC_OSZAPC,
3701 [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC,
3702 [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
3703 [INDEX_op_negl_T0_cc] = CC_OSZAPC,
982b4315
FB
3704 /* subtle: due to the incl/decl implementation, C is used */
3705 [INDEX_op_incl_T0_cc] = CC_OSZAPC,
3706 [INDEX_op_decl_T0_cc] = CC_OSZAPC,
dc99065b
FB
3707 [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
3708
3709 [INDEX_op_mulb_AL_T0] = CC_OSZAPC,
3710 [INDEX_op_imulb_AL_T0] = CC_OSZAPC,
3711 [INDEX_op_mulw_AX_T0] = CC_OSZAPC,
3712 [INDEX_op_imulw_AX_T0] = CC_OSZAPC,
3713 [INDEX_op_mull_EAX_T0] = CC_OSZAPC,
3714 [INDEX_op_imull_EAX_T0] = CC_OSZAPC,
3715 [INDEX_op_imulw_T0_T1] = CC_OSZAPC,
3716 [INDEX_op_imull_T0_T1] = CC_OSZAPC,
3717
3718 /* bcd */
3719 [INDEX_op_aam] = CC_OSZAPC,
3720 [INDEX_op_aad] = CC_OSZAPC,
3721 [INDEX_op_aas] = CC_OSZAPC,
3722 [INDEX_op_aaa] = CC_OSZAPC,
3723 [INDEX_op_das] = CC_OSZAPC,
3724 [INDEX_op_daa] = CC_OSZAPC,
3725
3726 [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
f631ef9b 3727 [INDEX_op_movw_eflags_T0] = CC_OSZAPC,
dc99065b
FB
3728 [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
3729 [INDEX_op_clc] = CC_C,
3730 [INDEX_op_stc] = CC_C,
3731 [INDEX_op_cmc] = CC_C,
3732
3733 [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C,
3734 [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C,
3735 [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C,
3736 [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C,
3737 [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C,
3738 [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C,
3739
3740 [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C,
3741 [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C,
3742 [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C,
3743 [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C,
3744 [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C,
3745 [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C,
3746
3747 [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC,
3748 [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC,
3749 [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC,
3750
3751 [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC,
3752 [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC,
3753 [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC,
3754
3755 [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC,
3756 [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC,
3757 [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC,
3758
3759 [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC,
3760 [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC,
3761 [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC,
3762 [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC,
3763
3764 [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC,
3765 [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC,
3766 [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC,
3767 [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC,
3768
3769 [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
3770 [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
3771 [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
3772 [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC,
3773 [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC,
3774 [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC,
3775 [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC,
3776 [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC,
3777
3778 [INDEX_op_bsfw_T0_cc] = CC_OSZAPC,
3779 [INDEX_op_bsfl_T0_cc] = CC_OSZAPC,
3780 [INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
3781 [INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
3782
9c605cb1
FB
3783#undef STRINGOP
3784#define STRINGOP(x) \
3785 [INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \
3786 [INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \
3787 [INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \
3788 [INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \
3789 [INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \
3790 [INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \
3791 [INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \
3792 [INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \
3793 [INDEX_op_ ## x ## l_a16] = CC_OSZAPC,
3794
3795 STRINGOP(scas)
3796 STRINGOP(repz_scas)
3797 STRINGOP(repnz_scas)
3798 STRINGOP(cmps)
3799 STRINGOP(repz_cmps)
3800 STRINGOP(repnz_cmps)
3801
3802 [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC,
dc99065b
FB
3803 [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
3804 [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
9c605cb1
FB
3805
3806 [INDEX_op_cmpxchg8b] = CC_Z,
78c34e98
FB
3807 [INDEX_op_lar] = CC_Z,
3808 [INDEX_op_lsl] = CC_Z,
d0a1ffc9
FB
3809 [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C,
3810 [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C,
dc99065b
FB
3811};
3812
3813/* simpler form of an operation if no flags need to be generated */
3814static uint16_t opc_simpler[NB_OPS] = {
3815 [INDEX_op_addl_T0_T1_cc] = INDEX_op_addl_T0_T1,
3816 [INDEX_op_orl_T0_T1_cc] = INDEX_op_orl_T0_T1,
3817 [INDEX_op_andl_T0_T1_cc] = INDEX_op_andl_T0_T1,
3818 [INDEX_op_subl_T0_T1_cc] = INDEX_op_subl_T0_T1,
3819 [INDEX_op_xorl_T0_T1_cc] = INDEX_op_xorl_T0_T1,
3820 [INDEX_op_negl_T0_cc] = INDEX_op_negl_T0,
3821 [INDEX_op_incl_T0_cc] = INDEX_op_incl_T0,
3822 [INDEX_op_decl_T0_cc] = INDEX_op_decl_T0,
3823
3824 [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1,
3825 [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1,
3826 [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1,
3827
3828 [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1,
3829 [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1,
3830 [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1,
3831
3832 [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
3833 [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
3834 [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1,
3835
3836 [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1,
3837 [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1,
3838 [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1,
3839
3840 [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1,
3841 [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1,
3842 [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1,
3843};
3844
3845static void optimize_flags_init(void)
3846{
3847 int i;
3848 /* put default values in arrays */
3849 for(i = 0; i < NB_OPS; i++) {
3850 if (opc_simpler[i] == 0)
3851 opc_simpler[i] = i;
3852 }
3853}
3854
3855/* CPU flags computation optimization: we move backward thru the
3856 generated code to see which flags are needed. The operation is
3857 modified if suitable */
3858static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
3859{
3860 uint16_t *opc_ptr;
3861 int live_flags, write_flags, op;
3862
3863 opc_ptr = opc_buf + opc_buf_len;
3864 /* live_flags contains the flags needed by the next instructions
3865 in the code. At the end of the bloc, we consider that all the
3866 flags are live. */
3867 live_flags = CC_OSZAPC;
3868 while (opc_ptr > opc_buf) {
3869 op = *--opc_ptr;
3870 /* if none of the flags written by the instruction is used,
3871 then we can try to find a simpler instruction */
3872 write_flags = opc_write_flags[op];
3873 if ((live_flags & write_flags) == 0) {
3874 *opc_ptr = opc_simpler[op];
3875 }
3876 /* compute the live flags before the instruction */
3877 live_flags &= ~write_flags;
3878 live_flags |= opc_read_flags[op];
3879 }
3880}
3881
5a91de8c
FB
3882/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
3883 basic block 'tb'. If search_pc is TRUE, also generate PC
3884 information for each intermediate instruction. */
717fc2ad 3885static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc)
ba1c6e37
FB
3886{
3887 DisasContext dc1, *dc = &dc1;
dc99065b
FB
3888 uint8_t *pc_ptr;
3889 uint16_t *gen_opc_end;
5a91de8c 3890 int flags, j, lj;
ba1c6e37 3891 long ret;
5a91de8c
FB
3892 uint8_t *pc_start;
3893 uint8_t *cs_base;
dc99065b
FB
3894
3895 /* generate intermediate code */
5a91de8c
FB
3896 pc_start = (uint8_t *)tb->pc;
3897 cs_base = (uint8_t *)tb->cs_base;
3898 flags = tb->flags;
3899
6dbad63e 3900 dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1;
dab2ed99 3901 dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1;
6dbad63e
FB
3902 dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
3903 dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
9c605cb1 3904 dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1;
982b4315
FB
3905 dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3;
3906 dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3;
c50c0c3f 3907 dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1;
ba1c6e37 3908 dc->cc_op = CC_OP_DYNAMIC;
dab2ed99 3909 dc->cs_base = cs_base;
d4e8164f 3910 dc->tb = tb;
717fc2ad
FB
3911 dc->popl_esp_hack = 0;
3912
dc99065b
FB
3913 gen_opc_ptr = gen_opc_buf;
3914 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3915 gen_opparam_ptr = gen_opparam_buf;
0ecfa993 3916
d19893da 3917 dc->is_jmp = DISAS_NEXT;
1017ebe9 3918 pc_ptr = pc_start;
5a91de8c 3919 lj = -1;
1017ebe9 3920 do {
5a91de8c
FB
3921 if (search_pc) {
3922 j = gen_opc_ptr - gen_opc_buf;
3923 if (lj < j) {
3924 lj++;
3925 while (lj < j)
3926 gen_opc_instr_start[lj++] = 0;
3927 gen_opc_pc[lj] = (uint32_t)pc_ptr;
717fc2ad 3928 gen_opc_cc_op[lj] = dc->cc_op;
5a91de8c
FB
3929 gen_opc_instr_start[lj] = 1;
3930 }
3931 }
6dbad63e 3932 ret = disas_insn(dc, pc_ptr);
1a9353d2 3933 if (ret == -1) {
9de5e440
FB
3934 /* we trigger an illegal instruction operation only if it
3935 is the first instruction. Otherwise, we simply stop
3936 generating the code just before it */
3937 if (pc_ptr == pc_start)
3938 return -1;
3939 else
3940 break;
1a9353d2 3941 }
1017ebe9 3942 pc_ptr = (void *)ret;
c50c0c3f
FB
3943 /* if single step mode, we generate only one instruction and
3944 generate an exception */
3945 if (dc->tf)
3946 break;
727d01d4
FB
3947 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
3948 (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
0ecfa993 3949 /* we must store the eflags state if it is not already done */
d19893da 3950 if (dc->is_jmp != DISAS_TB_JUMP) {
d4e8164f
FB
3951 if (dc->cc_op != CC_OP_DYNAMIC)
3952 gen_op_set_cc_op(dc->cc_op);
d19893da 3953 if (dc->is_jmp != DISAS_JUMP) {
d4e8164f
FB
3954 /* we add an additionnal jmp to update the simulated PC */
3955 gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
3956 }
0ecfa993 3957 }
c50c0c3f
FB
3958 if (dc->tf) {
3959 gen_op_raise_exception(EXCP01_SSTP);
3960 }
d4e8164f
FB
3961 if (dc->is_jmp != 3) {
3962 /* indicate that the hash table must be used to find the next TB */
3963 gen_op_movl_T0_0();
3964 }
dc99065b 3965 *gen_opc_ptr = INDEX_op_end;
0ecfa993
FB
3966
3967#ifdef DEBUG_DISAS
586314f2 3968 if (loglevel) {
dc99065b 3969 fprintf(logfile, "----------------\n");
b9adb4a6 3970 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
d19893da 3971 disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32);
1017ebe9 3972 fprintf(logfile, "\n");
982b4315 3973
dc99065b 3974 fprintf(logfile, "OP:\n");
9c605cb1 3975 dump_ops(gen_opc_buf, gen_opparam_buf);
dc99065b
FB
3976 fprintf(logfile, "\n");
3977 }
3978#endif
3979
3980 /* optimize flag computations */
3981 optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
3982
3983#ifdef DEBUG_DISAS
3984 if (loglevel) {
3985 fprintf(logfile, "AFTER FLAGS OPT:\n");
9c605cb1 3986 dump_ops(gen_opc_buf, gen_opparam_buf);
dc99065b
FB
3987 fprintf(logfile, "\n");
3988 }
3989#endif
5a91de8c
FB
3990 if (!search_pc)
3991 tb->size = pc_ptr - pc_start;
3992 return 0;
3993}
3994
717fc2ad
FB
3995int gen_intermediate_code(TranslationBlock *tb)
3996{
3997 return gen_intermediate_code_internal(tb, 0);
3998}
3999
4000int gen_intermediate_code_pc(TranslationBlock *tb)
4001{
4002 return gen_intermediate_code_internal(tb, 1);
4003}
4004
ba1c6e37
FB
4005CPUX86State *cpu_x86_init(void)
4006{
4007 CPUX86State *env;
4008 int i;
dc99065b 4009 static int inited;
ba1c6e37 4010
d19893da 4011 cpu_exec_init();
7d13299d 4012
ba1c6e37
FB
4013 env = malloc(sizeof(CPUX86State));
4014 if (!env)
4015 return NULL;
4016 memset(env, 0, sizeof(CPUX86State));
4017 /* basic FPU init */
4018 for(i = 0;i < 8; i++)
4019 env->fptags[i] = 1;
4020 env->fpuc = 0x37f;
9c605cb1
FB
4021 /* flags setup : we activate the IRQs by default as in user mode */
4022 env->eflags = 0x2 | IF_MASK;
dc99065b
FB
4023
4024 /* init various static tables */
4025 if (!inited) {
4026 inited = 1;
4027 optimize_flags_init();
4028 }
ba1c6e37
FB
4029 return env;
4030}
4031
4032void cpu_x86_close(CPUX86State *env)
4033{
4034 free(env);
4035}
148dfc2a 4036
717fc2ad
FB
4037/***********************************************************/
4038/* x86 mmu */
43518323 4039/* XXX: add PGE support */
717fc2ad
FB
4040
4041/* called when cr3 or PG bit are modified */
4042static int last_pg_state = -1;
4043int phys_ram_size;
4044int phys_ram_fd;
4045uint8_t *phys_ram_base;
4046
4047void cpu_x86_update_cr0(CPUX86State *env)
4048{
4049 int pg_state;
4050 void *map_addr;
4051
4052#ifdef DEBUG_MMU
4053 printf("CR0 update: CR0=0x%08x\n", env->cr[0]);
4054#endif
4055 pg_state = env->cr[0] & CR0_PG_MASK;
4056 if (pg_state != last_pg_state) {
4057 if (!pg_state) {
4058 /* we map the physical memory at address 0 */
4059
4060 map_addr = mmap((void *)0, phys_ram_size, PROT_WRITE | PROT_READ,
4061 MAP_SHARED | MAP_FIXED, phys_ram_fd, 0);
4062 if (map_addr == MAP_FAILED) {
4063 fprintf(stderr,
4064 "Could not map physical memory at host address 0x%08x\n",
4065 0);
4066 exit(1);
4067 }
4068 page_set_flags(0, phys_ram_size,
4069 PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC);
4070 } else {
4071 /* we unmap the physical memory */
4072 munmap((void *)0, phys_ram_size);
4073 page_set_flags(0, phys_ram_size, 0);
4074 }
4075 last_pg_state = pg_state;
4076 }
4077}
4078
4079void cpu_x86_update_cr3(CPUX86State *env)
4080{
4081 if (env->cr[0] & CR0_PG_MASK) {
4082#ifdef DEBUG_MMU
4083 printf("CR3 update: CR3=%08x\n", env->cr[3]);
4084#endif
4085 page_unmap();
4086 }
4087}
4088
4089void cpu_x86_init_mmu(CPUX86State *env)
4090{
4091 last_pg_state = -1;
4092 cpu_x86_update_cr0(env);
4093}
4094
43518323 4095/* XXX: also flush 4MB pages */
717fc2ad
FB
4096void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
4097{
43518323
FB
4098 int flags;
4099 unsigned long virt_addr;
4100
4101 flags = page_get_flags(addr);
4102 if (flags & PAGE_VALID) {
4103 virt_addr = addr & ~0xfff;
4104 munmap((void *)virt_addr, 4096);
4105 page_set_flags(virt_addr, virt_addr + 4096, 0);
4106 }
717fc2ad
FB
4107}
4108
4109/* return value:
4110 -1 = cannot handle fault
4111 0 = nothing more to do
4112 1 = generate PF fault
4113*/
4114int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
4115{
4116 uint8_t *pde_ptr, *pte_ptr;
4117 uint32_t pde, pte, virt_addr;
4118 int cpl, error_code, is_dirty, is_user, prot, page_size;
4119 void *map_addr;
4120
4121 cpl = env->segs[R_CS].selector & 3;
4122 is_user = (cpl == 3);
4123
4124#ifdef DEBUG_MMU
4125 printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n",
4126 addr, is_write, is_user, env->eip);
4127#endif
4128
4129 if (env->user_mode_only) {
4130 /* user mode only emulation */
4131 error_code = 0;
4132 goto do_fault;
4133 }
4134
4135 if (!(env->cr[0] & CR0_PG_MASK))
4136 return -1;
4137
4138 /* page directory entry */
4139 pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3));
4140 pde = ldl(pde_ptr);
4141 if (!(pde & PG_PRESENT_MASK)) {
4142 error_code = 0;
4143 goto do_fault;
4144 }
4145 if (is_user) {
4146 if (!(pde & PG_USER_MASK))
4147 goto do_fault_protect;
4148 if (is_write && !(pde & PG_RW_MASK))
4149 goto do_fault_protect;
4150 } else {
4151 if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) &&
4152 is_write && !(pde & PG_RW_MASK))
4153 goto do_fault_protect;
4154 }
4155 /* if PSE bit is set, then we use a 4MB page */
4156 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
4157 is_dirty = is_write && !(pde & PG_DIRTY_MASK);
4158 if (!(pde & PG_ACCESSED_MASK)) {
4159 pde |= PG_ACCESSED_MASK;
4160 if (is_dirty)
4161 pde |= PG_DIRTY_MASK;
4162 stl(pde_ptr, pde);
4163 }
4164
4165 pte = pde & ~0x003ff000; /* align to 4MB */
4166 page_size = 4096 * 1024;
4167 virt_addr = addr & ~0x003fffff;
4168 } else {
4169 if (!(pde & PG_ACCESSED_MASK)) {
4170 pde |= PG_ACCESSED_MASK;
4171 stl(pde_ptr, pde);
4172 }
4173
4174 /* page directory entry */
4175 pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc));
4176 pte = ldl(pte_ptr);
4177 if (!(pte & PG_PRESENT_MASK)) {
4178 error_code = 0;
4179 goto do_fault;
4180 }
4181 if (is_user) {
4182 if (!(pte & PG_USER_MASK))
4183 goto do_fault_protect;
4184 if (is_write && !(pte & PG_RW_MASK))
4185 goto do_fault_protect;
4186 } else {
4187 if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) &&
4188 is_write && !(pte & PG_RW_MASK))
4189 goto do_fault_protect;
4190 }
4191 is_dirty = is_write && !(pte & PG_DIRTY_MASK);
4192 if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
4193 pte |= PG_ACCESSED_MASK;
4194 if (is_dirty)
4195 pte |= PG_DIRTY_MASK;
4196 stl(pte_ptr, pte);
4197 }
4198 page_size = 4096;
4199 virt_addr = addr & ~0xfff;
4200 }
4201 /* the page can be put in the TLB */
4202 prot = PROT_READ;
4203 if (is_user) {
4204 if (pte & PG_RW_MASK)
4205 prot |= PROT_WRITE;
4206 } else {
4207 if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) ||
4208 (pte & PG_RW_MASK))
4209 prot |= PROT_WRITE;
4210 }
4211 map_addr = mmap((void *)virt_addr, page_size, prot,
4212 MAP_SHARED | MAP_FIXED, phys_ram_fd, pte & ~0xfff);
4213 if (map_addr == MAP_FAILED) {
4214 fprintf(stderr,
4215 "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
4216 pte & ~0xfff, virt_addr);
4217 exit(1);
4218 }
4219 page_set_flags(virt_addr, virt_addr + page_size,
4220 PAGE_VALID | PAGE_EXEC | prot);
4221#ifdef DEBUG_MMU
4222 printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
4223 pte & ~0xfff, virt_addr, (page_size != 4096));
4224#endif
4225 return 0;
4226 do_fault_protect:
4227 error_code = PG_ERROR_P_MASK;
4228 do_fault:
4229 env->cr[2] = addr;
4230 env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
4231 if (is_user)
4232 env->error_code |= PG_ERROR_U_MASK;
4233 return 1;
4234}
4235
4236/***********************************************************/
4237/* x86 debug */
4238
148dfc2a
FB
4239static const char *cc_op_str[] = {
4240 "DYNAMIC",
4241 "EFLAGS",
4242 "MUL",
4243 "ADDB",
4244 "ADDW",
4245 "ADDL",
4246 "ADCB",
4247 "ADCW",
4248 "ADCL",
4249 "SUBB",
4250 "SUBW",
4251 "SUBL",
4252 "SBBB",
4253 "SBBW",
4254 "SBBL",
4255 "LOGICB",
4256 "LOGICW",
4257 "LOGICL",
4258 "INCB",
4259 "INCW",
4260 "INCL",
4261 "DECB",
4262 "DECW",
4263 "DECL",
4264 "SHLB",
4265 "SHLW",
4266 "SHLL",
4267 "SARB",
4268 "SARW",
4269 "SARL",
4270};
4271
4272void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
4273{
4274 int eflags;
4275 char cc_op_name[32];
4276
4277 eflags = env->eflags;
4278 fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
4279 "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
4280 "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n",
4281 env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
4282 env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
4283 env->eip, eflags,
4284 eflags & DF_MASK ? 'D' : '-',
4285 eflags & CC_O ? 'O' : '-',
4286 eflags & CC_S ? 'S' : '-',
4287 eflags & CC_Z ? 'Z' : '-',
4288 eflags & CC_A ? 'A' : '-',
4289 eflags & CC_P ? 'P' : '-',
4290 eflags & CC_C ? 'C' : '-');
4291 fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
d8bc1fd0
FB
4292 env->segs[R_CS].selector,
4293 env->segs[R_SS].selector,
4294 env->segs[R_DS].selector,
4295 env->segs[R_ES].selector,
4296 env->segs[R_FS].selector,
4297 env->segs[R_GS].selector);
148dfc2a
FB
4298 if (flags & X86_DUMP_CCOP) {
4299 if ((unsigned)env->cc_op < CC_OP_NB)
4300 strcpy(cc_op_name, cc_op_str[env->cc_op]);
4301 else
4302 snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
4303 fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
4304 env->cc_src, env->cc_dst, cc_op_name);
4305 }
4306 if (flags & X86_DUMP_FPU) {
4307 fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
4308 (double)env->fpregs[0],
4309 (double)env->fpregs[1],
4310 (double)env->fpregs[2],
4311 (double)env->fpregs[3]);
4312 fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n",
4313 (double)env->fpregs[4],
4314 (double)env->fpregs[5],
4315 (double)env->fpregs[7],
4316 (double)env->fpregs[8]);
4317 }
4318}