Revision 6dbad63e

b/TODO
1
- daa/das
2
- optimize translated cache chaining (DLL PLT like system)
3 1
- segment ops (minimal LDT/GDT support for wine)
2
- optimize translated cache chaining (DLL PLT like system)
4 3
- improved 16 bit support 
5 4
- optimize inverse flags propagation (easy by generating intermediate
6 5
  micro operation array).
b/cpu-i386.h
123 123
typedef double CPU86_LDouble;
124 124
#endif
125 125

  
126
typedef struct SegmentCache {
127
    uint8_t *base;
128
    unsigned long limit;
129
    uint8_t seg_32bit;
130
} SegmentCache;
131

  
132
typedef struct SegmentDescriptorTable {
133
    uint8_t *base;
134
    unsigned long limit;
135
    /* this is the returned base when reading the register, just to
136
    avoid that the emulated program modifies it */
137
    unsigned long emu_base;
138
} SegmentDescriptorTable;
139

  
126 140
typedef struct CPUX86State {
127 141
    /* standard registers */
128 142
    uint32_t regs[8];
......
135 149
    uint32_t cc_op;
136 150
    int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
137 151

  
138
    /* segments */
139
    uint8_t *segs_base[6];
140

  
141 152
    /* FPU state */
142 153
    unsigned int fpstt; /* top of stack index */
143 154
    unsigned int fpus;
......
145 156
    uint8_t fptags[8];   /* 0 = valid, 1 = empty */
146 157
    CPU86_LDouble fpregs[8];    
147 158

  
148
    /* segments */
149
    uint32_t segs[6];
150

  
151 159
    /* emulator internal variables */
152 160
    CPU86_LDouble ft0;
153 161
    
162
    /* segments */
163
    uint32_t segs[6]; /* selector values */
164
    SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
165
    SegmentDescriptorTable gdt;
166
    SegmentDescriptorTable ldt;
167
    SegmentDescriptorTable idt;
168
    
169
    /* various CPU modes */
170
    int vm86;
171

  
154 172
    /* exception handling */
155 173
    jmp_buf jmp_env;
156 174
    int exception_index;
......
241 259
int cpu_x86_exec(CPUX86State *s);
242 260
void cpu_x86_close(CPUX86State *s);
243 261

  
262
/* needed to load some predefinied segment registers */
263
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
264

  
244 265
/* internal functions */
266

  
267
#define GEN_FLAG_CODE32_SHIFT 0
268
#define GEN_FLAG_ADDSEG_SHIFT 1
269
#define GEN_FLAG_ST_SHIFT     2
245 270
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
246
                     int *gen_code_size_ptr, uint8_t *pc_start);
271
                     int *gen_code_size_ptr, uint8_t *pc_start, 
272
                     int flags);
247 273
void cpu_x86_tblocks_init(void);
248 274

  
249 275
#endif /* CPU_I386_H */
b/exec-i386.c
36 36
#define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / 64)
37 37
#define CODE_GEN_HASH_BITS     15
38 38
#define CODE_GEN_HASH_SIZE     (1 << CODE_GEN_HASH_BITS)
39

  
39 40
typedef struct TranslationBlock {
40 41
    unsigned long pc;   /* simulated PC corresponding to this block */
42
    unsigned int flags; /* flags defining in which context the code was generated */
41 43
    uint8_t *tc_ptr;    /* pointer to the translated code */
42 44
    struct TranslationBlock *hash_next; /* next matching block */
43 45
} TranslationBlock;
......
137 139

  
138 140
/* find a translation block in the translation cache. If not found,
139 141
   allocate a new one */
140
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc)
142
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, 
143
                                                  unsigned int flags)
141 144
{
142 145
    TranslationBlock **ptb, *tb;
143 146
    unsigned int h;
......
148 151
        tb = *ptb;
149 152
        if (!tb)
150 153
            break;
151
        if (tb->pc == pc)
154
        if (tb->pc == pc && tb->flags == flags)
152 155
            return tb;
153 156
        ptb = &tb->hash_next;
154 157
    }
......
158 161
    tb = &tbs[nb_tbs++];
159 162
    *ptb = tb;
160 163
    tb->pc = pc;
164
    tb->flags = flags;
161 165
    tb->tc_ptr = NULL;
162 166
    tb->hash_next = NULL;
163 167
    return tb;
......
171 175
    void (*gen_func)(void);
172 176
    TranslationBlock *tb;
173 177
    uint8_t *tc_ptr;
174
    
178
    unsigned int flags;
179

  
175 180
    /* first we save global registers */
176 181
    saved_T0 = T0;
177 182
    saved_T1 = T1;
......
187 192
                cpu_x86_dump_state();
188 193
            }
189 194
#endif
190
            tb = tb_find_and_alloc((unsigned long)env->pc);
195
            /* we compute the CPU state. We assume it will not
196
               change during the whole generated block. */
197
            flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
