Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (33.6 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 <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 & CPU_LOG_TB_IN_ASM) {
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 */