Statistics
| Branch: | Revision:

root / target-i386 / translate-copy.c @ d1d9f421

History | View | Annotate | Download (33.7 kB)

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 */