198
            flags |= (((unsigned long)env->seg_cache[R_DS].base | 
199
                       (unsigned long)env->seg_cache[R_ES].base |
200
                       (unsigned long)env->seg_cache[R_SS].base) != 0) << 
201
                GEN_FLAG_ADDSEG_SHIFT;
202
            tb = tb_find_and_alloc((unsigned long)env->pc, flags);
191 203
            tc_ptr = tb->tc_ptr;
192 204
            if (!tb->tc_ptr) {
193 205
                /* if no translated code available, then translate it now */
194 206
                tc_ptr = code_gen_ptr;
195 207
                cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
196
                                 &code_gen_size, (uint8_t *)env->pc);
208
                                 &code_gen_size, (uint8_t *)env->pc, flags);
197 209
                tb->tc_ptr = tc_ptr;
198 210
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
199 211
            }
......
211 223
    env = saved_env;
212 224
    return ret;
213 225
}
226

  
227
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
228
{
229
    CPUX86State *saved_env;
230

  
231
    saved_env = env;
232
    env = s;
233
    load_seg(seg_reg, selector);
234
    env = saved_env;
235
}
b/exec-i386.h
27 27
extern FILE *logfile;
28 28
extern int loglevel;
29 29
extern int fprintf(FILE *, const char *, ...);
30
extern int printf(const char *, ...);
30 31

  
31 32
#ifdef __i386__
32 33
register unsigned int T0 asm("ebx");
......
103 104
} CCTable;
104 105

  
105 106
extern CCTable cc_table[];
107

  
108
void load_seg(int seg_reg, int selector);
b/linux-user/main.c
1 1
/*
2
 *  emu main
2
 *  gemu main
3 3
 * 
4 4
 *  Copyright (c) 2003 Fabrice Bellard
5 5
 *
......
80 80
    return 0;
81 81
}
82 82

  
83
/* default linux values for the selectors */
84
#define __USER_CS	(0x23)
85
#define __USER_DS	(0x2B)
83 86

  
84
/* XXX: currently we use LDT entries */
85
#define __USER_CS	(0x23|4)
86
#define __USER_DS	(0x2B|4)
87
void write_dt(void *ptr, unsigned long addr, unsigned long limit, 
88
              int seg32_bit)
89
{
90
    unsigned int e1, e2, limit_in_pages;
91
    limit_in_pages = 0;
92
    if (limit > 0xffff) {
93
        limit = limit >> 12;
94
        limit_in_pages = 1;
95
    }
96
    e1 = (addr << 16) | (limit & 0xffff);
97
    e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
98
    e2 |= limit_in_pages << 23; /* byte granularity */
99
    e2 |= seg32_bit << 22; /* 32 bit segment */
100
    stl((uint8_t *)ptr, e1);
101
    stl((uint8_t *)ptr + 4, e2);
102
}
103

  
104
uint64_t gdt_table[6];
87 105

  
88 106
void usage(void)
89 107
{
......
94 112
    exit(1);
95 113
}
96 114

  
115

  
116

  
97 117
int main(int argc, char **argv)
98 118
{
99 119
    const char *filename;
......
149 169

  
150 170
    env = cpu_x86_init();
151 171

  
172
    /* linux register setup */
152 173
    env->regs[R_EAX] = regs->eax;
153 174
    env->regs[R_EBX] = regs->ebx;
154 175
    env->regs[R_ECX] = regs->ecx;
......
157 178
    env->regs[R_EDI] = regs->edi;
158 179
    env->regs[R_EBP] = regs->ebp;
159 180
    env->regs[R_ESP] = regs->esp;
160
    env->segs[R_CS] = __USER_CS;
161
    env->segs[R_DS] = __USER_DS;
162
    env->segs[R_ES] = __USER_DS;
163
    env->segs[R_SS] = __USER_DS;
164
    env->segs[R_FS] = __USER_DS;
165
    env->segs[R_GS] = __USER_DS;
166 181
    env->pc = regs->eip;
167 182

  
168
#if 0
169
    LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32;
170
    LDT[__USER_CS >> 3].dwSelLimit = 0xfffff;
171
    LDT[__USER_CS >> 3].lpSelBase = NULL;
172

  
173
    LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32;
174
    LDT[__USER_DS >> 3].dwSelLimit = 0xfffff;
175
    LDT[__USER_DS >> 3].lpSelBase = NULL;
176
#endif
183
    /* linux segment setup */
184
    env->gdt.base = (void *)gdt_table;
185
    env->gdt.limit = sizeof(gdt_table) - 1;
186
    write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1);
187
    write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1);
188
    cpu_x86_load_seg(env, R_CS, __USER_CS);
189
    cpu_x86_load_seg(env, R_DS, __USER_DS);
190
    cpu_x86_load_seg(env, R_ES, __USER_DS);
191
    cpu_x86_load_seg(env, R_SS, __USER_DS);
192
    cpu_x86_load_seg(env, R_FS, __USER_DS);
193
    cpu_x86_load_seg(env, R_GS, __USER_DS);
