]> git.ipfire.org Git - thirdparty/qemu.git/blame - target-i386/translate-copy.c
find -type f | xargs sed -i 's/[\t ]$//g' # on most files
[thirdparty/qemu.git] / target-i386 / translate-copy.c
CommitLineData
58fe2f10
FB
1/*
2 * i386 on i386 translation
5fafdf24 3 *
58fe2f10
FB
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
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
19 */
67b915a5
FB
20#include "config.h"
21
58fe2f10
FB
22#include <stdarg.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <inttypes.h>
58fe2f10 27#include <assert.h>
58fe2f10
FB
28
29#include "cpu.h"
30#include "exec-all.h"
31#include "disas.h"
32
42c3c0cc
FB
33#ifdef USE_CODE_COPY
34
67b915a5
FB
35#include <signal.h>
36#include <sys/mman.h>
37#include <sys/ucontext.h>
38
58fe2f10
FB
39extern char exec_loop;
40
41/* operand size */
42enum {
43 OT_BYTE = 0,
44 OT_WORD,
5fafdf24 45 OT_LONG,
58fe2f10
FB
46 OT_QUAD,
47};
48
49#define PREFIX_REPZ 0x01
50#define PREFIX_REPNZ 0x02
51#define PREFIX_LOCK 0x04
52#define PREFIX_DATA 0x08
53#define PREFIX_ADR 0x10
54
55typedef struct DisasContext {
56 /* current insn context */
57 int override; /* -1 if no override */
58 int prefix;
59 int aflag, dflag;
14ce26e7 60 target_ulong pc; /* pc = eip + cs_base */
58fe2f10
FB
61 int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
62 static state change (stop translation) */
63 /* code output */
64 uint8_t *gen_code_ptr;
65 uint8_t *gen_code_start;
5fafdf24 66
58fe2f10 67 /* current block context */
14ce26e7 68 target_ulong cs_base; /* base of CS segment */
58fe2f10
FB
69 int pe; /* protected mode */
70 int code32; /* 32 bit code segment */
71 int f_st; /* currently unused */
72 int vm86; /* vm86 mode */
73 int cpl;
74 int iopl;
42c3c0cc 75 int flags;
58fe2f10
FB
76 struct TranslationBlock *tb;
77} DisasContext;
78
79#define CPU_FIELD_OFFSET(field) offsetof(CPUState, field)
80
81#define CPU_SEG 0x64 /* fs override */
82
83static inline void gb(DisasContext *s, uint32_t val)
84{
85 *s->gen_code_ptr++ = val;
86}
87
88static inline void gw(DisasContext *s, uint32_t val)
89{
90 *s->gen_code_ptr++ = val;
91 *s->gen_code_ptr++ = val >> 8;
92}
93
94static inline void gl(DisasContext *s, uint32_t val)
95{
96 *s->gen_code_ptr++ = val;
97 *s->gen_code_ptr++ = val >> 8;
98 *s->gen_code_ptr++ = val >> 16;
99 *s->gen_code_ptr++ = val >> 24;
100}
101
102static inline void gjmp(DisasContext *s, long val)
103{
104 gb(s, 0xe9); /* jmp */
105 gl(s, val - (long)(s->gen_code_ptr + 4));
106}
107
5fafdf24 108static inline void gen_movl_addr_im(DisasContext *s,
58fe2f10
FB
109 uint32_t addr, uint32_t val)
110{
111 gb(s, CPU_SEG); /* seg movl im, addr */
5fafdf24 112 gb(s, 0xc7);
58fe2f10
FB
113 gb(s, 0x05);
114 gl(s, addr);
115 gl(s, val);
116}
117
5fafdf24 118static inline void gen_movw_addr_im(DisasContext *s,
58fe2f10
FB
119 uint32_t addr, uint32_t val)
120{
121 gb(s, CPU_SEG); /* seg movl im, addr */
5fafdf24
TS
122 gb(s, 0x66);
123 gb(s, 0xc7);
58fe2f10
FB
124 gb(s, 0x05);
125 gl(s, addr);
126 gw(s, val);
127}
128
129
130static void gen_jmp(DisasContext *s, uint32_t target_eip)
131{
132 TranslationBlock *tb = s->tb;
133
134 gb(s, 0xe9); /* jmp */
135 tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
136 gl(s, 0);
137
138 tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
139 gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
140 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
141 gjmp(s, (long)&exec_loop);
142
143 s->is_jmp = 1;
144}
145
146static void gen_jcc(DisasContext *s, int op,
147 uint32_t target_eip, uint32_t next_eip)
148{
149 TranslationBlock *tb = s->tb;
150
151 gb(s, 0x0f); /* jcc */
152 gb(s, 0x80 + op);
153 tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
154 gl(s, 0);
155 gb(s, 0xe9); /* jmp */
156 tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start;
157 gl(s, 0);
5fafdf24 158
58fe2f10
FB
159 tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
160 gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
161 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
162 gjmp(s, (long)&exec_loop);
163
164 tb->tb_next_offset[1] = s->gen_code_ptr - s->gen_code_start;
165 gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), next_eip);
166 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb | 1);
167 gjmp(s, (long)&exec_loop);
168
169 s->is_jmp = 1;
170}
171
172static void gen_eob(DisasContext *s)
173{
174 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0);
175 gjmp(s, (long)&exec_loop);
176
177 s->is_jmp = 1;
178}
179
180static inline void gen_lea_modrm(DisasContext *s, int modrm)
181{
182 int havesib;
183 int base, disp;
184 int index;
185 int scale;
186 int mod, rm, code;
187
188 mod = (modrm >> 6) & 3;
189 rm = modrm & 7;
190
191 if (s->aflag) {
192
193 havesib = 0;
194 base = rm;
195 index = 0;
196 scale = 0;
5fafdf24 197
58fe2f10
FB
198 if (base == 4) {
199 havesib = 1;
200 code = ldub_code(s->pc++);
201 scale = (code >> 6) & 3;
202 index = (code >> 3) & 7;
203 base = code & 7;
204 }
205
206 switch (mod) {
207 case 0:
208 if (base == 5) {
209 base = -1;
210 disp = ldl_code(s->pc);
211 s->pc += 4;
212 } else {
213 disp = 0;
214 }
215 break;
216 case 1:
217 disp = (int8_t)ldub_code(s->pc++);
218 break;
219 default:
220 case 2:
221 disp = ldl_code(s->pc);
222 s->pc += 4;
223 break;
224 }
5fafdf24 225
58fe2f10
FB
226 } else {
227 switch (mod) {
228 case 0:
229 if (rm == 6) {
230 disp = lduw_code(s->pc);
231 s->pc += 2;
232 } else {
233 disp = 0;
234 }
235 break;
236 case 1:
237 disp = (int8_t)ldub_code(s->pc++);
238 break;
239 default:
240 case 2:
241 disp = lduw_code(s->pc);
242 s->pc += 2;
243 break;
244 }
245 }
246}
247
248static inline void parse_modrm(DisasContext *s, int modrm)
249{
250 if ((modrm & 0xc0) != 0xc0)
5fafdf24 251 gen_lea_modrm(s, modrm);
58fe2f10
FB
252}
253
254static inline uint32_t insn_get(DisasContext *s, int ot)
255{
256 uint32_t ret;
257
258 switch(ot) {
259 case OT_BYTE:
260 ret = ldub_code(s->pc);
261 s->pc++;
262 break;
263 case OT_WORD:
264 ret = lduw_code(s->pc);
265 s->pc += 2;
266 break;
267 default:
268 case OT_LONG:
269 ret = ldl_code(s->pc);
270 s->pc += 4;
271 break;
272 }
273 return ret;
274}
275
276/* convert one instruction. s->is_jmp is set if the translation must
277 be stopped. */
278static int disas_insn(DisasContext *s)
279{
14ce26e7 280 target_ulong pc_start, pc_tmp, pc_start_insn;
58fe2f10
FB
281 int b, prefixes, aflag, dflag, next_eip, val;
282 int ot;
42c3c0cc 283 int modrm, mod, op, rm;
58fe2f10
FB
284
285 pc_start = s->pc;
286 prefixes = 0;
287 aflag = s->code32;
288 dflag = s->code32;
289 s->override = -1;
290 next_byte:
291 b = ldub_code(s->pc);
292 s->pc++;
293 /* check prefixes */
294 switch (b) {
295 case 0xf3:
296 prefixes |= PREFIX_REPZ;
297 goto next_byte;
298 case 0xf2:
299 prefixes |= PREFIX_REPNZ;
300 goto next_byte;
301 case 0xf0:
302 prefixes |= PREFIX_LOCK;
303 goto next_byte;
304 case 0x2e:
305 s->override = R_CS;
306 goto next_byte;
307 case 0x36:
308 s->override = R_SS;
309 goto next_byte;
310 case 0x3e:
311 s->override = R_DS;
312 goto next_byte;
313 case 0x26:
314 s->override = R_ES;
315 goto next_byte;
316 case 0x64:
317 s->override = R_FS;
318 goto next_byte;
319 case 0x65:
320 s->override = R_GS;
321 goto next_byte;
322 case 0x66:
323 prefixes |= PREFIX_DATA;
324 goto next_byte;
325 case 0x67:
326 prefixes |= PREFIX_ADR;
327 goto next_byte;
328 }
329
330 if (prefixes & PREFIX_DATA)
331 dflag ^= 1;
332 if (prefixes & PREFIX_ADR)
333 aflag ^= 1;
334
335 s->prefix = prefixes;
336 s->aflag = aflag;
337 s->dflag = dflag;
338
339 /* lock generation */
340 if (prefixes & PREFIX_LOCK)
341 goto unsupported_op;
342 if (s->override == R_FS || s->override == R_GS || s->override == R_CS)
343 goto unsupported_op;
344
345 pc_start_insn = s->pc - 1;
346 /* now check op code */
347 reswitch:
348 switch(b) {
349 case 0x0f:
350 /**************************/
351 /* extended op code */
352 b = ldub_code(s->pc++) | 0x100;
353 goto reswitch;
5fafdf24 354
58fe2f10
FB
355 /**************************/
356 /* arith & logic */
357 case 0x00 ... 0x05:
358 case 0x08 ... 0x0d:
359 case 0x10 ... 0x15:
360 case 0x18 ... 0x1d:
361 case 0x20 ... 0x25:
362 case 0x28 ... 0x2d:
363 case 0x30 ... 0x35:
364 case 0x38 ... 0x3d:
365 {
366 int f;
367 f = (b >> 1) & 3;
368
369 if ((b & 1) == 0)
370 ot = OT_BYTE;
371 else
372 ot = dflag ? OT_LONG : OT_WORD;
5fafdf24 373
58fe2f10
FB
374 switch(f) {
375 case 0: /* OP Ev, Gv */
376 modrm = ldub_code(s->pc++);
377 parse_modrm(s, modrm);
378 break;
379 case 1: /* OP Gv, Ev */
380 modrm = ldub_code(s->pc++);
381 parse_modrm(s, modrm);
382 break;
383 case 2: /* OP A, Iv */
384 insn_get(s, ot);
385 break;
386 }
387 }
388 break;
389
390 case 0x80: /* GRP1 */
391 case 0x81:
d64477af 392 case 0x82:
58fe2f10
FB
393 case 0x83:
394 {
395 if ((b & 1) == 0)
396 ot = OT_BYTE;
397 else
398 ot = dflag ? OT_LONG : OT_WORD;
5fafdf24 399
58fe2f10
FB
400 modrm = ldub_code(s->pc++);
401 parse_modrm(s, modrm);
402
403 switch(b) {
404 default:
405 case 0x80:
406 case 0x81:
d64477af 407 case 0x82:
58fe2f10
FB
408 insn_get(s, ot);
409 break;
410 case 0x83:
411 insn_get(s, OT_BYTE);
412 break;
413 }
414 }
415 break;
416
417 /**************************/
418 /* inc, dec, and other misc arith */
419 case 0x40 ... 0x47: /* inc Gv */
420 break;
421 case 0x48 ... 0x4f: /* dec Gv */
422 break;
423 case 0xf6: /* GRP3 */
424 case 0xf7:
425 if ((b & 1) == 0)
426 ot = OT_BYTE;
427 else
428 ot = dflag ? OT_LONG : OT_WORD;
429
430 modrm = ldub_code(s->pc++);
431 op = (modrm >> 3) & 7;
432 parse_modrm(s, modrm);
433
434 switch(op) {
435 case 0: /* test */
436 insn_get(s, ot);
437 break;
438 case 2: /* not */
439 break;
440 case 3: /* neg */
441 break;
442 case 4: /* mul */
443 break;
444 case 5: /* imul */
445 break;
446 case 6: /* div */
447 break;
448 case 7: /* idiv */
449 break;
450 default:
451 goto illegal_op;
452 }
453 break;
454
455 case 0xfe: /* GRP4 */
456 case 0xff: /* GRP5 */
457 if ((b & 1) == 0)
458 ot = OT_BYTE;
459 else
460 ot = dflag ? OT_LONG : OT_WORD;
461
462 modrm = ldub_code(s->pc++);
463 mod = (modrm >> 6) & 3;
464 op = (modrm >> 3) & 7;
465 if (op >= 2 && b == 0xfe) {
466 goto illegal_op;
467 }
468 pc_tmp = s->pc;
469 parse_modrm(s, modrm);
470
471 switch(op) {
472 case 0: /* inc Ev */
473 break;
474 case 1: /* dec Ev */
475 break;
476 case 2: /* call Ev */
477 /* XXX: optimize and handle MEM exceptions specifically
5fafdf24
TS
478 fs movl %eax, regs[0]
479 movl Ev, %eax
58fe2f10
FB
480 pushl next_eip
481 fs movl %eax, eip
482 */
483 goto unsupported_op;
484 case 3: /* lcall Ev */
485 goto unsupported_op;
486 case 4: /* jmp Ev */
487 /* XXX: optimize and handle MEM exceptions specifically
5fafdf24
TS
488 fs movl %eax, regs[0]
489 movl Ev, %eax
58fe2f10
FB
490 fs movl %eax, eip
491 */
492 goto unsupported_op;
493 case 5: /* ljmp Ev */
494 goto unsupported_op;
495 case 6: /* push Ev */
496 break;
497 default:
498 goto illegal_op;
499 }
500 break;
501 case 0xa8: /* test eAX, Iv */
502 case 0xa9:
503 if ((b & 1) == 0)
504 ot = OT_BYTE;
505 else
506 ot = dflag ? OT_LONG : OT_WORD;
507 insn_get(s, ot);
508 break;
5fafdf24 509
58fe2f10
FB
510 case 0x98: /* CWDE/CBW */
511 break;
512 case 0x99: /* CDQ/CWD */
513 break;
514 case 0x1af: /* imul Gv, Ev */
515 case 0x69: /* imul Gv, Ev, I */
516 case 0x6b:
517 ot = dflag ? OT_LONG : OT_WORD;
518 modrm = ldub_code(s->pc++);
519 parse_modrm(s, modrm);
520 if (b == 0x69) {
521 insn_get(s, ot);
522 } else if (b == 0x6b) {
523 insn_get(s, OT_BYTE);
524 } else {
525 }
526 break;
527
528 case 0x84: /* test Ev, Gv */
5fafdf24
TS
529 case 0x85:
530
58fe2f10
FB
531 case 0x1c0:
532 case 0x1c1: /* xadd Ev, Gv */
533
534 case 0x1b0:
535 case 0x1b1: /* cmpxchg Ev, Gv */
536
537 case 0x8f: /* pop Ev */
538
539 case 0x88:
540 case 0x89: /* mov Gv, Ev */
541
542 case 0x8a:
543 case 0x8b: /* mov Ev, Gv */
544
545 case 0x1b6: /* movzbS Gv, Eb */
546 case 0x1b7: /* movzwS Gv, Eb */
547 case 0x1be: /* movsbS Gv, Eb */
548 case 0x1bf: /* movswS Gv, Eb */
549
550 case 0x86:
551 case 0x87: /* xchg Ev, Gv */
552
553 case 0xd0:
554 case 0xd1: /* shift Ev,1 */
555
556 case 0xd2:
557 case 0xd3: /* shift Ev,cl */
558
559 case 0x1a5: /* shld cl */
560 case 0x1ad: /* shrd cl */
561
562 case 0x190 ... 0x19f: /* setcc Gv */
563
564 /* XXX: emulate cmov if not available ? */
565 case 0x140 ... 0x14f: /* cmov Gv, Ev */
566
567 case 0x1a3: /* bt Gv, Ev */
568 case 0x1ab: /* bts */
569 case 0x1b3: /* btr */
570 case 0x1bb: /* btc */
571
572 case 0x1bc: /* bsf */
573 case 0x1bd: /* bsr */
574
575 modrm = ldub_code(s->pc++);
576 parse_modrm(s, modrm);
577 break;
578
579 case 0x1c7: /* cmpxchg8b */
580 modrm = ldub_code(s->pc++);
581 mod = (modrm >> 6) & 3;
582 if (mod == 3)
583 goto illegal_op;
584 parse_modrm(s, modrm);
585 break;
5fafdf24 586
58fe2f10
FB
587 /**************************/
588 /* push/pop */
589 case 0x50 ... 0x57: /* push */
590 case 0x58 ... 0x5f: /* pop */
591 case 0x60: /* pusha */
592 case 0x61: /* popa */
593 break;
594
595 case 0x68: /* push Iv */
596 case 0x6a:
597 ot = dflag ? OT_LONG : OT_WORD;
598 if (b == 0x68)
599 insn_get(s, ot);
600 else
601 insn_get(s, OT_BYTE);
602 break;
603 case 0xc8: /* enter */
604 lduw_code(s->pc);
605 s->pc += 2;
606 ldub_code(s->pc++);
607 break;
608 case 0xc9: /* leave */
609 break;
610
611 case 0x06: /* push es */
612 case 0x0e: /* push cs */
613 case 0x16: /* push ss */
614 case 0x1e: /* push ds */
615 /* XXX: optimize:
616 push segs[n].selector
617 */
618 goto unsupported_op;
619 case 0x1a0: /* push fs */
620 case 0x1a8: /* push gs */
621 goto unsupported_op;
622 case 0x07: /* pop es */
623 case 0x17: /* pop ss */
624 case 0x1f: /* pop ds */
625 goto unsupported_op;
626 case 0x1a1: /* pop fs */
627 case 0x1a9: /* pop gs */
628 goto unsupported_op;
629 case 0x8e: /* mov seg, Gv */
630 /* XXX: optimize:
631 fs movl r, regs[]
632 movl segs[].selector, r
633 mov r, Gv
634 fs movl regs[], r
635 */
636 goto unsupported_op;
637 case 0x8c: /* mov Gv, seg */
638 goto unsupported_op;
639 case 0xc4: /* les Gv */
640 op = R_ES;
641 goto do_lxx;
642 case 0xc5: /* lds Gv */
643 op = R_DS;
644 goto do_lxx;
645 case 0x1b2: /* lss Gv */
646 op = R_SS;
647 goto do_lxx;
648 case 0x1b4: /* lfs Gv */
649 op = R_FS;
650 goto do_lxx;
651 case 0x1b5: /* lgs Gv */
652 op = R_GS;
653 do_lxx:
654 goto unsupported_op;
58fe2f10
FB
655 /************************/
656 /* floats */
5fafdf24 657 case 0xd8 ... 0xdf:
42c3c0cc
FB
658#if 1
659 /* currently not stable enough */
660 goto unsupported_op;
661#else
662 if (s->flags & (HF_EM_MASK | HF_TS_MASK))
663 goto unsupported_op;
664#endif
665#if 0
666 /* for testing FPU context switch */
667 {
668 static int count;
669 count = (count + 1) % 3;
670 if (count != 0)
671 goto unsupported_op;
672 }
673#endif
58fe2f10
FB
674 modrm = ldub_code(s->pc++);
675 mod = (modrm >> 6) & 3;
676 rm = modrm & 7;
677 op = ((b & 7) << 3) | ((modrm >> 3) & 7);
678 if (mod != 3) {
679 /* memory op */
42c3c0cc 680 parse_modrm(s, modrm);
58fe2f10
FB
681 switch(op) {
682 case 0x00 ... 0x07: /* fxxxs */
683 case 0x10 ... 0x17: /* fixxxl */
684 case 0x20 ... 0x27: /* fxxxl */
685 case 0x30 ... 0x37: /* fixxx */
58fe2f10
FB
686 break;
687 case 0x08: /* flds */
688 case 0x0a: /* fsts */
689 case 0x0b: /* fstps */
690 case 0x18: /* fildl */
691 case 0x1a: /* fistl */
692 case 0x1b: /* fistpl */
693 case 0x28: /* fldl */
694 case 0x2a: /* fstl */
695 case 0x2b: /* fstpl */
696 case 0x38: /* filds */
697 case 0x3a: /* fists */
698 case 0x3b: /* fistps */
58fe2f10 699 case 0x0c: /* fldenv mem */
58fe2f10 700 case 0x0d: /* fldcw mem */
58fe2f10 701 case 0x0e: /* fnstenv mem */
58fe2f10 702 case 0x0f: /* fnstcw mem */
58fe2f10 703 case 0x1d: /* fldt mem */
58fe2f10 704 case 0x1f: /* fstpt mem */
58fe2f10 705 case 0x2c: /* frstor mem */
58fe2f10 706 case 0x2e: /* fnsave mem */
58fe2f10 707 case 0x2f: /* fnstsw mem */
58fe2f10 708 case 0x3c: /* fbld */
58fe2f10 709 case 0x3e: /* fbstp */
58fe2f10 710 case 0x3d: /* fildll */
58fe2f10 711 case 0x3f: /* fistpll */
58fe2f10
FB
712 break;
713 default:
714 goto illegal_op;
715 }
716 } else {
717 /* register float ops */
58fe2f10
FB
718 switch(op) {
719 case 0x08: /* fld sti */
58fe2f10 720 case 0x09: /* fxchg sti */
58fe2f10
FB
721 break;
722 case 0x0a: /* grp d9/2 */
723 switch(rm) {
724 case 0: /* fnop */
725 break;
726 default:
727 goto illegal_op;
728 }
729 break;
730 case 0x0c: /* grp d9/4 */
731 switch(rm) {
732 case 0: /* fchs */
58fe2f10 733 case 1: /* fabs */
58fe2f10 734 case 4: /* ftst */
58fe2f10 735 case 5: /* fxam */
58fe2f10
FB
736 break;
737 default:
738 goto illegal_op;
739 }
740 break;
741 case 0x0d: /* grp d9/5 */
58fe2f10 742 switch(rm) {
42c3c0cc
FB
743 case 0:
744 case 1:
745 case 2:
746 case 3:
747 case 4:
748 case 5:
749 case 6:
58fe2f10
FB
750 break;
751 default:
42c3c0cc 752 goto illegal_op;
58fe2f10
FB
753 }
754 break;
42c3c0cc
FB
755 case 0x0e: /* grp d9/6 */
756 break;
58fe2f10 757 case 0x0f: /* grp d9/7 */
58fe2f10
FB
758 break;
759 case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
760 case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
761 case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
58fe2f10
FB
762 break;
763 case 0x02: /* fcom */
58fe2f10
FB
764 break;
765 case 0x03: /* fcomp */
58fe2f10
FB
766 break;
767 case 0x15: /* da/5 */
768 switch(rm) {
769 case 1: /* fucompp */
58fe2f10
FB
770 break;
771 default:
772 goto illegal_op;
773 }
774 break;
775 case 0x1c:
776 switch(rm) {
777 case 0: /* feni (287 only, just do nop here) */
58fe2f10 778 case 1: /* fdisi (287 only, just do nop here) */
42c3c0cc 779 goto unsupported_op;
58fe2f10 780 case 2: /* fclex */
58fe2f10 781 case 3: /* fninit */
58fe2f10
FB
782 case 4: /* fsetpm (287 only, just do nop here) */
783 break;
784 default:
785 goto illegal_op;
786 }
787 break;
788 case 0x1d: /* fucomi */
58fe2f10
FB
789 break;
790 case 0x1e: /* fcomi */
58fe2f10 791 break;
14ce26e7
FB
792 case 0x28: /* ffree sti */
793 break;
58fe2f10 794 case 0x2a: /* fst sti */
58fe2f10
FB
795 break;
796 case 0x2b: /* fstp sti */
58fe2f10
FB
797 break;
798 case 0x2c: /* fucom st(i) */
58fe2f10
FB
799 break;
800 case 0x2d: /* fucomp st(i) */
58fe2f10
FB
801 break;
802 case 0x33: /* de/3 */
803 switch(rm) {
804 case 1: /* fcompp */
58fe2f10
FB
805 break;
806 default:
807 goto illegal_op;
808 }
809 break;
810 case 0x3c: /* df/4 */
811 switch(rm) {
812 case 0:
58fe2f10
FB
813 break;
814 default:
815 goto illegal_op;
816 }
817 break;
818 case 0x3d: /* fucomip */
58fe2f10
FB
819 break;
820 case 0x3e: /* fcomip */
58fe2f10
FB
821 break;
822 case 0x10 ... 0x13: /* fcmovxx */
823 case 0x18 ... 0x1b:
58fe2f10
FB
824 break;
825 default:
826 goto illegal_op;
827 }
828 }
42c3c0cc 829 s->tb->cflags |= CF_TB_FP_USED;
58fe2f10 830 break;
42c3c0cc 831
58fe2f10
FB
832 /**************************/
833 /* mov */
834 case 0xc6:
835 case 0xc7: /* mov Ev, Iv */
836 if ((b & 1) == 0)
837 ot = OT_BYTE;
838 else
839 ot = dflag ? OT_LONG : OT_WORD;
840 modrm = ldub_code(s->pc++);
841 parse_modrm(s, modrm);
842 insn_get(s, ot);
843 break;
844
845 case 0x8d: /* lea */
846 ot = dflag ? OT_LONG : OT_WORD;
847 modrm = ldub_code(s->pc++);
848 mod = (modrm >> 6) & 3;
849 if (mod == 3)
850 goto illegal_op;
851 parse_modrm(s, modrm);
852 break;
5fafdf24 853
58fe2f10
FB
854 case 0xa0: /* mov EAX, Ov */
855 case 0xa1:
856 case 0xa2: /* mov Ov, EAX */
857 case 0xa3:
858 if ((b & 1) == 0)
859 ot = OT_BYTE;
860 else
861 ot = dflag ? OT_LONG : OT_WORD;
862 if (s->aflag)
863 insn_get(s, OT_LONG);
864 else
865 insn_get(s, OT_WORD);
866 break;
867 case 0xd7: /* xlat */
868 break;
869 case 0xb0 ... 0xb7: /* mov R, Ib */
870 insn_get(s, OT_BYTE);
871 break;
872 case 0xb8 ... 0xbf: /* mov R, Iv */
873 ot = dflag ? OT_LONG : OT_WORD;
874 insn_get(s, ot);
875 break;
876
877 case 0x91 ... 0x97: /* xchg R, EAX */
878 break;
879
880 /************************/
881 /* shifts */
882 case 0xc0:
883 case 0xc1: /* shift Ev,imm */
884
885 case 0x1a4: /* shld imm */
886 case 0x1ac: /* shrd imm */
887 modrm = ldub_code(s->pc++);
888 parse_modrm(s, modrm);
889 ldub_code(s->pc++);
890 break;
5fafdf24 891
58fe2f10
FB
892 /************************/
893 /* string ops */
894
895 case 0xa4: /* movsS */
896 case 0xa5:
897 break;
5fafdf24 898
58fe2f10
FB
899 case 0xaa: /* stosS */
900 case 0xab:
901 break;
902
903 case 0xac: /* lodsS */
904 case 0xad:
905 break;
906
907 case 0xae: /* scasS */
908 case 0xaf:
909 break;
910
911 case 0xa6: /* cmpsS */
912 case 0xa7:
913 break;
914
915 case 0x6c: /* insS */
916 case 0x6d:
917 goto unsupported_op;
918
919 case 0x6e: /* outsS */
920 case 0x6f:
921 goto unsupported_op;
922
923 /************************/
924 /* port I/O */
925 case 0xe4:
926 case 0xe5:
927 goto unsupported_op;
928
929 case 0xe6:
930 case 0xe7:
931 goto unsupported_op;
932
933 case 0xec:
934 case 0xed:
935 goto unsupported_op;
936
937 case 0xee:
938 case 0xef:
939 goto unsupported_op;
940
941 /************************/
942 /* control */
943#if 0
944 case 0xc2: /* ret im */
945 val = ldsw_code(s->pc);
946 s->pc += 2;
947 gen_pop_T0(s);
948 gen_stack_update(s, val + (2 << s->dflag));
949 if (s->dflag == 0)
950 gen_op_andl_T0_ffff();
951 gen_op_jmp_T0();
952 gen_eob(s);
953 break;
954#endif
955
956 case 0xc3: /* ret */
957 gb(s, CPU_SEG);
5fafdf24 958 if (!s->dflag)
58fe2f10
FB
959 gb(s, 0x66); /* d16 */
960 gb(s, 0x8f); /* pop addr */
961 gb(s, 0x05);
962 gl(s, CPU_FIELD_OFFSET(eip));
963 if (!s->dflag) {
964 /* reset high bits of EIP */
965 gen_movw_addr_im(s, CPU_FIELD_OFFSET(eip) + 2, 0);
966 }
967 gen_eob(s);
968 goto no_copy;
969 case 0xca: /* lret im */
970 case 0xcb: /* lret */
971 case 0xcf: /* iret */
972 case 0x9a: /* lcall im */
973 case 0xea: /* ljmp im */
974 goto unsupported_op;
975
976 case 0xe8: /* call im */
977 ot = dflag ? OT_LONG : OT_WORD;
978 val = insn_get(s, ot);
979 next_eip = s->pc - s->cs_base;
980 val += next_eip;
981 if (s->dflag) {
982 gb(s, 0x68); /* pushl imm */
983 gl(s, next_eip);
984 } else {
985 gb(s, 0x66); /* pushw imm */
986 gb(s, 0x68);
987 gw(s, next_eip);
988 val &= 0xffff;
989 }
990 gen_jmp(s, val);
991 goto no_copy;
992 case 0xe9: /* jmp */
993 ot = dflag ? OT_LONG : OT_WORD;
994 val = insn_get(s, ot);
995 val += s->pc - s->cs_base;
996 if (s->dflag == 0)
997 val = val & 0xffff;
998 gen_jmp(s, val);
999 goto no_copy;
1000 case 0xeb: /* jmp Jb */
1001 val = (int8_t)insn_get(s, OT_BYTE);
1002 val += s->pc - s->cs_base;
1003 if (s->dflag == 0)
1004 val = val & 0xffff;
1005 gen_jmp(s, val);
1006 goto no_copy;
1007 case 0x70 ... 0x7f: /* jcc Jb */
1008 val = (int8_t)insn_get(s, OT_BYTE);
1009 goto do_jcc;
1010 case 0x180 ... 0x18f: /* jcc Jv */
1011 if (dflag) {
1012 val = insn_get(s, OT_LONG);
1013 } else {
5fafdf24 1014 val = (int16_t)insn_get(s, OT_WORD);
58fe2f10
FB
1015 }
1016 do_jcc:
1017 next_eip = s->pc - s->cs_base;
1018 val += next_eip;
1019 if (s->dflag == 0)
1020 val &= 0xffff;
1021 gen_jcc(s, b & 0xf, val, next_eip);
1022 goto no_copy;
1023
1024 /************************/
1025 /* flags */
1026 case 0x9c: /* pushf */
1027 /* XXX: put specific code ? */
1028 goto unsupported_op;
1029 case 0x9d: /* popf */
1030 goto unsupported_op;
1031
1032 case 0x9e: /* sahf */
1033 case 0x9f: /* lahf */
1034 case 0xf5: /* cmc */
1035 case 0xf8: /* clc */
1036 case 0xf9: /* stc */
1037 case 0xfc: /* cld */
1038 case 0xfd: /* std */
1039 break;
1040
1041 /************************/
1042 /* bit operations */
1043 case 0x1ba: /* bt/bts/btr/btc Gv, im */
1044 ot = dflag ? OT_LONG : OT_WORD;
1045 modrm = ldub_code(s->pc++);
1046 op = (modrm >> 3) & 7;
1047 parse_modrm(s, modrm);
1048 /* load shift */
1049 ldub_code(s->pc++);
1050 if (op < 4)
1051 goto illegal_op;
1052 break;
1053 /************************/
1054 /* bcd */
1055 case 0x27: /* daa */
1056 break;
1057 case 0x2f: /* das */
1058 break;
1059 case 0x37: /* aaa */
1060 break;
1061 case 0x3f: /* aas */
1062 break;
1063 case 0xd4: /* aam */
1064 ldub_code(s->pc++);
1065 break;
1066 case 0xd5: /* aad */
1067 ldub_code(s->pc++);
1068 break;
1069 /************************/
1070 /* misc */
1071 case 0x90: /* nop */
1072 break;
1073 case 0x9b: /* fwait */
5fafdf24 1074 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
42c3c0cc
FB
1075 (HF_MP_MASK | HF_TS_MASK)) {
1076 goto unsupported_op;
1077 }
58fe2f10
FB
1078 break;
1079 case 0xcc: /* int3 */
1080 goto unsupported_op;
1081 case 0xcd: /* int N */
1082 goto unsupported_op;
1083 case 0xce: /* into */
1084 goto unsupported_op;
1085 case 0xf1: /* icebp (undocumented, exits to external debugger) */
1086 goto unsupported_op;
1087 case 0xfa: /* cli */
1088 goto unsupported_op;
1089 case 0xfb: /* sti */
1090 goto unsupported_op;
1091 case 0x62: /* bound */
1092 modrm = ldub_code(s->pc++);
1093 mod = (modrm >> 6) & 3;
1094 if (mod == 3)
1095 goto illegal_op;
1096 parse_modrm(s, modrm);
1097 break;
1098 case 0x1c8 ... 0x1cf: /* bswap reg */
1099 break;
1100 case 0xd6: /* salc */
1101 break;
1102 case 0xe0: /* loopnz */
1103 case 0xe1: /* loopz */
1104 case 0xe2: /* loop */
1105 case 0xe3: /* jecxz */
1106 goto unsupported_op;
1107
1108 case 0x130: /* wrmsr */
1109 case 0x132: /* rdmsr */
1110 goto unsupported_op;
1111 case 0x131: /* rdtsc */
1112 goto unsupported_op;
1113 case 0x1a2: /* cpuid */
1114 goto unsupported_op;
1115 case 0xf4: /* hlt */
1116 goto unsupported_op;
1117 case 0x100:
1118 goto unsupported_op;
1119 case 0x101:
1120 goto unsupported_op;
1121 case 0x108: /* invd */
1122 case 0x109: /* wbinvd */
1123 goto unsupported_op;
1124 case 0x63: /* arpl */
1125 goto unsupported_op;
1126 case 0x102: /* lar */
1127 case 0x103: /* lsl */
1128 goto unsupported_op;
1129 case 0x118:
1130 goto unsupported_op;
1131 case 0x120: /* mov reg, crN */
1132 case 0x122: /* mov crN, reg */
1133 goto unsupported_op;
1134 case 0x121: /* mov reg, drN */
1135 case 0x123: /* mov drN, reg */
1136 goto unsupported_op;
1137 case 0x106: /* clts */
1138 goto unsupported_op;
1139 default:
1140 goto illegal_op;
1141 }
1142
1143 /* just copy the code */
1144
1145 /* no override yet */
1146 if (!s->dflag)
1147 gb(s, 0x66);
1148 if (!s->aflag)
1149 gb(s, 0x67);
1150 if (prefixes & PREFIX_REPZ)
1151 gb(s, 0xf3);
1152 else if (prefixes & PREFIX_REPNZ)
1153 gb(s, 0xf2);
1154 {
1155 int len, i;
1156 len = s->pc - pc_start_insn;
1157 for(i = 0; i < len; i++) {
1158 *s->gen_code_ptr++ = ldub_code(pc_start_insn + i);
1159 }
1160 }
1161 no_copy:
1162 return 0;
1163 illegal_op:
1164 unsupported_op:
1165 /* fall back to slower code gen necessary */
1166 s->pc = pc_start;
1167 return -1;
1168}
1169
1170#define GEN_CODE_MAX_SIZE 8192
1171#define GEN_CODE_MAX_INSN_SIZE 512
1172
1173static inline int gen_intermediate_code_internal(CPUState *env,
5fafdf24 1174 TranslationBlock *tb,
58fe2f10
FB
1175 uint8_t *gen_code_ptr,
1176 int *gen_code_size_ptr,
1177 int search_pc,
1178 uint8_t *tc_ptr)
1179{
1180 DisasContext dc1, *dc = &dc1;
14ce26e7
FB
1181 target_ulong pc_insn, pc_start, cs_base;
1182 uint8_t *gen_code_end;
58fe2f10 1183 int flags, ret;
58fe2f10
FB
1184
1185 if (env->nb_breakpoints > 0 ||
1186 env->singlestep_enabled)
1187 return -1;
1188 flags = tb->flags;
5fafdf24 1189 if (flags & (HF_TF_MASK | HF_ADDSEG_MASK |
58fe2f10
FB
1190 HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK))
1191 return -1;
1192 if (!(flags & HF_SS32_MASK))
1193 return -1;
d720b93d
FB
1194 if (tb->cflags & CF_SINGLE_INSN)
1195 return -1;
5fafdf24 1196 gen_code_end = gen_code_ptr +
58fe2f10
FB
1197 GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE;
1198 dc->gen_code_ptr = gen_code_ptr;
1199 dc->gen_code_start = gen_code_ptr;
1200
1201 /* generate intermediate code */
14ce26e7
FB
1202 pc_start = tb->pc;
1203 cs_base = tb->cs_base;
58fe2f10
FB
1204 dc->pc = pc_start;
1205 dc->cs_base = cs_base;
1206 dc->pe = (flags >> HF_PE_SHIFT) & 1;
1207 dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
1208 dc->f_st = 0;
1209 dc->vm86 = (flags >> VM_SHIFT) & 1;
1210 dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
1211 dc->iopl = (flags >> IOPL_SHIFT) & 3;
1212 dc->tb = tb;
42c3c0cc
FB
1213 dc->flags = flags;
1214
58fe2f10
FB
1215 dc->is_jmp = 0;
1216
1217 for(;;) {
1218 pc_insn = dc->pc;
1219 ret = disas_insn(dc);
1220 if (ret < 0) {
1221 /* unsupported insn */
1222 if (dc->pc == pc_start) {
1223 /* if first instruction, signal that no copying was done */
1224 return -1;
1225 } else {
1226 gen_jmp(dc, dc->pc - dc->cs_base);
1227 dc->is_jmp = 1;
1228 }
1229 }
1230 if (search_pc) {
1231 /* search pc mode */
1232 if (tc_ptr < dc->gen_code_ptr) {
1233 env->eip = pc_insn - cs_base;
1234 return 0;
1235 }
1236 }
1237 /* stop translation if indicated */
1238 if (dc->is_jmp)
1239 break;
1240 /* if too long translation, stop generation */
1241 if (dc->gen_code_ptr >= gen_code_end ||
1242 (dc->pc - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
1243 gen_jmp(dc, dc->pc - dc->cs_base);
1244 break;
1245 }
1246 }
5fafdf24 1247
58fe2f10 1248#ifdef DEBUG_DISAS
e19e89a5 1249 if (loglevel & CPU_LOG_TB_IN_ASM) {
58fe2f10 1250 fprintf(logfile, "----------------\n");
5fafdf24 1251 fprintf(logfile, "IN: COPY: %s fpu=%d\n",
42c3c0cc
FB
1252 lookup_symbol(pc_start),
1253 tb->cflags & CF_TB_FP_USED ? 1 : 0);
14ce26e7 1254 target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32);
58fe2f10
FB
1255 fprintf(logfile, "\n");
1256 }
1257#endif
1258
1259 if (!search_pc) {
1260 *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start;
1261 tb->size = dc->pc - pc_start;
42c3c0cc 1262 tb->cflags |= CF_CODE_COPY;
58fe2f10
FB
1263 return 0;
1264 } else {
1265 return -1;
1266 }
1267}
1268
1269/* generate code by just copying data. Return -1 if cannot generate
1270 any code. Return 0 if code was generated */
1271int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb,
1272 int max_code_size, int *gen_code_size_ptr)
1273{
1274 /* generate machine code */
1275 tb->tb_next_offset[0] = 0xffff;
1276 tb->tb_next_offset[1] = 0xffff;
1277#ifdef USE_DIRECT_JUMP
1278 /* the following two entries are optional (only used for string ops) */
1279 tb->tb_jmp_offset[2] = 0xffff;
1280 tb->tb_jmp_offset[3] = 0xffff;
1281#endif
5fafdf24 1282 return gen_intermediate_code_internal(env, tb,
58fe2f10
FB
1283 tb->tc_ptr, gen_code_size_ptr,
1284 0, NULL);
1285}
1286
1287static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE];
1288
5fafdf24 1289int cpu_restore_state_copy(TranslationBlock *tb,
58fe2f10
FB
1290 CPUState *env, unsigned long searched_pc,
1291 void *puc)
1292{
1293 struct ucontext *uc = puc;
1294 int ret, eflags;
1295
1296 /* find opc index corresponding to search_pc */
1297 if (searched_pc < (unsigned long)tb->tc_ptr)
1298 return -1;
1299 searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf;
5fafdf24 1300 ret = gen_intermediate_code_internal(env, tb,
58fe2f10
FB
1301 dummy_gen_code_buf, NULL,
1302 1, (uint8_t *)searched_pc);
1303 if (ret < 0)
1304 return ret;
1305 /* restore all the CPU state from the CPU context from the
42c3c0cc 1306 signal. The FPU context stays in the host CPU. */
5fafdf24 1307
58fe2f10
FB
1308 env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX];
1309 env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX];
1310 env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX];
1311 env->regs[R_EBX] = uc->uc_mcontext.gregs[REG_EBX];
1312 env->regs[R_ESP] = uc->uc_mcontext.gregs[REG_ESP];
1313 env->regs[R_EBP] = uc->uc_mcontext.gregs[REG_EBP];
1314 env->regs[R_ESI] = uc->uc_mcontext.gregs[REG_ESI];
1315 env->regs[R_EDI] = uc->uc_mcontext.gregs[REG_EDI];
1316 eflags = uc->uc_mcontext.gregs[REG_EFL];
1317 env->df = 1 - (2 * ((eflags >> 10) & 1));
1318 env->cc_src = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1319 env->cc_op = CC_OP_EFLAGS;
1320 return 0;
1321}
42c3c0cc
FB
1322
1323#endif /* USE_CODE_COPY */