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