177 194

  
178 195
    for(;;) {
179 196
        int err;
......
186 203
            if (pc[0] == 0xcd && pc[1] == 0x80) {
187 204
                /* syscall */
188 205
                env->pc += 2;
189
                env->regs[R_EAX] = do_syscall(env->regs[R_EAX], 
206
                env->regs[R_EAX] = do_syscall(env, 
207
                                              env->regs[R_EAX], 
190 208
                                              env->regs[R_EBX],
191 209
                                              env->regs[R_ECX],
192 210
                                              env->regs[R_EDX],
b/linux-user/qemu.h
48 48

  
49 49
void target_set_brk(char *new_brk);
50 50
void syscall_init(void);
51
long do_syscall(int num, long arg1, long arg2, long arg3, 
51
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
52 52
                long arg4, long arg5, long arg6);
53 53
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
54 54

  
b/linux-user/syscall.c
69 69
#include "syscall_defs.h"
70 70

  
71 71
#ifdef TARGET_I386
72
#include "cpu-i386.h"
72 73
#include "syscall-i386.h"
73 74
#endif
74 75

  
......
607 608
    .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
608 609
};
609 610

  
611
#ifdef TARGET_I386
612

  
613
/* NOTE: there is really one LDT for all the threads */
614
uint8_t *ldt_table;
615

  
616
static int read_ldt(void *ptr, unsigned long bytecount)
617
{
618
    int size;
619

  
620
    if (!ldt_table)
621
        return 0;
622
    size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
623
    if (size > bytecount)
624
        size = bytecount;
625
    memcpy(ptr, ldt_table, size);
626
    return size;
627
}
628

  
629
/* XXX: add locking support */
630
static int write_ldt(CPUX86State *env, 
631
                     void *ptr, unsigned long bytecount, int oldmode)
632
{
633
    struct target_modify_ldt_ldt_s ldt_info;
634
    int seg_32bit, contents, read_exec_only, limit_in_pages;
635
    int seg_not_present, useable;
636
    uint32_t *lp, entry_1, entry_2;
637

  
638
    if (bytecount != sizeof(ldt_info))
639
        return -EINVAL;
640
    memcpy(&ldt_info, ptr, sizeof(ldt_info));
641
    tswap32s(&ldt_info.entry_number);
642
    tswapls((long *)&ldt_info.base_addr);
643
    tswap32s(&ldt_info.limit);
644
    tswap32s(&ldt_info.flags);
645
    
646
    if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
647
        return -EINVAL;
648
    seg_32bit = ldt_info.flags & 1;
649
    contents = (ldt_info.flags >> 1) & 3;
650
    read_exec_only = (ldt_info.flags >> 3) & 1;
651
    limit_in_pages = (ldt_info.flags >> 4) & 1;
652
    seg_not_present = (ldt_info.flags >> 5) & 1;
653
    useable = (ldt_info.flags >> 6) & 1;
654

  
655
    if (contents == 3) {
656
        if (oldmode)
657
            return -EINVAL;
658
        if (seg_not_present == 0)
659
            return -EINVAL;
660
    }
661
    /* allocate the LDT */
662
    if (!ldt_table) {
663
        ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
664
        if (!ldt_table)
665
            return -ENOMEM;
666
        memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
667
        env->ldt.base = ldt_table;
668
        env->ldt.limit = 0xffff;
669
    }
670

  
671
    /* NOTE: same code as Linux kernel */
672
    /* Allow LDTs to be cleared by the user. */
673
    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
674
        if (oldmode ||
675
            (contents == 0		&&
676
             read_exec_only == 1	&&
677
             seg_32bit == 0		&&
678
             limit_in_pages == 0	&&
679
             seg_not_present == 1	&&
680
             useable == 0 )) {
681
            entry_1 = 0;
682
            entry_2 = 0;
683
            goto install;
684
        }
685
    }
686
    
687
    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
688
        (ldt_info.limit & 0x0ffff);
689
    entry_2 = (ldt_info.base_addr & 0xff000000) |
690
        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
691
        (ldt_info.limit & 0xf0000) |
692
        ((read_exec_only ^ 1) << 9) |
693
        (contents << 10) |
694
        ((seg_not_present ^ 1) << 15) |
695
        (seg_32bit << 22) |
696
        (limit_in_pages << 23) |
697
        0x7000;
698
    if (!oldmode)
699
        entry_2 |= (useable << 20);
700
    
701
    /* Install the new entry ...  */
702
install:
703
    lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
704
    lp[0] = tswap32(entry_1);
705
    lp[1] = tswap32(entry_2);
706
    return 0;
707
}
708

  
709
/* specific and weird i386 syscalls */
710
int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount)
711
{
712
    int ret = -ENOSYS;
713
    
714
    switch (func) {
715
    case 0:
716
        ret = read_ldt(ptr, bytecount);
717
        break;
718
    case 1:
719
        ret = write_ldt(env, ptr, bytecount, 1);
720
        break;
721
    case 0x11:
722
        ret = write_ldt(env, ptr, bytecount, 0);
723
        break;
724
    }
725
    return ret;
726
}
727
#endif
728

  
610 729
void syscall_init(void)
611 730
{
612 731
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); 
......
616 735
#undef STRUCT_SPECIAL
617 736
}
618 737
                                 
