Commit 6dbad63eef5947c6c8750e44f408138779b6d0bb

Authored by bellard
1 parent 27362c82

added minimal segment support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@28 c046a42c-6fe2-441c-8c8c-71466251a162
1 -- daa/das  
2 -- optimize translated cache chaining (DLL PLT like system)  
3 - segment ops (minimal LDT/GDT support for wine) 1 - segment ops (minimal LDT/GDT support for wine)
  2 +- optimize translated cache chaining (DLL PLT like system)
4 - improved 16 bit support 3 - improved 16 bit support
5 - optimize inverse flags propagation (easy by generating intermediate 4 - optimize inverse flags propagation (easy by generating intermediate
6 micro operation array). 5 micro operation array).
cpu-i386.h
@@ -123,6 +123,20 @@ typedef long double CPU86_LDouble; @@ -123,6 +123,20 @@ typedef long double CPU86_LDouble;
123 typedef double CPU86_LDouble; 123 typedef double CPU86_LDouble;
124 #endif 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 typedef struct CPUX86State { 140 typedef struct CPUX86State {
127 /* standard registers */ 141 /* standard registers */
128 uint32_t regs[8]; 142 uint32_t regs[8];
@@ -135,9 +149,6 @@ typedef struct CPUX86State { @@ -135,9 +149,6 @@ typedef struct CPUX86State {
135 uint32_t cc_op; 149 uint32_t cc_op;
136 int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ 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 /* FPU state */ 152 /* FPU state */
142 unsigned int fpstt; /* top of stack index */ 153 unsigned int fpstt; /* top of stack index */
143 unsigned int fpus; 154 unsigned int fpus;
@@ -145,12 +156,19 @@ typedef struct CPUX86State { @@ -145,12 +156,19 @@ typedef struct CPUX86State {
145 uint8_t fptags[8]; /* 0 = valid, 1 = empty */ 156 uint8_t fptags[8]; /* 0 = valid, 1 = empty */
146 CPU86_LDouble fpregs[8]; 157 CPU86_LDouble fpregs[8];
147 158
148 - /* segments */  
149 - uint32_t segs[6];  
150 -  
151 /* emulator internal variables */ 159 /* emulator internal variables */
152 CPU86_LDouble ft0; 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 /* exception handling */ 172 /* exception handling */
155 jmp_buf jmp_env; 173 jmp_buf jmp_env;
156 int exception_index; 174 int exception_index;
@@ -241,9 +259,17 @@ CPUX86State *cpu_x86_init(void); @@ -241,9 +259,17 @@ CPUX86State *cpu_x86_init(void);
241 int cpu_x86_exec(CPUX86State *s); 259 int cpu_x86_exec(CPUX86State *s);
242 void cpu_x86_close(CPUX86State *s); 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 /* internal functions */ 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 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 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 void cpu_x86_tblocks_init(void); 273 void cpu_x86_tblocks_init(void);
248 274
249 #endif /* CPU_I386_H */ 275 #endif /* CPU_I386_H */
exec-i386.c
@@ -36,8 +36,10 @@ @@ -36,8 +36,10 @@
36 #define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) 36 #define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
37 #define CODE_GEN_HASH_BITS 15 37 #define CODE_GEN_HASH_BITS 15
38 #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) 38 #define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
  39 +
39 typedef struct TranslationBlock { 40 typedef struct TranslationBlock {
40 unsigned long pc; /* simulated PC corresponding to this block */ 41 unsigned long pc; /* simulated PC corresponding to this block */
  42 + unsigned int flags; /* flags defining in which context the code was generated */
41 uint8_t *tc_ptr; /* pointer to the translated code */ 43 uint8_t *tc_ptr; /* pointer to the translated code */
42 struct TranslationBlock *hash_next; /* next matching block */ 44 struct TranslationBlock *hash_next; /* next matching block */
43 } TranslationBlock; 45 } TranslationBlock;
@@ -137,7 +139,8 @@ static void tb_flush(void) @@ -137,7 +139,8 @@ static void tb_flush(void)
137 139
138 /* find a translation block in the translation cache. If not found, 140 /* find a translation block in the translation cache. If not found,
139 allocate a new one */ 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 TranslationBlock **ptb, *tb; 145 TranslationBlock **ptb, *tb;
143 unsigned int h; 146 unsigned int h;
@@ -148,7 +151,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc) @@ -148,7 +151,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc)
148 tb = *ptb; 151 tb = *ptb;
149 if (!tb) 152 if (!tb)
150 break; 153 break;
151 - if (tb->pc == pc) 154 + if (tb->pc == pc && tb->flags == flags)
152 return tb; 155 return tb;
153 ptb = &tb->hash_next; 156 ptb = &tb->hash_next;
154 } 157 }
@@ -158,6 +161,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc) @@ -158,6 +161,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc)
158 tb = &tbs[nb_tbs++]; 161 tb = &tbs[nb_tbs++];
159 *ptb = tb; 162 *ptb = tb;
160 tb->pc = pc; 163 tb->pc = pc;
  164 + tb->flags = flags;
