0.6.2-alt1.1
[qemu] / qemu-snapshot-2004-11-28_23 / target-i386 / translate-copy.c
1 /*
2  *  i386 on i386 translation
3  * 
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  */
20 #include "config.h"
21
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <inttypes.h>
27 #include <assert.h>
28
29 #include "cpu.h"
30 #include "exec-all.h"
31 #include "disas.h"
32
33 #ifdef USE_CODE_COPY
34
35 #include <signal.h>
36 #include <sys/mman.h>
37 #include <sys/ucontext.h>
38
39 extern char exec_loop;
40
41 /* operand size */
42 enum {
43     OT_BYTE = 0,
44     OT_WORD,
45     OT_LONG, 
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
55 typedef struct DisasContext {
56     /* current insn context */
57     int override; /* -1 if no override */
58     int prefix;
59     int aflag, dflag;
60     uint8_t *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;
66     
67     /* current block context */
68     uint8_t *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;
78
79 #define CPU_FIELD_OFFSET(field) offsetof(CPUState, field)
80
81 #define CPU_SEG 0x64 /* fs override */
82
83 static inline void gb(DisasContext *s, uint32_t val)
84 {
85     *s->gen_code_ptr++ = val;
86 }
87
88 static inline void gw(DisasContext *s, uint32_t val)
89 {
90     *s->gen_code_ptr++ = val;
91     *s->gen_code_ptr++ = val >> 8;
92 }
93
94 static 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
102 static 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
108 static inline void gen_movl_addr_im(DisasContext *s, 
109                                     uint32_t addr, uint32_t val)
110 {
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);
116 }
117
118 static inline void gen_movw_addr_im(DisasContext *s, 
119                                     uint32_t addr, uint32_t val)
120 {
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);
127 }
128
129
130 static 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
146 static 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);
158     
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
172 static 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
180 static 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;
197         
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         }
225         
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
248 static inline void parse_modrm(DisasContext *s, int modrm)
249 {
250     if ((modrm & 0xc0) != 0xc0)
251         gen_lea_modrm(s, modrm);        
252 }
253
254 static 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.  */
278 static int disas_insn(DisasContext *s)
279 {
280     uint8_t *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;
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;
354         
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;
373             
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:
392     case 0x82:
393     case 0x83:
394         {
395             if ((b & 1) == 0)
396                 ot = OT_BYTE;
397             else
398                 ot = dflag ? OT_LONG : OT_WORD;
399             
400             modrm = ldub_code(s->pc++);
401             parse_modrm(s, modrm);
402
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;
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
478                fs movl %eax, regs[0] 
479                movl Ev, %eax 
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
488                fs movl %eax, regs[0] 
489                movl Ev, %eax 
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;
509         
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 */
529     case 0x85: 
530         
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;
586         
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;
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 */
667         {
668             static int count;
669             count = (count + 1) % 3;
670             if (count != 0)
671                 goto unsupported_op;
672         }
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;
715             }
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;
728                 }
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;
739                 }
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;
753                 }
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;
773                 }
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;
786                 }
787                 break;
788             case 0x1d: /* fucomi */
789                 break;
790             case 0x1e: /* fcomi */
791                 break;
792             case 0x2a: /* fst sti */
793                 break;
794             case 0x2b: /* fstp sti */
795                 break;
796             case 0x2c: /* fucom st(i) */
797                 break;
798             case 0x2d: /* fucomp st(i) */
799                 break;
800             case 0x33: /* de/3 */
801                 switch(rm) {
802                 case 1: /* fcompp */
803                     break;
804                 default:
805                     goto illegal_op;
806                 }
807                 break;
808             case 0x3c: /* df/4 */
809                 switch(rm) {
810                 case 0:
811                     break;
812                 default:
813                     goto illegal_op;
814                 }
815                 break;
816             case 0x3d: /* fucomip */
817                 break;
818             case 0x3e: /* fcomip */
819                 break;
820             case 0x10 ... 0x13: /* fcmovxx */
821             case 0x18 ... 0x1b:
822                 break;
823             default:
824                 goto illegal_op;
825             }
826         }
827         s->tb->cflags |= CF_TB_FP_USED;
828         break;
829
830         /**************************/
831         /* mov */
832     case 0xc6:
833     case 0xc7: /* mov Ev, Iv */
834         if ((b & 1) == 0)
835             ot = OT_BYTE;
836         else
837             ot = dflag ? OT_LONG : OT_WORD;
838         modrm = ldub_code(s->pc++);
839         parse_modrm(s, modrm);
840         insn_get(s, ot);
841         break;
842
843     case 0x8d: /* lea */
844         ot = dflag ? OT_LONG : OT_WORD;
845         modrm = ldub_code(s->pc++);
846         mod = (modrm >> 6) & 3;
847         if (mod == 3)
848             goto illegal_op;
849         parse_modrm(s, modrm);
850         break;
851         
852     case 0xa0: /* mov EAX, Ov */
853     case 0xa1:
854     case 0xa2: /* mov Ov, EAX */
855     case 0xa3:
856         if ((b & 1) == 0)
857             ot = OT_BYTE;
858         else
859             ot = dflag ? OT_LONG : OT_WORD;
860         if (s->aflag)
861             insn_get(s, OT_LONG);
862         else
863             insn_get(s, OT_WORD);
864         break;
865     case 0xd7: /* xlat */
866         break;
867     case 0xb0 ... 0xb7: /* mov R, Ib */
868         insn_get(s, OT_BYTE);
869         break;
870     case 0xb8 ... 0xbf: /* mov R, Iv */
871         ot = dflag ? OT_LONG : OT_WORD;
872         insn_get(s, ot);
873         break;
874
875     case 0x91 ... 0x97: /* xchg R, EAX */
876         break;
877
878         /************************/
879         /* shifts */
880     case 0xc0:
881     case 0xc1: /* shift Ev,imm */
882
883     case 0x1a4: /* shld imm */
884     case 0x1ac: /* shrd imm */
885         modrm = ldub_code(s->pc++);
886         parse_modrm(s, modrm);
887         ldub_code(s->pc++);
888         break;
889         
890         /************************/
891         /* string ops */
892
893     case 0xa4: /* movsS */
894     case 0xa5:
895         break;
896         
897     case 0xaa: /* stosS */
898     case 0xab:
899         break;
900
901     case 0xac: /* lodsS */
902     case 0xad:
903         break;
904
905     case 0xae: /* scasS */
906     case 0xaf:
907         break;
908
909     case 0xa6: /* cmpsS */
910     case 0xa7:
911         break;
912
913     case 0x6c: /* insS */
914     case 0x6d:
915         goto unsupported_op;
916
917     case 0x6e: /* outsS */
918     case 0x6f:
919         goto unsupported_op;
920
921         /************************/
922         /* port I/O */
923     case 0xe4:
924     case 0xe5:
925         goto unsupported_op;
926
927     case 0xe6:
928     case 0xe7:
929         goto unsupported_op;
930
931     case 0xec:
932     case 0xed:
933         goto unsupported_op;
934
935     case 0xee:
936     case 0xef:
937         goto unsupported_op;
938
939         /************************/
940         /* control */
941 #if 0
942     case 0xc2: /* ret im */
943         val = ldsw_code(s->pc);
944         s->pc += 2;
945         gen_pop_T0(s);
946         gen_stack_update(s, val + (2 << s->dflag));
947         if (s->dflag == 0)
948             gen_op_andl_T0_ffff();
949         gen_op_jmp_T0();
950         gen_eob(s);
951         break;
952 #endif
953
954     case 0xc3: /* ret */
955         gb(s, CPU_SEG);
956         if (!s->dflag)  
957             gb(s, 0x66); /* d16 */
958         gb(s, 0x8f); /* pop addr */
959         gb(s, 0x05);
960         gl(s, CPU_FIELD_OFFSET(eip));
961         if (!s->dflag) {
962             /* reset high bits of EIP */
963             gen_movw_addr_im(s, CPU_FIELD_OFFSET(eip) + 2, 0);
964         }
965         gen_eob(s);
966         goto no_copy;
967     case 0xca: /* lret im */
968     case 0xcb: /* lret */
969     case 0xcf: /* iret */
970     case 0x9a: /* lcall im */
971     case 0xea: /* ljmp im */
972         goto unsupported_op;
973
974     case 0xe8: /* call im */
975         ot = dflag ? OT_LONG : OT_WORD;
976         val = insn_get(s, ot);
977         next_eip = s->pc - s->cs_base;
978         val += next_eip;
979         if (s->dflag) {
980             gb(s, 0x68); /* pushl imm */
981             gl(s, next_eip);
982         } else {
983             gb(s, 0x66); /* pushw imm */
984             gb(s, 0x68);
985             gw(s, next_eip);
986             val &= 0xffff;
987         }
988         gen_jmp(s, val);
989         goto no_copy;
990     case 0xe9: /* jmp */
991         ot = dflag ? OT_LONG : OT_WORD;
992         val = insn_get(s, ot);
993         val += s->pc - s->cs_base;
994         if (s->dflag == 0)
995             val = val & 0xffff;
996         gen_jmp(s, val);
997         goto no_copy;
998     case 0xeb: /* jmp Jb */
999         val = (int8_t)insn_get(s, OT_BYTE);
1000         val += s->pc - s->cs_base;
1001         if (s->dflag == 0)
1002             val = val & 0xffff;
1003         gen_jmp(s, val);
1004         goto no_copy;
1005     case 0x70 ... 0x7f: /* jcc Jb */
1006         val = (int8_t)insn_get(s, OT_BYTE);
1007         goto do_jcc;
1008     case 0x180 ... 0x18f: /* jcc Jv */
1009         if (dflag) {
1010             val = insn_get(s, OT_LONG);
1011         } else {
1012             val = (int16_t)insn_get(s, OT_WORD); 
1013         }
1014     do_jcc:
1015         next_eip = s->pc - s->cs_base;
1016         val += next_eip;
1017         if (s->dflag == 0)
1018             val &= 0xffff;
1019         gen_jcc(s, b & 0xf, val, next_eip);
1020         goto no_copy;
1021
1022         /************************/
1023         /* flags */
1024     case 0x9c: /* pushf */
1025         /* XXX: put specific code ? */
1026         goto unsupported_op;
1027     case 0x9d: /* popf */
1028         goto unsupported_op;
1029
1030     case 0x9e: /* sahf */
1031     case 0x9f: /* lahf */
1032     case 0xf5: /* cmc */
1033     case 0xf8: /* clc */
1034     case 0xf9: /* stc */
1035     case 0xfc: /* cld */
1036     case 0xfd: /* std */
1037         break;
1038
1039         /************************/
1040         /* bit operations */
1041     case 0x1ba: /* bt/bts/btr/btc Gv, im */
1042         ot = dflag ? OT_LONG : OT_WORD;
1043         modrm = ldub_code(s->pc++);
1044         op = (modrm >> 3) & 7;
1045         parse_modrm(s, modrm);
1046         /* load shift */
1047         ldub_code(s->pc++);
1048         if (op < 4)
1049             goto illegal_op;
1050         break;
1051         /************************/
1052         /* bcd */
1053     case 0x27: /* daa */
1054         break;
1055     case 0x2f: /* das */
1056         break;
1057     case 0x37: /* aaa */
1058         break;
1059     case 0x3f: /* aas */
1060         break;
1061     case 0xd4: /* aam */
1062         ldub_code(s->pc++);
1063         break;
1064     case 0xd5: /* aad */
1065         ldub_code(s->pc++);
1066         break;
1067         /************************/
1068         /* misc */
1069     case 0x90: /* nop */
1070         break;
1071     case 0x9b: /* fwait */
1072         if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == 
1073             (HF_MP_MASK | HF_TS_MASK)) {
1074             goto unsupported_op;
1075         }
1076         break;
1077     case 0xcc: /* int3 */
1078         goto unsupported_op;
1079     case 0xcd: /* int N */
1080         goto unsupported_op;
1081     case 0xce: /* into */
1082         goto unsupported_op;
1083     case 0xf1: /* icebp (undocumented, exits to external debugger) */
1084         goto unsupported_op;
1085     case 0xfa: /* cli */
1086         goto unsupported_op;
1087     case 0xfb: /* sti */
1088         goto unsupported_op;
1089     case 0x62: /* bound */
1090         modrm = ldub_code(s->pc++);
1091         mod = (modrm >> 6) & 3;
1092         if (mod == 3)
1093             goto illegal_op;
1094         parse_modrm(s, modrm);
1095         break;
1096     case 0x1c8 ... 0x1cf: /* bswap reg */
1097         break;
1098     case 0xd6: /* salc */
1099         break;
1100     case 0xe0: /* loopnz */
1101     case 0xe1: /* loopz */
1102     case 0xe2: /* loop */
1103     case 0xe3: /* jecxz */
1104         goto unsupported_op;
1105
1106     case 0x130: /* wrmsr */
1107     case 0x132: /* rdmsr */
1108         goto unsupported_op;
1109     case 0x131: /* rdtsc */
1110         goto unsupported_op;
1111     case 0x1a2: /* cpuid */
1112         goto unsupported_op;
1113     case 0xf4: /* hlt */
1114         goto unsupported_op;
1115     case 0x100:
1116         goto unsupported_op;
1117     case 0x101:
1118         goto unsupported_op;
1119     case 0x108: /* invd */
1120     case 0x109: /* wbinvd */
1121         goto unsupported_op;
1122     case 0x63: /* arpl */
1123         goto unsupported_op;
1124     case 0x102: /* lar */
1125     case 0x103: /* lsl */
1126         goto unsupported_op;
1127     case 0x118:
1128         goto unsupported_op;
1129     case 0x120: /* mov reg, crN */
1130     case 0x122: /* mov crN, reg */
1131         goto unsupported_op;
1132     case 0x121: /* mov reg, drN */
1133     case 0x123: /* mov drN, reg */
1134         goto unsupported_op;
1135     case 0x106: /* clts */
1136         goto unsupported_op;
1137     default:
1138         goto illegal_op;
1139     }
1140
1141     /* just copy the code */
1142
1143     /* no override yet */
1144     if (!s->dflag)
1145         gb(s, 0x66);
1146     if (!s->aflag)
1147         gb(s, 0x67);
1148     if (prefixes & PREFIX_REPZ)
1149         gb(s, 0xf3);
1150     else if (prefixes & PREFIX_REPNZ)
1151         gb(s, 0xf2);
1152     {
1153         int len, i;
1154         len = s->pc - pc_start_insn;
1155         for(i = 0; i < len; i++) {
1156             *s->gen_code_ptr++ = ldub_code(pc_start_insn + i);
1157         }
1158     }
1159  no_copy:
1160     return 0;
1161  illegal_op:
1162  unsupported_op:
1163     /* fall back to slower code gen necessary */
1164     s->pc = pc_start;
1165     return -1;
1166 }
1167
1168 #define GEN_CODE_MAX_SIZE      8192
1169 #define GEN_CODE_MAX_INSN_SIZE 512
1170
1171 static inline int gen_intermediate_code_internal(CPUState *env,
1172                                                  TranslationBlock *tb, 
1173                                                  uint8_t *gen_code_ptr,
1174                                                  int *gen_code_size_ptr,
1175                                                  int search_pc,
1176                                                  uint8_t *tc_ptr)
1177 {
1178     DisasContext dc1, *dc = &dc1;
1179     uint8_t *pc_insn, *pc_start, *gen_code_end;
1180     int flags, ret;
1181     uint8_t *cs_base;
1182
1183     if (env->nb_breakpoints > 0 ||
1184         env->singlestep_enabled)
1185         return -1;
1186     flags = tb->flags;
1187     if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | 
1188                  HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK))
1189         return -1;
1190     if (!(flags & HF_SS32_MASK))
1191         return -1;
1192     if (tb->cflags & CF_SINGLE_INSN)
1193         return -1;
1194     gen_code_end = gen_code_ptr + 
1195         GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE;
1196     dc->gen_code_ptr = gen_code_ptr;
1197     dc->gen_code_start = gen_code_ptr;
1198
1199     /* generate intermediate code */
1200     pc_start = (uint8_t *)tb->pc;
1201     cs_base = (uint8_t *)tb->cs_base;
1202     dc->pc = pc_start;
1203     dc->cs_base = cs_base;
1204     dc->pe = (flags >> HF_PE_SHIFT) & 1;
1205     dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
1206     dc->f_st = 0;
1207     dc->vm86 = (flags >> VM_SHIFT) & 1;
1208     dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
1209     dc->iopl = (flags >> IOPL_SHIFT) & 3;
1210     dc->tb = tb;
1211     dc->flags = flags;
1212
1213     dc->is_jmp = 0;
1214
1215     for(;;) {
1216         pc_insn = dc->pc;
1217         ret = disas_insn(dc);
1218         if (ret < 0) {
1219             /* unsupported insn */
1220             if (dc->pc == pc_start) {
1221                 /* if first instruction, signal that no copying was done */
1222                 return -1;
1223             } else {
1224                 gen_jmp(dc, dc->pc - dc->cs_base);
1225                 dc->is_jmp = 1;
1226             }
1227         }
1228         if (search_pc) {
1229             /* search pc mode */
1230             if (tc_ptr < dc->gen_code_ptr) {
1231                 env->eip = pc_insn - cs_base;
1232                 return 0;
1233             }
1234         }
1235         /* stop translation if indicated */
1236         if (dc->is_jmp)
1237             break;
1238         /* if too long translation, stop generation */
1239         if (dc->gen_code_ptr >= gen_code_end ||
1240             (dc->pc - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
1241             gen_jmp(dc, dc->pc - dc->cs_base);
1242             break;
1243         }
1244     }
1245     
1246 #ifdef DEBUG_DISAS
1247     if (loglevel & CPU_LOG_TB_IN_ASM) {
1248         fprintf(logfile, "----------------\n");
1249         fprintf(logfile, "IN: COPY: %s fpu=%d\n", 
1250                 lookup_symbol(pc_start),
1251                 tb->cflags & CF_TB_FP_USED ? 1 : 0);
1252         disas(logfile, pc_start, dc->pc - pc_start, 0, !dc->code32);
1253         fprintf(logfile, "\n");
1254     }
1255 #endif
1256
1257     if (!search_pc) {
1258         *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start;
1259         tb->size = dc->pc - pc_start;
1260         tb->cflags |= CF_CODE_COPY;
1261         return 0;
1262     } else {
1263         return -1;
1264     }
1265 }
1266
1267 /* generate code by just copying data. Return -1 if cannot generate
1268    any code. Return 0 if code was generated */
1269 int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb,
1270                       int max_code_size, int *gen_code_size_ptr)
1271 {
1272     /* generate machine code */
1273     tb->tb_next_offset[0] = 0xffff;
1274     tb->tb_next_offset[1] = 0xffff;
1275 #ifdef USE_DIRECT_JUMP
1276     /* the following two entries are optional (only used for string ops) */
1277     tb->tb_jmp_offset[2] = 0xffff;
1278     tb->tb_jmp_offset[3] = 0xffff;
1279 #endif
1280     return gen_intermediate_code_internal(env, tb, 
1281                                           tb->tc_ptr, gen_code_size_ptr,
1282                                           0, NULL);
1283 }
1284
1285 static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE];
1286
1287 int cpu_restore_state_copy(TranslationBlock *tb, 
1288                            CPUState *env, unsigned long searched_pc,
1289                            void *puc)
1290 {
1291     struct ucontext *uc = puc;
1292     int ret, eflags;
1293
1294     /* find opc index corresponding to search_pc */
1295     if (searched_pc < (unsigned long)tb->tc_ptr)
1296         return -1;
1297     searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf;
1298     ret = gen_intermediate_code_internal(env, tb, 
1299                                          dummy_gen_code_buf, NULL,
1300                                          1, (uint8_t *)searched_pc);
1301     if (ret < 0)
1302         return ret;
1303     /* restore all the CPU state from the CPU context from the
1304        signal. The FPU context stays in the host CPU. */
1305     
1306     env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX];
1307     env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX];
1308     env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX];
1309     env->regs[R_EBX] = uc->uc_mcontext.gregs[REG_EBX];
1310     env->regs[R_ESP] = uc->uc_mcontext.gregs[REG_ESP];
1311     env->regs[R_EBP] = uc->uc_mcontext.gregs[REG_EBP];
1312     env->regs[R_ESI] = uc->uc_mcontext.gregs[REG_ESI];
1313     env->regs[R_EDI] = uc->uc_mcontext.gregs[REG_EDI];
1314     eflags = uc->uc_mcontext.gregs[REG_EFL];
1315     env->df = 1 - (2 * ((eflags >> 10) & 1));
1316     env->cc_src = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1317     env->cc_op = CC_OP_EFLAGS;
1318     return 0;
1319 }
1320
1321 #endif /* USE_CODE_COPY */