619
long do_syscall(int num, long arg1, long arg2, long arg3, 
738
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
620 739
                long arg4, long arg5, long arg6)
621 740
{
622 741
    long ret;
......
1095 1214
        /* no need to transcode because we use the linux syscall */
1096 1215
        ret = get_errno(sys_uname((struct new_utsname *)arg1));
1097 1216
        break;
1217
#ifdef TARGET_I386
1098 1218
    case TARGET_NR_modify_ldt:
1099
        goto unimplemented;
1219
        ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3));
1220
        break;
1221
#endif
1100 1222
    case TARGET_NR_adjtimex:
1101 1223
        goto unimplemented;
1102 1224
    case TARGET_NR_mprotect:
b/linux-user/syscall_types.h
61 61

  
62 62
STRUCT(hd_geometry,
63 63
       TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG)
64

  
b/op-i386.c
858 858
    CC_SRC = eflags;
859 859
}
860 860

  
861
/* segment handling */
862

  
863
void load_seg(int seg_reg, int selector)
864
{
865
    SegmentCache *sc;
866
    SegmentDescriptorTable *dt;
867
    int index;
868
    uint32_t e1, e2;
869
    uint8_t *ptr;
870

  
871
    env->segs[seg_reg] = selector;
872
    sc = &env->seg_cache[seg_reg];
873
    if (env->vm86) {
874
        sc->base = (void *)(selector << 4);
875
        sc->limit = 0xffff;
876
        sc->seg_32bit = 0;
877
    } else {
878
        if (selector & 0x4)
879
            dt = &env->ldt;
880
        else
881
            dt = &env->gdt;
882
        index = selector & ~7;
883
        if ((index + 7) > dt->limit)
884
            raise_exception(EXCP0D_GPF);
885
        ptr = dt->base + index;
886
        e1 = ldl(ptr);
887
        e2 = ldl(ptr + 4);
888
        sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
889
        sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000);
890
        if (e2 & (1 << 23))
891
            sc->limit = (sc->limit << 12) | 0xfff;
892
        sc->seg_32bit = (e2 >> 22) & 1;
893
#if 0
894
        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", 
895
                selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit);
896
#endif
897
    }
898
}
899

  
900
void OPPROTO op_movl_seg_T0(void)
901
{
902
    load_seg(PARAM1, T0 & 0xffff);
903
}
904

  
905
void OPPROTO op_movl_T0_seg(void)
906
{
907
    T0 = env->segs[PARAM1];
908
}
909

  
910
void OPPROTO op_addl_A0_seg(void)
911
{
912
    A0 += *(unsigned long *)((char *)env + PARAM1);
913
}
914

  
861 915
/* flags handling */
862 916

  
863 917
/* slow jumps cases (compute x86 flags) */
b/syscall-i386.h
758 758
#define TARGET_SOUND_MIXER_WRITE_ENHANCE  0xc0044d1f
759 759
#define TARGET_SOUND_MIXER_WRITE_LOUD     0xc0044d1f
760 760
#define TARGET_SOUND_MIXER_WRITE_RECSRC   0xc0044dff
761

  
762
#define TARGET_LDT_ENTRIES      8192
763
#define TARGET_LDT_ENTRY_SIZE	8
764

  
765
struct target_modify_ldt_ldt_s {
766
    unsigned int  entry_number;
767
    target_ulong base_addr;
768
    unsigned int limit;
769
    unsigned int flags;
770
};
771

  
b/tests/test-i386.c
1 1
#include <stdlib.h>
2 2
#include <stdio.h>
3
#include <inttypes.h>
3 4
#include <math.h>
4 5

  
5 6
#define xglue(x, y) x ## y
......
612 613
    TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));
613 614
}
614 615

  
616
/**********************************************/
617
/* segmentation tests */
618

  
619
#include <asm/ldt.h>
620
#include <linux/unistd.h>
621

  
622
_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
623

  
624
uint8_t seg_data1[4096];
625
uint8_t seg_data2[4096];
626

  
627
#define MK_SEL(n) (((n) << 3) | 4)
628

  
629
/* NOTE: we use Linux modify_ldt syscall */
630
void test_segs(void)
631
{
632
    struct modify_ldt_ldt_s ldt;
633
    long long ldt_table[3];
634
    int i, res, res2;
635
    char tmp;
636

  
637
    ldt.entry_number = 1;
638
    ldt.base_addr = (unsigned long)&seg_data1;
639
    ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12;
640
    ldt.seg_32bit = 1;
641
    ldt.contents = MODIFY_LDT_CONTENTS_DATA;
642
    ldt.read_exec_only = 0;
643
    ldt.limit_in_pages = 1;
644
    ldt.seg_not_present = 0;
645
    ldt.useable = 1;
646
    modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
647

  
648
    ldt.entry_number = 2;
649
    ldt.base_addr = (unsigned long)&seg_data2;
650
    ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12;
651
    ldt.seg_32bit = 1;
652
    ldt.contents = MODIFY_LDT_CONTENTS_DATA;
653
    ldt.read_exec_only = 0;
654
    ldt.limit_in_pages = 1;
655
    ldt.seg_not_present = 0;
656
    ldt.useable = 1;
657
    modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
658

  
659
    modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */
660
    for(i=0;i<3;i++)
661
        printf("%d: %016Lx\n", i, ldt_table[i]);
662

  
663
    /* do some tests with fs or gs */
664
    asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
665
    asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2)));