161 tb->tc_ptr = NULL; 165 tb->tc_ptr = NULL;
162 tb->hash_next = NULL; 166 tb->hash_next = NULL;
163 return tb; 167 return tb;
@@ -171,7 +175,8 @@ int cpu_x86_exec(CPUX86State *env1) @@ -171,7 +175,8 @@ int cpu_x86_exec(CPUX86State *env1)
171 void (*gen_func)(void); 175 void (*gen_func)(void);
172 TranslationBlock *tb; 176 TranslationBlock *tb;
173 uint8_t *tc_ptr; 177 uint8_t *tc_ptr;
174 - 178 + unsigned int flags;
  179 +
175 /* first we save global registers */ 180 /* first we save global registers */
176 saved_T0 = T0; 181 saved_T0 = T0;
177 saved_T1 = T1; 182 saved_T1 = T1;
@@ -187,13 +192,20 @@ int cpu_x86_exec(CPUX86State *env1) @@ -187,13 +192,20 @@ int cpu_x86_exec(CPUX86State *env1)
187 cpu_x86_dump_state(); 192 cpu_x86_dump_state();
188 } 193 }
189 #endif 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 tc_ptr = tb->tc_ptr; 203 tc_ptr = tb->tc_ptr;
192 if (!tb->tc_ptr) { 204 if (!tb->tc_ptr) {
193 /* if no translated code available, then translate it now */ 205 /* if no translated code available, then translate it now */
194 tc_ptr = code_gen_ptr; 206 tc_ptr = code_gen_ptr;
195 cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 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 tb->tc_ptr = tc_ptr; 209 tb->tc_ptr = tc_ptr;
198 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); 210 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
199 } 211 }
@@ -211,3 +223,13 @@ int cpu_x86_exec(CPUX86State *env1) @@ -211,3 +223,13 @@ int cpu_x86_exec(CPUX86State *env1)
211 env = saved_env; 223 env = saved_env;
212 return ret; 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 +}
exec-i386.h
@@ -27,6 +27,7 @@ typedef struct FILE FILE; @@ -27,6 +27,7 @@ typedef struct FILE FILE;
27 extern FILE *logfile; 27 extern FILE *logfile;
28 extern int loglevel; 28 extern int loglevel;
29 extern int fprintf(FILE *, const char *, ...); 29 extern int fprintf(FILE *, const char *, ...);
  30 +extern int printf(const char *, ...);
30 31
31 #ifdef __i386__ 32 #ifdef __i386__
32 register unsigned int T0 asm("ebx"); 33 register unsigned int T0 asm("ebx");
@@ -103,3 +104,5 @@ typedef struct CCTable { @@ -103,3 +104,5 @@ typedef struct CCTable {
103 } CCTable; 104 } CCTable;
104 105
105 extern CCTable cc_table[]; 106 extern CCTable cc_table[];
  107 +
  108 +void load_seg(int seg_reg, int selector);
