Replace tabs by 8 spaces. No code change, by Herve Poussineau.
[qemu/dscho.git] / target-i386 / translate-copy.c
blobcf8bd5ab3f7ba97d97cf69dc2eca8133a8c14c59
1 /*
2 * i386 on i386 translation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
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.
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.
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
20 #include "config.h"
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <inttypes.h>
27 #include <assert.h>
29 #include "cpu.h"
30 #include "exec-all.h"
31 #include "disas.h"
33 #ifdef USE_CODE_COPY
35 #include <signal.h>
36 #include <sys/mman.h>
37 #include <sys/ucontext.h>
39 extern char exec_loop;
41 /* operand size */
42 enum {
43 OT_BYTE = 0,
44 OT_WORD,
45 OT_LONG,
46 OT_QUAD,
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
55 typedef struct DisasContext {
56 /* current insn context */
57 int override; /* -1 if no override */
58 int prefix;
59 int aflag, dflag;
60 target_ulong pc; /* pc = eip + cs_base */
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;
67 /* current block context */
68 target_ulong cs_base; /* base of CS segment */
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;
75 int flags;
76 struct TranslationBlock *tb;
77 } DisasContext;
79 #define CPU_FIELD_OFFSET(field) offsetof(CPUState, field)
81 #define CPU_SEG 0x64 /* fs override */
83 static inline void gb(DisasContext *s, uint32_t val)
85 *s->gen_code_ptr++ = val;
88 static inline void gw(DisasContext *s, uint32_t val)
90 *s->gen_code_ptr++ = val;
91 *s->gen_code_ptr++ = val >> 8;
94 static inline void gl(DisasContext *s, uint32_t val)
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;
102 static inline void gjmp(DisasContext *s, long val)
104 gb(s, 0xe9); /* jmp */
105 gl(s, val - (long)(s->gen_code_ptr + 4));
108 static inline void gen_movl_addr_im(DisasContext *s,
109 uint32_t addr, uint32_t val)
111 gb(s, CPU_SEG); /* seg movl im, addr */
112 gb(s, 0xc7);
113 gb(s, 0x05);
114 gl(s, addr);
115 gl(s, val);
118 static inline void gen_movw_addr_im(DisasContext *s,
119 uint32_t addr, uint32_t val)
121 gb(s, CPU_SEG); /* seg movl im, addr */
122 gb(s, 0x66);
123 gb(s, 0xc7);
124 gb(s, 0x05);
125 gl(s, addr);
126 gw(s, val);
130 static void gen_jmp(DisasContext *s, uint32_t target_eip)
132 TranslationBlock *tb = s->tb;
134 gb(s, 0xe9); /* jmp */
135 tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
136 gl(s, 0);
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);
143 s->is_jmp = 1;
146 static void gen_jcc(DisasContext *s, int op,
147 uint32_t target_eip, uint32_t next_eip)
149 TranslationBlock *tb = s->tb;
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);
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);
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);
169 s->is_jmp = 1;
172 static void gen_eob(DisasContext *s)
174 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0);
175 gjmp(s, (long)&exec_loop);
177 s->is_jmp = 1;
180 static inline void gen_lea_modrm(DisasContext *s, int modrm)
182 int havesib;
183 int base, disp;
184 int index;
185 int scale;
186 int mod, rm, code;
188 mod = (modrm >> 6) & 3;
189 rm = modrm & 7;
191 if (s->aflag) {
193 havesib = 0;
194 base = rm;
195 index = 0;
196 scale = 0;
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;
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;
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;
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;
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;
248 static inline void parse_modrm(DisasContext *s, int modrm)
250 if ((modrm & 0xc0) != 0xc0)
251 gen_lea_modrm(s, modrm);
254 static inline uint32_t insn_get(DisasContext *s, int ot)
256 uint32_t ret;
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;
273 return ret;
276 /* convert one instruction. s->is_jmp is set if the translation must
277 be stopped. */
278 static int disas_insn(DisasContext *s)
280 target_ulong pc_start, pc_tmp, pc_start_insn;
281 int b, prefixes, aflag, dflag, next_eip, val;
282 int ot;
283 int modrm, mod, op, rm;
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;
330 if (prefixes & PREFIX_DATA)
331 dflag ^= 1;
332 if (prefixes & PREFIX_ADR)
333 aflag ^= 1;
335 s->prefix = prefixes;
336 s->aflag = aflag;
337 s->dflag = dflag;
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;
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;
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:
366 int f;
367 f = (b >> 1) & 3;
369 if ((b & 1) == 0)
370 ot = OT_BYTE;
371 else
372 ot = dflag ? OT_LONG : OT_WORD;
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;
388 break;
390 case 0x80: /* GRP1 */
391 case 0x81:
392 case 0x82:
393 case 0x83:
395 if ((b & 1) == 0)
396 ot = OT_BYTE;
397 else
398 ot = dflag ? OT_LONG : OT_WORD;
400 modrm = ldub_code(s->pc++);
401 parse_modrm(s, modrm);
403 switch(b) {
404 default:
405 case 0x80:
406 case 0x81:
407 case 0x82:
408 insn_get(s, ot);
409 break;
410 case 0x83:
411 insn_get(s, OT_BYTE);
412 break;
415 break;
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;
430 modrm = ldub_code(s->pc++);
431 op = (modrm >> 3) & 7;
432 parse_modrm(s, modrm);
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;
453 break;
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;
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;
468 pc_tmp = s->pc;
469 parse_modrm(s, modrm);
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
478 fs movl %eax, regs[0]
479 movl Ev, %eax
480 pushl next_eip
481 fs movl %eax, eip
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
488 fs movl %eax, regs[0]
489 movl Ev, %eax
490 fs movl %eax, eip
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;
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;
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 {
526 break;
528 case 0x84: /* test Ev, Gv */
529 case 0x85:
531 case 0x1c0:
532 case 0x1c1: /* xadd Ev, Gv */
534 case 0x1b0:
535 case 0x1b1: /* cmpxchg Ev, Gv */
537 case 0x8f: /* pop Ev */
539 case 0x88:
540 case 0x89: /* mov Gv, Ev */
542 case 0x8a:
543 case 0x8b: /* mov Ev, Gv */
545 case 0x1b6: /* movzbS Gv, Eb */
546 case 0x1b7: /* movzwS Gv, Eb */
547 case 0x1be: /* movsbS Gv, Eb */
548 case 0x1bf: /* movswS Gv, Eb */
550 case 0x86:
551 case 0x87: /* xchg Ev, Gv */
553 case 0xd0:
554 case 0xd1: /* shift Ev,1 */
556 case 0xd2:
557 case 0xd3: /* shift Ev,cl */
559 case 0x1a5: /* shld cl */
560 case 0x1ad: /* shrd cl */
562 case 0x190 ... 0x19f: /* setcc Gv */
564 /* XXX: emulate cmov if not available ? */
565 case 0x140 ... 0x14f: /* cmov Gv, Ev */
567 case 0x1a3: /* bt Gv, Ev */
568 case 0x1ab: /* bts */
569 case 0x1b3: /* btr */
570 case 0x1bb: /* btc */
572 case 0x1bc: /* bsf */
573 case 0x1bd: /* bsr */
575 modrm = ldub_code(s->pc++);
576 parse_modrm(s, modrm);
577 break;
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;
587 /**************************/
588 /* push/pop */
589 case 0x50 ... 0x57: /* push */
590 case 0x58 ... 0x5f: /* pop */
591 case 0x60: /* pusha */
592 case 0x61: /* popa */
593 break;
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;
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
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
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;
655 /************************/
656 /* floats */
657 case 0xd8 ... 0xdf:
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 */
668 static int count;
669 count = (count + 1) % 3;
670 if (count != 0)
671 goto unsupported_op;
673 #endif
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 */
680 parse_modrm(s, modrm);
681 switch(op) {
682 case 0x00 ... 0x07: /* fxxxs */
683 case 0x10 ... 0x17: /* fixxxl */
684 case 0x20 ... 0x27: /* fxxxl */
685 case 0x30 ... 0x37: /* fixxx */
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 */
699 case 0x0c: /* fldenv mem */
700 case 0x0d: /* fldcw mem */
701 case 0x0e: /* fnstenv mem */
702 case 0x0f: /* fnstcw mem */
703 case 0x1d: /* fldt mem */
704 case 0x1f: /* fstpt mem */
705 case 0x2c: /* frstor mem */
706 case 0x2e: /* fnsave mem */
707 case 0x2f: /* fnstsw mem */
708 case 0x3c: /* fbld */
709 case 0x3e: /* fbstp */
710 case 0x3d: /* fildll */
711 case 0x3f: /* fistpll */
712 break;
713 default:
714 goto illegal_op;
716 } else {
717 /* register float ops */
718 switch(op) {
719 case 0x08: /* fld sti */
720 case 0x09: /* fxchg sti */
721 break;
722 case 0x0a: /* grp d9/2 */
723 switch(rm) {
724 case 0: /* fnop */
725 break;
726 default:
727 goto illegal_op;
729 break;
730 case 0x0c: /* grp d9/4 */
731 switch(rm) {
732 case 0: /* fchs */
733 case 1: /* fabs */
734 case 4: /* ftst */
735 case 5: /* fxam */
736 break;
737 default:
738 goto illegal_op;
740 break;
741 case 0x0d: /* grp d9/5 */
742 switch(rm) {
743 case 0:
744 case 1:
745 case 2:
746 case 3:
747 case 4:
748 case 5:
749 case 6:
750 break;
751 default:
752 goto illegal_op;
754 break;
755 case 0x0e: /* grp d9/6 */
756 break;
757 case 0x0f: /* grp d9/7 */
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 */
762 break;
763 case 0x02: /* fcom */
764 break;
765 case 0x03: /* fcomp */
766 break;
767 case 0x15: /* da/5 */
768 switch(rm) {
769 case 1: /* fucompp */
770 break;
771 default:
772 goto illegal_op;
774 break;
775 case 0x1c:
776 switch(rm) {
777 case 0: /* feni (287 only, just do nop here) */
778 case 1: /* fdisi (287 only, just do nop here) */
779 goto unsupported_op;
780 case 2: /* fclex */
781 case 3: /* fninit */
782 case 4: /* fsetpm (287 only, just do nop here) */
783 break;
784 default:
785 goto illegal_op;
787 break;
788 case 0x1d: /* fucomi */
789 break;
790 case 0x1e: /* fcomi */
791 break;
792 case 0x28: /* ffree sti */
793 break;
794 case 0x2a: /* fst sti */
795 break;
796 case 0x2b: /* fstp sti */
797 break;
798 case 0x2c: /* fucom st(i) */
799 break;
800 case 0x2d: /* fucomp st(i) */
801 break;
802 case 0x33: /* de/3 */
803 switch(rm) {
804 case 1: /* fcompp */
805 break;
806 default:
807 goto illegal_op;
809 break;
810 case 0x3c: /* df/4 */
811 switch(rm) {
812 case 0:
813 break;
814 default:
815 goto illegal_op;
817 break;
818 case 0x3d: /* fucomip */
819 break;
820 case 0x3e: /* fcomip */
821 break;
822 case 0x10 ... 0x13: /* fcmovxx */
823 case 0x18 ... 0x1b:
824 break;
825 default:
826 goto illegal_op;
829 s->tb->cflags |= CF_TB_FP_USED;
830 break;
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;
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;
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;
877 case 0x91 ... 0x97: /* xchg R, EAX */
878 break;
880 /************************/
881 /* shifts */
882 case 0xc0:
883 case 0xc1: /* shift Ev,imm */
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;
892 /************************/
893 /* string ops */
895 case 0xa4: /* movsS */
896 case 0xa5:
897 break;
899 case 0xaa: /* stosS */
900 case 0xab:
901 break;
903 case 0xac: /* lodsS */
904 case 0xad:
905 break;
907 case 0xae: /* scasS */
908 case 0xaf:
909 break;
911 case 0xa6: /* cmpsS */
912 case 0xa7:
913 break;
915 case 0x6c: /* insS */
916 case 0x6d:
917 goto unsupported_op;
919 case 0x6e: /* outsS */
920 case 0x6f:
921 goto unsupported_op;
923 /************************/
924 /* port I/O */
925 case 0xe4:
926 case 0xe5:
927 goto unsupported_op;
929 case 0xe6:
930 case 0xe7:
931 goto unsupported_op;
933 case 0xec:
934 case 0xed:
935 goto unsupported_op;
937 case 0xee:
938 case 0xef:
939 goto unsupported_op;
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
956 case 0xc3: /* ret */
957 gb(s, CPU_SEG);
958 if (!s->dflag)
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);
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;
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;
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 {
1014 val = (int16_t)insn_get(s, OT_WORD);
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;
1024 /************************/
1025 /* flags */
1026 case 0x9c: /* pushf */
1027 /* XXX: put specific code ? */
1028 goto unsupported_op;
1029 case 0x9d: /* popf */
1030 goto unsupported_op;
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;
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 */
1074 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
1075 (HF_MP_MASK | HF_TS_MASK)) {
1076 goto unsupported_op;
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;
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;
1143 /* just copy the code */
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);
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);
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;
1170 #define GEN_CODE_MAX_SIZE 8192
1171 #define GEN_CODE_MAX_INSN_SIZE 512
1173 static inline int gen_intermediate_code_internal(CPUState *env,
1174 TranslationBlock *tb,
1175 uint8_t *gen_code_ptr,
1176 int *gen_code_size_ptr,
1177 int search_pc,
1178 uint8_t *tc_ptr)
1180 DisasContext dc1, *dc = &dc1;
1181 target_ulong pc_insn, pc_start, cs_base;
1182 uint8_t *gen_code_end;
1183 int flags, ret;
1185 if (env->nb_breakpoints > 0 ||
1186 env->singlestep_enabled)
1187 return -1;
1188 flags = tb->flags;
1189 if (flags & (HF_TF_MASK | HF_ADDSEG_MASK |
1190 HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK))
1191 return -1;
1192 if (!(flags & HF_SS32_MASK))
1193 return -1;
1194 if (tb->cflags & CF_SINGLE_INSN)
1195 return -1;
1196 gen_code_end = gen_code_ptr +
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;
1201 /* generate intermediate code */
1202 pc_start = tb->pc;
1203 cs_base = tb->cs_base;
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;
1213 dc->flags = flags;
1215 dc->is_jmp = 0;
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;
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;
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;
1248 #ifdef DEBUG_DISAS
1249 if (loglevel & CPU_LOG_TB_IN_ASM) {
1250 fprintf(logfile, "----------------\n");
1251 fprintf(logfile, "IN: COPY: %s fpu=%d\n",
1252 lookup_symbol(pc_start),
1253 tb->cflags & CF_TB_FP_USED ? 1 : 0);
1254 target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32);
1255 fprintf(logfile, "\n");
1257 #endif
1259 if (!search_pc) {
1260 *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start;
1261 tb->size = dc->pc - pc_start;
1262 tb->cflags |= CF_CODE_COPY;
1263 return 0;
1264 } else {
1265 return -1;
1269 /* generate code by just copying data. Return -1 if cannot generate
1270 any code. Return 0 if code was generated */
1271 int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb,
1272 int max_code_size, int *gen_code_size_ptr)
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
1282 return gen_intermediate_code_internal(env, tb,
1283 tb->tc_ptr, gen_code_size_ptr,
1284 0, NULL);
1287 static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE];
1289 int cpu_restore_state_copy(TranslationBlock *tb,
1290 CPUState *env, unsigned long searched_pc,
1291 void *puc)
1293 struct ucontext *uc = puc;
1294 int ret, eflags;
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;
1300 ret = gen_intermediate_code_internal(env, tb,
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
1306 signal. The FPU context stays in the host CPU. */
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;
1323 #endif /* USE_CODE_COPY */