666

  
667
    seg_data1[1] = 0xaa;
668
    seg_data2[1] = 0x55;
669

  
670
    asm volatile ("fs movzbl 0x1, %0" : "=r" (res));
671
    printf("FS[1] = %02x\n", res);
672

  
673
    asm volatile ("gs movzbl 0x1, %0" : "=r" (res));
674
    printf("GS[1] = %02x\n", res);
675

  
676
    /* tests with ds/ss (implicit segment case) */
677
    tmp = 0xa5;
678
    asm volatile ("pushl %%ebp\n\t"
679
                  "pushl %%ds\n\t"
680
                  "movl %2, %%ds\n\t"
681
                  "movl %3, %%ebp\n\t"
682
                  "movzbl 0x1, %0\n\t"
683
                  "movzbl (%%ebp), %1\n\t"
684
                  "popl %%ds\n\t"
685
                  "popl %%ebp\n\t"
686
                  : "=r" (res), "=r" (res2)
687
                  : "r" (MK_SEL(1)), "r" (&tmp));
688
    printf("DS[1] = %02x\n", res);
689
    printf("SS[tmp] = %02x\n", res2);
690
}
615 691

  
616 692
static void *call_end __init_call = NULL;
617 693

  
......
628 704
    test_bsx();
629 705
    test_mul();
630 706
    test_jcc();
631
    test_lea();
632 707
    test_floats();
633 708
    test_bcd();
709
    test_lea();
710
    test_segs();
634 711
    return 0;
635 712
}
b/translate-i386.c
34 34
#include "dis-asm.h"
35 35
#endif
36 36

  
37
#ifndef offsetof
38
#define offsetof(type, field) ((size_t) &((type *)0)->field)
39
#endif
40

  
37 41
static uint8_t *gen_code_ptr;
38 42
int __op_param1, __op_param2, __op_param3;
39 43

  
......
71 75
    int prefix;
72 76
    int aflag, dflag;
73 77
    uint8_t *pc; /* current pc */
74
    int cc_op; /* current CC operation */
75
    int f_st;
78
    int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
79
                   static state change (stop translation) */
80
    /* current block context */
81
    int code32; /* 32 bit code segment */
82
    int cc_op;  /* current CC operation */
83
    int addseg; /* non zero if either DS/ES/SS have a non zero base */
84
    int f_st;   /* currently unused */
76 85
} DisasContext;
77 86

  
78 87
/* i386 arith/logic operations */
......
763 772
static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
764 773
{
765 774
    int havesib;
766
    int havebase;
767 775
    int base, disp;
768
    int index = 0;
769
    int scale = 0;
770
    int reg1, reg2, opreg;
771
    int mod, rm, code;
776
    int index;
777
    int scale;
778
    int opreg;
779
    int mod, rm, code, override, must_add_seg;
780

  
781
    /* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */
782
    /* XXX: fix lea case */
783
    override = -1;
784
    must_add_seg = s->addseg;
785
    if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | 
786
                     PREFIX_ES | PREFIX_FS | PREFIX_GS)) {
787
        if (s->prefix & PREFIX_ES)
788
            override = R_ES;
789
        else if (s->prefix & PREFIX_CS)
790
            override = R_CS;
791
        else if (s->prefix & PREFIX_SS)
792
            override = R_SS;
793
        else if (s->prefix & PREFIX_DS)
794
            override = R_DS;
795
        else if (s->prefix & PREFIX_FS)
796
            override = R_FS;
797
        else
798
            override = R_GS;
799
        must_add_seg = 1;
800
    }
772 801

  
773 802
    mod = (modrm >> 6) & 3;
774 803
    rm = modrm & 7;