linux-user/main.c
1 /* 1 /*
2 - * emu main 2 + * gemu main
3 * 3 *
4 * Copyright (c) 2003 Fabrice Bellard 4 * Copyright (c) 2003 Fabrice Bellard
5 * 5 *
@@ -80,10 +80,28 @@ int cpu_x86_inl(int addr) @@ -80,10 +80,28 @@ int cpu_x86_inl(int addr)
80 return 0; 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 void usage(void) 106 void usage(void)
89 { 107 {
@@ -94,6 +112,8 @@ void usage(void) @@ -94,6 +112,8 @@ void usage(void)
94 exit(1); 112 exit(1);
95 } 113 }
96 114
  115 +
  116 +
97 int main(int argc, char **argv) 117 int main(int argc, char **argv)
98 { 118 {
99 const char *filename; 119 const char *filename;
@@ -149,6 +169,7 @@ int main(int argc, char **argv) @@ -149,6 +169,7 @@ int main(int argc, char **argv)
149 169
150 env = cpu_x86_init(); 170 env = cpu_x86_init();
151 171
  172 + /* linux register setup */
152 env->regs[R_EAX] = regs->eax; 173 env->regs[R_EAX] = regs->eax;
153 env->regs[R_EBX] = regs->ebx; 174 env->regs[R_EBX] = regs->ebx;
154 env->regs[R_ECX] = regs->ecx; 175 env->regs[R_ECX] = regs->ecx;
@@ -157,23 +178,19 @@ int main(int argc, char **argv) @@ -157,23 +178,19 @@ int main(int argc, char **argv)
157 env->regs[R_EDI] = regs->edi; 178 env->regs[R_EDI] = regs->edi;
158 env->regs[R_EBP] = regs->ebp; 179 env->regs[R_EBP] = regs->ebp;
159 env->regs[R_ESP] = regs->esp; 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 env->pc = regs->eip; 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 for(;;) { 195 for(;;) {
179 int err; 196 int err;
@@ -186,7 +203,8 @@ int main(int argc, char **argv) @@ -186,7 +203,8 @@ int main(int argc, char **argv)
186 if (pc[0] == 0xcd && pc[1] == 0x80) { 203 if (pc[0] == 0xcd && pc[1] == 0x80) {
187 /* syscall */ 204 /* syscall */
188 env->pc += 2; 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 env->regs[R_EBX], 208 env->regs[R_EBX],
191 env->regs[R_ECX], 209 env->regs[R_ECX],
192 env->regs[R_EDX], 210 env->regs[R_EDX],
linux-user/qemu.h
@@ -48,7 +48,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp, @@ -48,7 +48,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
48 48
49 void target_set_brk(char *new_brk); 49 void target_set_brk(char *new_brk);
50 void syscall_init(void); 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 long arg4, long arg5, long arg6); 52 long arg4, long arg5, long arg6);
53 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); 53 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
54 54
linux-user/syscall.c
@@ -69,6 +69,7 @@ struct dirent { @@ -69,6 +69,7 @@ struct dirent {
69 #include "syscall_defs.h" 69 #include "syscall_defs.h"
70 70
71 #ifdef TARGET_I386 71 #ifdef TARGET_I386
  72 +#include "cpu-i386.h"
72 #include "syscall-i386.h" 73 #include "syscall-i386.h"
73 #endif 74 #endif
74 75
@@ -607,6 +608,124 @@ StructEntry struct_termios_def = { @@ -607,6 +608,124 @@ StructEntry struct_termios_def = {
607 .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, 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 void syscall_init(void) 729 void syscall_init(void)
611 { 730 {
612 #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); 731 #define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
@@ -616,7 +735,7 @@ void syscall_init(void) @@ -616,7 +735,7 @@ void syscall_init(void)
616 #undef STRUCT_SPECIAL 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 long arg4, long arg5, long arg6) 739 long arg4, long arg5, long arg6)
621 { 740 {
622 long ret; 741 long ret;
@@ -1095,8 +1214,11 @@ long do_syscall(int num, long arg1, long arg2, long arg3, @@ -1095,8 +1214,11 @@ long do_syscall(int num, long arg1, long arg2, long arg3,
1095 /* no need to transcode because we use the linux syscall */ 1214 /* no need to transcode because we use the linux syscall */
1096 ret = get_errno(sys_uname((struct new_utsname *)arg1)); 1215 ret = get_errno(sys_uname((struct new_utsname *)arg1));
1097 break; 1216 break;
  1217 +#ifdef TARGET_I386
1098 case TARGET_NR_modify_ldt: 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 case TARGET_NR_adjtimex: 1222 case TARGET_NR_adjtimex:
1101 goto unimplemented; 1223 goto unimplemented;
1102 case TARGET_NR_mprotect: 1224 case TARGET_NR_mprotect:
linux-user/syscall_types.h
@@ -61,4 +61,3 @@ STRUCT(cdrom_read_audio, @@ -61,4 +61,3 @@ STRUCT(cdrom_read_audio,
61 61
62 STRUCT(hd_geometry, 62 STRUCT(hd_geometry,
63 TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG) 63 TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG)
64 -  
op-i386.c
@@ -858,6 +858,60 @@ void OPPROTO op_das(void) @@ -858,6 +858,60 @@ void OPPROTO op_das(void)
858 CC_SRC = eflags; 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 /* flags handling */ 915 /* flags handling */
862 916
863 /* slow jumps cases (compute x86 flags) */ 917 /* slow jumps cases (compute x86 flags) */
syscall-i386.h
@@ -758,3 +758,14 @@ struct target_termios { @@ -758,3 +758,14 @@ struct target_termios {
758 #define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f 758 #define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f
759 #define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f 759 #define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f
760 #define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff 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 +
tests/test-i386.c
1 #include <stdlib.h> 1 #include <stdlib.h>
2 #include <stdio.h> 2 #include <stdio.h>
  3 +#include <inttypes.h>
3 #include <math.h> 4 #include <math.h>
4 5
5 #define xglue(x, y) x ## y 6 #define xglue(x, y) x ## y
@@ -612,6 +613,81 @@ void test_bcd(void) @@ -612,6 +613,81 @@ void test_bcd(void)
612 TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); 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 static void *call_end __init_call = NULL; 692 static void *call_end __init_call = NULL;
617 693
@@ -628,8 +704,9 @@ int main(int argc, char **argv) @@ -628,8 +704,9 @@ int main(int argc, char **argv)
628 test_bsx(); 704 test_bsx();
629 test_mul(); 705 test_mul();
630 test_jcc(); 706 test_jcc();
631 - test_lea();  
632 test_floats(); 707 test_floats();
633 test_bcd(); 708 test_bcd();
  709 + test_lea();
  710 + test_segs();
634 return 0; 711 return 0;
635 } 712 }
translate-i386.c
@@ -34,6 +34,10 @@ @@ -34,6 +34,10 @@
34 #include "dis-asm.h" 34 #include "dis-asm.h"
35 #endif 35 #endif
36 36
  37 +#ifndef offsetof
  38 +#define offsetof(type, field) ((size_t) &((type *)0)->field)
  39 +#endif
  40 +
37 static uint8_t *gen_code_ptr; 41 static uint8_t *gen_code_ptr;
38 int __op_param1, __op_param2, __op_param3; 42 int __op_param1, __op_param2, __op_param3;
39 43
@@ -71,8 +75,13 @@ typedef struct DisasContext { @@ -71,8 +75,13 @@ typedef struct DisasContext {
71 int prefix; 75 int prefix;
72 int aflag, dflag; 76 int aflag, dflag;
73 uint8_t *pc; /* current pc */ 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 } DisasContext; 85 } DisasContext;
77 86
78 /* i386 arith/logic operations */ 87 /* i386 arith/logic operations */
@@ -763,12 +772,32 @@ static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) @@ -763,12 +772,32 @@ static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
763 static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) 772 static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
764 { 773 {
765 int havesib; 774 int havesib;
766 - int havebase;  
767 int base, disp; 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 mod = (modrm >> 6) & 3; 802 mod = (modrm >> 6) & 3;
774 rm = modrm & 7; 803 rm = modrm & 7;
@@ -776,8 +805,9 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ @@ -776,8 +805,9 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
776 if (s->aflag) { 805 if (s->aflag) {
777 806
778 havesib = 0; 807 havesib = 0;
779 - havebase = 1;  
780 base = rm; 808 base = rm;
  809 + index = 0;
  810 + scale = 0;
781 811
782 if (base == 4) { 812 if (base == 4) {
783 havesib = 1; 813 havesib = 1;
@@ -790,7 +820,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ @@ -790,7 +820,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
790 switch (mod) { 820 switch (mod) {
791 case 0: 821 case 0:
792 if (base == 5) { 822 if (base == 5) {
793 - havebase = 0; 823 + base = -1;
794 disp = ldl(s->pc); 824 disp = ldl(s->pc);
795 s->pc += 4; 825 s->pc += 4;
796 } else { 826 } else {
@@ -806,40 +836,25 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ @@ -806,40 +836,25 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
806 s->pc += 4; 836 s->pc += 4;
807 break; 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 } else { 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 } else { 859 } else {
845 switch (mod) { 860 switch (mod) {
@@ -848,6 +863,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ @@ -848,6 +863,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
848 disp = lduw(s->pc); 863 disp = lduw(s->pc);
849 s->pc += 2; 864 s->pc += 2;
850 gen_op_movl_A0_im(disp); 865 gen_op_movl_A0_im(disp);
  866 + rm = 0; /* avoid SS override */
851 goto no_rm; 867 goto no_rm;
852 } else { 868 } else {
853 disp = 0; 869 disp = 0;
@@ -896,8 +912,18 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ @@ -896,8 +912,18 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
896 if (disp != 0) 912 if (disp != 0)
897 gen_op_addl_A0_im(disp); 913 gen_op_addl_A0_im(disp);
898 gen_op_andl_A0_ffff(); 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 opreg = OR_A0; 927 opreg = OR_A0;
902 disp = 0; 928 disp = 0;
903 *reg_ptr = opreg; 929 *reg_ptr = opreg;
@@ -1082,10 +1108,19 @@ static void gen_setcc(DisasContext *s, int b) @@ -1082,10 +1108,19 @@ static void gen_setcc(DisasContext *s, int b)
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 /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr 1120 /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
1086 is set to true if the instruction sets the PC (last instruction of 1121 is set to true if the instruction sets the PC (last instruction of
1087 a basic block) */ 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 int b, prefixes, aflag, dflag; 1125 int b, prefixes, aflag, dflag;
1091 int shift, ot; 1126 int shift, ot;
@@ -1093,8 +1128,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -1093,8 +1128,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1093 1128
1094 s->pc = pc_start; 1129 s->pc = pc_start;
1095 prefixes = 0; 1130 prefixes = 0;
1096 - aflag = 1;  
1097 - dflag = 1; 1131 + aflag = s->code32;
  1132 + dflag = s->code32;
1098 // cur_pc = s->pc; /* for insn generation */ 1133 // cur_pc = s->pc; /* for insn generation */
1099 next_byte: 1134 next_byte:
1100 b = ldub(s->pc); 1135 b = ldub(s->pc);
@@ -1416,11 +1451,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -1416,11 +1451,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1416 gen_op_movl_T1_im((long)s->pc); 1451 gen_op_movl_T1_im((long)s->pc);
1417 gen_op_pushl_T1(); 1452 gen_op_pushl_T1();
1418 gen_op_jmp_T0(); 1453 gen_op_jmp_T0();
1419 - *is_jmp_ptr = 1; 1454 + s->is_jmp = 1;
1420 break; 1455 break;
1421 case 4: /* jmp Ev */ 1456 case 4: /* jmp Ev */
1422 gen_op_jmp_T0(); 1457 gen_op_jmp_T0();
1423 - *is_jmp_ptr = 1; 1458 + s->is_jmp = 1;
1424 break; 1459 break;
1425 case 6: /* push Ev */ 1460 case 6: /* push Ev */
1426 gen_op_pushl_T0(); 1461 gen_op_pushl_T0();
@@ -1555,6 +1590,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -1555,6 +1590,30 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1555 gen_op_popl_T0(); 1590 gen_op_popl_T0();
1556 gen_op_mov_reg_T0[OT_LONG][R_EBP](); 1591 gen_op_mov_reg_T0[OT_LONG][R_EBP]();
1557 break; 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 /* mov */ 1618 /* mov */
1560 case 0x88: 1619 case 0x88:
@@ -1598,6 +1657,24 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -1598,6 +1657,24 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1598 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); 1657 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1599 gen_op_mov_reg_T0[ot][reg](); 1658 gen_op_mov_reg_T0[ot][reg]();
1600 break; 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 case 0x1b6: /* movzbS Gv, Eb */ 1679 case 0x1b6: /* movzbS Gv, Eb */
1603 case 0x1b7: /* movzwS Gv, Eb */ 1680 case 0x1b7: /* movzwS Gv, Eb */
@@ -1648,8 +1725,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -1648,8 +1725,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1648 ot = dflag ? OT_LONG : OT_WORD; 1725 ot = dflag ? OT_LONG : OT_WORD;
1649 modrm = ldub(s->pc++); 1726 modrm = ldub(s->pc++);
1650 reg = (modrm >> 3) & 7; 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 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); 1733 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
  1734 + s->addseg = val;
1653 gen_op_mov_reg_A0[ot - OT_WORD][reg](); 1735 gen_op_mov_reg_A0[ot - OT_WORD][reg]();
1654 break; 1736 break;
1655 1737
@@ -1711,6 +1793,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -1711,6 +1793,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1711 gen_op_st_T0_A0[ot](); 1793 gen_op_st_T0_A0[ot]();
1712 gen_op_mov_reg_T1[ot][reg](); 1794 gen_op_mov_reg_T1[ot][reg]();
1713 break; 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 /* shifts */ 1827 /* shifts */
@@ -2327,12 +2438,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -2327,12 +2438,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2327 gen_op_popl_T0(); 2438 gen_op_popl_T0();
2328 gen_op_addl_ESP_im(val); 2439 gen_op_addl_ESP_im(val);
2329 gen_op_jmp_T0(); 2440 gen_op_jmp_T0();
2330 - *is_jmp_ptr = 1; 2441 + s->is_jmp = 1;
2331 break; 2442 break;
2332 case 0xc3: /* ret */ 2443 case 0xc3: /* ret */
2333 gen_op_popl_T0(); 2444 gen_op_popl_T0();
2334 gen_op_jmp_T0(); 2445 gen_op_jmp_T0();
2335 - *is_jmp_ptr = 1; 2446 + s->is_jmp = 1;
2336 break; 2447 break;
2337 case 0xe8: /* call */ 2448 case 0xe8: /* call */
2338 val = insn_get(s, OT_LONG); 2449 val = insn_get(s, OT_LONG);
@@ -2340,19 +2451,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -2340,19 +2451,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2340 gen_op_movl_T1_im((long)s->pc); 2451 gen_op_movl_T1_im((long)s->pc);
2341 gen_op_pushl_T1(); 2452 gen_op_pushl_T1();
2342 gen_op_jmp_im(val); 2453 gen_op_jmp_im(val);
2343 - *is_jmp_ptr = 1; 2454 + s->is_jmp = 1;
2344 break; 2455 break;
2345 case 0xe9: /* jmp */ 2456 case 0xe9: /* jmp */
2346 val = insn_get(s, OT_LONG); 2457 val = insn_get(s, OT_LONG);
2347 val += (long)s->pc; 2458 val += (long)s->pc;
2348 gen_op_jmp_im(val); 2459 gen_op_jmp_im(val);
2349 - *is_jmp_ptr = 1; 2460 + s->is_jmp = 1;
2350 break; 2461 break;
2351 case 0xeb: /* jmp Jb */ 2462 case 0xeb: /* jmp Jb */
2352 val = (int8_t)insn_get(s, OT_BYTE); 2463 val = (int8_t)insn_get(s, OT_BYTE);
2353 val += (long)s->pc; 2464 val += (long)s->pc;
2354 gen_op_jmp_im(val); 2465 gen_op_jmp_im(val);
2355 - *is_jmp_ptr = 1; 2466 + s->is_jmp = 1;
2356 break; 2467 break;
2357 case 0x70 ... 0x7f: /* jcc Jb */ 2468 case 0x70 ... 0x7f: /* jcc Jb */
2358 val = (int8_t)insn_get(s, OT_BYTE); 2469 val = (int8_t)insn_get(s, OT_BYTE);
@@ -2367,7 +2478,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -2367,7 +2478,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2367 val += (long)s->pc; /* XXX: fix 16 bit wrap */ 2478 val += (long)s->pc; /* XXX: fix 16 bit wrap */
2368 do_jcc: 2479 do_jcc:
2369 gen_jcc(s, b, val); 2480 gen_jcc(s, b, val);
2370 - *is_jmp_ptr = 1; 2481 + s->is_jmp = 1;
2371 break; 2482 break;
2372 2483
2373 case 0x190 ... 0x19f: 2484 case 0x190 ... 0x19f:
@@ -2548,19 +2659,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -2548,19 +2659,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2548 break; 2659 break;
2549 case 0xcc: /* int3 */ 2660 case 0xcc: /* int3 */
2550 gen_op_int3((long)pc_start); 2661 gen_op_int3((long)pc_start);
2551 - *is_jmp_ptr = 1; 2662 + s->is_jmp = 1;
2552 break; 2663 break;
2553 case 0xcd: /* int N */ 2664 case 0xcd: /* int N */
2554 val = ldub(s->pc++); 2665 val = ldub(s->pc++);
2555 /* XXX: currently we ignore the interrupt number */ 2666 /* XXX: currently we ignore the interrupt number */
2556 gen_op_int_im((long)pc_start); 2667 gen_op_int_im((long)pc_start);
2557 - *is_jmp_ptr = 1; 2668 + s->is_jmp = 1;
2558 break; 2669 break;
2559 case 0xce: /* into */ 2670 case 0xce: /* into */
2560 if (s->cc_op != CC_OP_DYNAMIC) 2671 if (s->cc_op != CC_OP_DYNAMIC)
2561 gen_op_set_cc_op(s->cc_op); 2672 gen_op_set_cc_op(s->cc_op);
2562 gen_op_into((long)pc_start, (long)s->pc); 2673 gen_op_into((long)pc_start, (long)s->pc);
2563 - *is_jmp_ptr = 1; 2674 + s->is_jmp = 1;
2564 break; 2675 break;
2565 case 0x1c8 ... 0x1cf: /* bswap reg */ 2676 case 0x1c8 ... 0x1cf: /* bswap reg */
2566 reg = b & 7; 2677 reg = b & 7;
@@ -2586,38 +2697,43 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) @@ -2586,38 +2697,43 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2586 return -1; 2697 return -1;
2587 } 2698 }
2588 return (long)s->pc; 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 /* return the next pc */ 2705 /* return the next pc */
2592 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 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 DisasContext dc1, *dc = &dc1; 2710 DisasContext dc1, *dc = &dc1;
2596 uint8_t *gen_code_end, *pc_ptr; 2711 uint8_t *gen_code_end, *pc_ptr;
2597 - int is_jmp;  
2598 long ret; 2712 long ret;
2599 #ifdef DEBUG_DISAS 2713 #ifdef DEBUG_DISAS
2600 struct disassemble_info disasm_info; 2714 struct disassemble_info disasm_info;
2601 #endif 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 dc->cc_op = CC_OP_DYNAMIC; 2719 dc->cc_op = CC_OP_DYNAMIC;
2604 gen_code_ptr = gen_code_buf; 2720 gen_code_ptr = gen_code_buf;
2605 gen_code_end = gen_code_buf + max_code_size - 4096; 2721 gen_code_end = gen_code_buf + max_code_size - 4096;
2606 gen_start(); 2722 gen_start();
2607 2723
2608 - is_jmp = 0; 2724 + dc->is_jmp = 0;
2609 pc_ptr = pc_start; 2725 pc_ptr = pc_start;
2610 do { 2726 do {
2611 - ret = disas_insn(dc, pc_ptr, &is_jmp); 2727 + ret = disas_insn(dc, pc_ptr);
2612 if (ret == -1) 2728 if (ret == -1)
2613 error("unknown instruction at PC=0x%x B=%02x %02x", 2729 error("unknown instruction at PC=0x%x B=%02x %02x",
2614 pc_ptr, pc_ptr[0], pc_ptr[1]); 2730 pc_ptr, pc_ptr[0], pc_ptr[1]);
2615 pc_ptr = (void *)ret; 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 /* we must store the eflags state if it is not already done */ 2733 /* we must store the eflags state if it is not already done */
2618 if (dc->cc_op != CC_OP_DYNAMIC) 2734 if (dc->cc_op != CC_OP_DYNAMIC)
2619 gen_op_set_cc_op(dc->cc_op); 2735 gen_op_set_cc_op(dc->cc_op);
2620 - if (!is_jmp) { 2736 + if (dc->is_jmp != 1) {
2621 /* we add an additionnal jmp to update the simulated PC */ 2737 /* we add an additionnal jmp to update the simulated PC */
2622 gen_op_jmp_im(ret); 2738 gen_op_jmp_im(ret);
2623 } 2739 }