Commit 6dbad63eef5947c6c8750e44f408138779b6d0bb
1 parent
27362c82
added minimal segment support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@28 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
12 changed files
with
550 additions
and
103 deletions
TODO
| 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
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, ®_addr, &offset_addr); | 1733 | gen_lea_modrm(s, modrm, ®_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 | } |