......
776 805
    if (s->aflag) {
777 806

  
778 807
        havesib = 0;
779
        havebase = 1;
780 808
        base = rm;
809
        index = 0;
810
        scale = 0;
781 811
        
782 812
        if (base == 4) {
783 813
            havesib = 1;
......
790 820
        switch (mod) {
791 821
        case 0:
792 822
            if (base == 5) {
793
                havebase = 0;
823
                base = -1;
794 824
                disp = ldl(s->pc);
795 825
                s->pc += 4;
796 826
            } else {
......
806 836
            s->pc += 4;
807 837
            break;
808 838
        }
809

  
810
        reg1 = OR_ZERO;
811
        reg2 = OR_ZERO;
812
          
813
        if (havebase || (havesib && (index != 4 || scale != 0))) {
814
            if (havebase)
815
                reg1 = OR_EAX + base;
816
            if (havesib && index != 4) {
817
                if (havebase)
818
                    reg2 = index + OR_EAX;
819
                else
820
                    reg1 = index + OR_EAX;
821
            }
822
        }
823
        /* XXX: disp only ? */
824
        if (reg2 == OR_ZERO) {
825
            /* op: disp + (reg1 << scale) */
826
            if (reg1 == OR_ZERO) {
827
                gen_op_movl_A0_im(disp);
828
            } else if (scale == 0 && disp == 0) {
829
                gen_op_movl_A0_reg[reg1]();
830
            } else {
831
                gen_op_movl_A0_im(disp);
832
                gen_op_addl_A0_reg_sN[scale][reg1]();
833
            }
839
        
840
        if (base >= 0) {
841
            gen_op_movl_A0_reg[base]();
842
            if (disp != 0)
843
                gen_op_addl_A0_im(disp);
834 844
        } else {
835
            /* op: disp + reg1 + (reg2 << scale) */
836
            if (disp != 0) {
837
                gen_op_movl_A0_im(disp);
838
                gen_op_addl_A0_reg_sN[0][reg1]();
839
            } else {
840
                gen_op_movl_A0_reg[reg1]();
845
            gen_op_movl_A0_im(disp);
846
        }
847
        if (havesib && (index != 4 || scale != 0)) {
848
            gen_op_addl_A0_reg_sN[scale][index]();
849
        }
850
        if (must_add_seg) {
851
            if (override < 0) {
852
                if (base == R_EBP || base == R_ESP)
853
                    override = R_SS;
854
                else
855
                    override = R_DS;
841 856
            }
842
            gen_op_addl_A0_reg_sN[scale][reg2]();
857
            gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
843 858
        }
844 859
    } else {
845 860
        switch (mod) {
......
848 863
                disp = lduw(s->pc);
849 864
                s->pc += 2;
850 865
                gen_op_movl_A0_im(disp);
866
                rm = 0; /* avoid SS override */
851 867
                goto no_rm;
852 868
            } else {
853 869
                disp = 0;
......
896 912
        if (disp != 0)
897 913
            gen_op_addl_A0_im(disp);
898 914
        gen_op_andl_A0_ffff();
899
    no_rm: ;
915
    no_rm:
916
        if (must_add_seg) {
917
            if (override < 0) {
918
                if (rm == 2 || rm == 3 || rm == 6)
919
                    override = R_SS;
920
                else
921
                    override = R_DS;
922
            }
923
            gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
924
        }
900 925
    }
926

  
901 927
    opreg = OR_A0;
902 928
    disp = 0;
903 929
    *reg_ptr = opreg;
......
1082 1108
    }
1083 1109
}
1084 1110

  
1111
/* move T0 to seg_reg and compute if the CPU state may change */
1112
void gen_movl_seg_T0(DisasContext *s, int seg_reg)
1113
{
1114
    gen_op_movl_seg_T0(seg_reg);
1115
    if (!s->addseg && seg_reg < R_FS)
1116
        s->is_jmp = 2; /* abort translation because the register may
1117
                          have a non zero base */
1118
}
1119

  
1085 1120
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
1086 1121
   is set to true if the instruction sets the PC (last instruction of
1087 1122
   a basic block) */
1088
long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1123
long disas_insn(DisasContext *s, uint8_t *pc_start)
1089 1124
{
1090 1125
    int b, prefixes, aflag, dflag;
1091 1126
    int shift, ot;
......
1093 1128

  
1094 1129
    s->pc = pc_start;
1095 1130
    prefixes = 0;
1096
    aflag = 1;
1097
    dflag = 1;
1131
    aflag = s->code32;
1132
    dflag = s->code32;
1098 1133
    //    cur_pc = s->pc; /* for insn generation */
1099 1134
 next_byte:
1100 1135
    b = ldub(s->pc);
......
1416 1451
            gen_op_movl_T1_im((long)s->pc);
1417 1452
            gen_op_pushl_T1();
1418 1453
            gen_op_jmp_T0();
1419
            *is_jmp_ptr = 1;
1454
            s->is_jmp = 1;
1420 1455
            break;
1421 1456
        case 4: /* jmp Ev */
1422 1457
            gen_op_jmp_T0();
1423
            *is_jmp_ptr = 1;
1458
            s->is_jmp = 1;
1424 1459
            break;
1425 1460
        case 6: /* push Ev */
1426 1461
            gen_op_pushl_T0();
......
1555 1590
        gen_op_popl_T0();
1556 1591
        gen_op_mov_reg_T0[OT_LONG][R_EBP]();
1557 1592
        break;
1593
    case 0x06: /* push es */
1594
    case 0x0e: /* push cs */
1595
    case 0x16: /* push ss */
1596
    case 0x1e: /* push ds */
1597
        gen_op_movl_T0_seg(b >> 3);
1598
        gen_op_pushl_T0();
1599
        break;
1600
    case 0x1a0: /* push fs */
1601
    case 0x1a8: /* push gs */
1602
        gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS);
1603
        gen_op_pushl_T0();
1604
        break;
1605
    case 0x07: /* pop es */
1606
    case 0x17: /* pop ss */
1607
    case 0x1f: /* pop ds */
1608
        gen_op_popl_T0();
1609
        gen_movl_seg_T0(s, b >> 3);
1610
        break;
1611
    case 0x1a1: /* pop fs */
1612
    case 0x1a9: /* pop gs */
1613
        gen_op_popl_T0();
1614
        gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS);
1615
        break;
1616

  
1558 1617
        /**************************/
1559 1618
        /* mov */
1560 1619
    case 0x88:
......
1598 1657
        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1599 1658
        gen_op_mov_reg_T0[ot][reg]();
1600 1659
        break;
1660
    case 0x8e: /* mov seg, Gv */
1661
        ot = dflag ? OT_LONG : OT_WORD;
1662
        modrm = ldub(s->pc++);
1663
        reg = (modrm >> 3) & 7;
1664
        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1665
        if (reg >= 6)
1666
            goto illegal_op;
1667
        gen_movl_seg_T0(s, reg);
1668
        break;
1669
    case 0x8c: /* mov Gv, seg */
1670
        ot = dflag ? OT_LONG : OT_WORD;
1671
        modrm = ldub(s->pc++);
1672
        reg = (modrm >> 3) & 7;
1673
        if (reg >= 6)
1674
            goto illegal_op;
1675
        gen_op_movl_T0_seg(reg);
1676
        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
1677
        break;
1601 1678

  
1602 1679
    case 0x1b6: /* movzbS Gv, Eb */
1603 1680
    case 0x1b7: /* movzwS Gv, Eb */
......
1648 1725
        ot = dflag ? OT_LONG : OT_WORD;
1649 1726
        modrm = ldub(s->pc++);
1650 1727
        reg = (modrm >> 3) & 7;
1651

  
1728
        /* we must ensure that no segment is added */
1729
        s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | 
1730
                       PREFIX_ES | PREFIX_FS | PREFIX_GS);
1731
        val = s->addseg;
1732
        s->addseg = 0;
1652 1733
        gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1734
        s->addseg = val;
1653 1735
        gen_op_mov_reg_A0[ot - OT_WORD][reg]();
1654 1736
        break;
1655 1737
        
......
1711 1793
        gen_op_st_T0_A0[ot]();
1712 1794
        gen_op_mov_reg_T1[ot][reg]();
1713 1795
        break;
1796
    case 0xc4: /* les Gv */
1797
        op = R_ES;
1798
        goto do_lxx;
1799
    case 0xc5: /* lds Gv */
1800
        op = R_DS;
1801
        goto do_lxx;
1802
    case 0x1b2: /* lss Gv */
1803
        op = R_SS;
1804
        goto do_lxx;
1805
    case 0x1b4: /* lfs Gv */
1806
        op = R_FS;
1807
        goto do_lxx;
1808
    case 0x1b5: /* lgs Gv */
1809
        op = R_GS;
1810
    do_lxx:
1811
        ot = dflag ? OT_LONG : OT_WORD;
1812
        modrm = ldub(s->pc++);
1813
        reg = (modrm >> 3) & 7;
1814
        mod = (modrm >> 6) & 3;
1815
        if (mod == 3)
1816
            goto illegal_op;
1817
        gen_op_ld_T1_A0[ot]();
1818
        op_addl_A0_im(1 << (ot - OT_WORD + 1));
1819
        /* load the segment first to handle exceptions properly */
1820
        gen_op_lduw_T0_A0();
1821
        gen_movl_seg_T0(s, op);
1822
        /* then put the data */
1823
        gen_op_mov_reg_T1[ot][reg]();
1824
        break;
1714 1825
        
1715 1826
        /************************/
1716 1827
        /* shifts */
......
2327 2438
        gen_op_popl_T0();
2328 2439
        gen_op_addl_ESP_im(val);
2329 2440
        gen_op_jmp_T0();
2330
        *is_jmp_ptr = 1;
2441
        s->is_jmp = 1;
2331 2442
        break;
2332 2443
    case 0xc3: /* ret */
2333 2444
        gen_op_popl_T0();
2334 2445
        gen_op_jmp_T0();
2335
        *is_jmp_ptr = 1;
2446
        s->is_jmp = 1;
2336 2447
        break;
2337 2448
    case 0xe8: /* call */
2338 2449
        val = insn_get(s, OT_LONG);
......
2340 2451
        gen_op_movl_T1_im((long)s->pc);
2341 2452
        gen_op_pushl_T1();
2342 2453
        gen_op_jmp_im(val);
2343
        *is_jmp_ptr = 1;
2454
        s->is_jmp = 1;
2344 2455
        break;
2345 2456
    case 0xe9: /* jmp */
2346 2457
        val = insn_get(s, OT_LONG);
2347 2458
        val += (long)s->pc;
2348 2459
        gen_op_jmp_im(val);
2349
        *is_jmp_ptr = 1;
2460
        s->is_jmp = 1;
2350 2461
        break;
2351 2462
    case 0xeb: /* jmp Jb */
2352 2463
        val = (int8_t)insn_get(s, OT_BYTE);
2353 2464
        val += (long)s->pc;
2354 2465
        gen_op_jmp_im(val);
2355
        *is_jmp_ptr = 1;
2466
        s->is_jmp = 1;
2356 2467
        break;
2357 2468
    case 0x70 ... 0x7f: /* jcc Jb */
2358 2469
        val = (int8_t)insn_get(s, OT_BYTE);
......
2367 2478
        val += (long)s->pc; /* XXX: fix 16 bit wrap */
2368 2479
    do_jcc:
2369 2480
        gen_jcc(s, b, val);
2370
        *is_jmp_ptr = 1;
2481
        s->is_jmp = 1;
2371 2482
        break;
2372 2483

  
2373 2484
    case 0x190 ... 0x19f:
......
2548 2659
        break;
2549 2660
    case 0xcc: /* int3 */
2550 2661
        gen_op_int3((long)pc_start);
2551
        *is_jmp_ptr = 1;
2662
        s->is_jmp = 1;
2552 2663
        break;
2553 2664
    case 0xcd: /* int N */
2554 2665
        val = ldub(s->pc++);
2555 2666
        /* XXX: currently we ignore the interrupt number */
2556 2667
        gen_op_int_im((long)pc_start);
2557
        *is_jmp_ptr = 1;
2668
        s->is_jmp = 1;
2558 2669
        break;
2559 2670
    case 0xce: /* into */
2560 2671
        if (s->cc_op != CC_OP_DYNAMIC)
2561 2672
            gen_op_set_cc_op(s->cc_op);
2562 2673
        gen_op_into((long)pc_start, (long)s->pc);
2563
        *is_jmp_ptr = 1;
2674
        s->is_jmp = 1;
2564 2675
        break;
2565 2676
    case 0x1c8 ... 0x1cf: /* bswap reg */
2566 2677
        reg = b & 7;
......
2586 2697
        return -1;
2587 2698
    }
2588 2699
    return (long)s->pc;
2700
 illegal_op:
2701
    error("illegal opcode pc=0x%08Lx", (long)pc_start);
2702
    return -1;
2589 2703
}
2590 2704

  
2591 2705
/* return the next pc */
2592 2706
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
2593
                     int *gen_code_size_ptr, uint8_t *pc_start)
2707
                     int *gen_code_size_ptr, uint8_t *pc_start, 
2708
                     int flags)
2594 2709
{
2595 2710
    DisasContext dc1, *dc = &dc1;
2596 2711
    uint8_t *gen_code_end, *pc_ptr;
2597
    int is_jmp;
2598 2712
    long ret;
2599 2713
#ifdef DEBUG_DISAS
2600 2714
    struct disassemble_info disasm_info;
2601 2715
#endif
2602

  
2716
    dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1;
2717
    dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
2718
    dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
2603 2719
    dc->cc_op = CC_OP_DYNAMIC;
2604 2720
    gen_code_ptr = gen_code_buf;
2605 2721
    gen_code_end = gen_code_buf + max_code_size - 4096;
2606 2722
    gen_start();
2607 2723

  
2608
    is_jmp = 0;
2724
    dc->is_jmp = 0;
2609 2725
    pc_ptr = pc_start;
2610 2726
    do {
2611
        ret = disas_insn(dc, pc_ptr, &is_jmp);
2727
        ret = disas_insn(dc, pc_ptr);
2612 2728
        if (ret == -1) 
2613 2729
            error("unknown instruction at PC=0x%x B=%02x %02x", 
2614 2730
                  pc_ptr, pc_ptr[0], pc_ptr[1]);
2615 2731
        pc_ptr = (void *)ret;
2616
    } while (!is_jmp && gen_code_ptr < gen_code_end);
2732
    } while (!dc->is_jmp && gen_code_ptr < gen_code_end);
2617 2733
    /* we must store the eflags state if it is not already done */
2618 2734
    if (dc->cc_op != CC_OP_DYNAMIC)
2619 2735
        gen_op_set_cc_op(dc->cc_op);
2620
    if (!is_jmp) {
2736
    if (dc->is_jmp != 1) {
2621 2737
        /* we add an additionnal jmp to update the simulated PC */
2622 2738
        gen_op_jmp_im(ret);
2623 2739
    }

Also available in: Unified diff