Revision 6dbad63e
b/TODO | ||
---|---|---|
1 |
- daa/das |
|
2 |
- optimize translated cache chaining (DLL PLT like system) |
|
3 | 1 |
- segment ops (minimal LDT/GDT support for wine) |
2 |
- optimize translated cache chaining (DLL PLT like system) |
|
4 | 3 |
- improved 16 bit support |
5 | 4 |
- optimize inverse flags propagation (easy by generating intermediate |
6 | 5 |
micro operation array). |
b/cpu-i386.h | ||
---|---|---|
123 | 123 |
typedef double CPU86_LDouble; |
124 | 124 |
#endif |
125 | 125 |
|
126 |
typedef struct SegmentCache { |
|
127 |
uint8_t *base; |
|
128 |
unsigned long limit; |
|
129 |
uint8_t seg_32bit; |
|
130 |
} SegmentCache; |
|
131 |
|
|
132 |
typedef struct SegmentDescriptorTable { |
|
133 |
uint8_t *base; |
|
134 |
unsigned long limit; |
|
135 |
/* this is the returned base when reading the register, just to |
|
136 |
avoid that the emulated program modifies it */ |
|
137 |
unsigned long emu_base; |
|
138 |
} SegmentDescriptorTable; |
|
139 |
|
|
126 | 140 |
typedef struct CPUX86State { |
127 | 141 |
/* standard registers */ |
128 | 142 |
uint32_t regs[8]; |
... | ... | |
135 | 149 |
uint32_t cc_op; |
136 | 150 |
int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ |
137 | 151 |
|
138 |
/* segments */ |
|
139 |
uint8_t *segs_base[6]; |
|
140 |
|
|
141 | 152 |
/* FPU state */ |
142 | 153 |
unsigned int fpstt; /* top of stack index */ |
143 | 154 |
unsigned int fpus; |
... | ... | |
145 | 156 |
uint8_t fptags[8]; /* 0 = valid, 1 = empty */ |
146 | 157 |
CPU86_LDouble fpregs[8]; |
147 | 158 |
|
148 |
/* segments */ |
|
149 |
uint32_t segs[6]; |
|
150 |
|
|
151 | 159 |
/* emulator internal variables */ |
152 | 160 |
CPU86_LDouble ft0; |
153 | 161 |
|
162 |
/* segments */ |
|
163 |
uint32_t segs[6]; /* selector values */ |
|
164 |
SegmentCache seg_cache[6]; /* info taken from LDT/GDT */ |
|
165 |
SegmentDescriptorTable gdt; |
|
166 |
SegmentDescriptorTable ldt; |
|
167 |
SegmentDescriptorTable idt; |
|
168 |
|
|
169 |
/* various CPU modes */ |
|
170 |
int vm86; |
|
171 |
|
|
154 | 172 |
/* exception handling */ |
155 | 173 |
jmp_buf jmp_env; |
156 | 174 |
int exception_index; |
... | ... | |
241 | 259 |
int cpu_x86_exec(CPUX86State *s); |
242 | 260 |
void cpu_x86_close(CPUX86State *s); |
243 | 261 |
|
262 |
/* needed to load some predefinied segment registers */ |
|
263 |
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); |
|
264 |
|
|
244 | 265 |
/* internal functions */ |
266 |
|
|
267 |
#define GEN_FLAG_CODE32_SHIFT 0 |
|
268 |
#define GEN_FLAG_ADDSEG_SHIFT 1 |
|
269 |
#define GEN_FLAG_ST_SHIFT 2 |
|
245 | 270 |
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
246 |
int *gen_code_size_ptr, uint8_t *pc_start); |
|
271 |
int *gen_code_size_ptr, uint8_t *pc_start, |
|
272 |
int flags); |
|
247 | 273 |
void cpu_x86_tblocks_init(void); |
248 | 274 |
|
249 | 275 |
#endif /* CPU_I386_H */ |
b/exec-i386.c | ||
---|---|---|
36 | 36 |
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) |
37 | 37 |
#define CODE_GEN_HASH_BITS 15 |
38 | 38 |
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) |
39 |
|
|
39 | 40 |
typedef struct TranslationBlock { |
40 | 41 |
unsigned long pc; /* simulated PC corresponding to this block */ |
42 |
unsigned int flags; /* flags defining in which context the code was generated */ |
|
41 | 43 |
uint8_t *tc_ptr; /* pointer to the translated code */ |
42 | 44 |
struct TranslationBlock *hash_next; /* next matching block */ |
43 | 45 |
} TranslationBlock; |
... | ... | |
137 | 139 |
|
138 | 140 |
/* find a translation block in the translation cache. If not found, |
139 | 141 |
allocate a new one */ |
140 |
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc) |
|
142 |
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, |
|
143 |
unsigned int flags) |
|
141 | 144 |
{ |
142 | 145 |
TranslationBlock **ptb, *tb; |
143 | 146 |
unsigned int h; |
... | ... | |
148 | 151 |
tb = *ptb; |
149 | 152 |
if (!tb) |
150 | 153 |
break; |
151 |
if (tb->pc == pc) |
|
154 |
if (tb->pc == pc && tb->flags == flags)
|
|
152 | 155 |
return tb; |
153 | 156 |
ptb = &tb->hash_next; |
154 | 157 |
} |
... | ... | |
158 | 161 |
tb = &tbs[nb_tbs++]; |
159 | 162 |
*ptb = tb; |
160 | 163 |
tb->pc = pc; |
164 |
tb->flags = flags; |
|
161 | 165 |
tb->tc_ptr = NULL; |
162 | 166 |
tb->hash_next = NULL; |
163 | 167 |
return tb; |
... | ... | |
171 | 175 |
void (*gen_func)(void); |
172 | 176 |
TranslationBlock *tb; |
173 | 177 |
uint8_t *tc_ptr; |
174 |
|
|
178 |
unsigned int flags; |
|
179 |
|
|
175 | 180 |
/* first we save global registers */ |
176 | 181 |
saved_T0 = T0; |
177 | 182 |
saved_T1 = T1; |
... | ... | |
187 | 192 |
cpu_x86_dump_state(); |
188 | 193 |
} |
189 | 194 |
#endif |
190 |
tb = tb_find_and_alloc((unsigned long)env->pc); |
|
195 |
/* we compute the CPU state. We assume it will not |
|
196 |
change during the whole generated block. */ |
|
197 |
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; |
|
198 |
flags |= (((unsigned long)env->seg_cache[R_DS].base | |
|
199 |
(unsigned long)env->seg_cache[R_ES].base | |
|
200 |
(unsigned long)env->seg_cache[R_SS].base) != 0) << |
|
201 |
GEN_FLAG_ADDSEG_SHIFT; |
|
202 |
tb = tb_find_and_alloc((unsigned long)env->pc, flags); |
|
191 | 203 |
tc_ptr = tb->tc_ptr; |
192 | 204 |
if (!tb->tc_ptr) { |
193 | 205 |
/* if no translated code available, then translate it now */ |
194 | 206 |
tc_ptr = code_gen_ptr; |
195 | 207 |
cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, |
196 |
&code_gen_size, (uint8_t *)env->pc); |
|
208 |
&code_gen_size, (uint8_t *)env->pc, flags);
|
|
197 | 209 |
tb->tc_ptr = tc_ptr; |
198 | 210 |
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
199 | 211 |
} |
... | ... | |
211 | 223 |
env = saved_env; |
212 | 224 |
return ret; |
213 | 225 |
} |
226 |
|
|
227 |
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) |
|
228 |
{ |
|
229 |
CPUX86State *saved_env; |
|
230 |
|
|
231 |
saved_env = env; |
|
232 |
env = s; |
|
233 |
load_seg(seg_reg, selector); |
|
234 |
env = saved_env; |
|
235 |
} |
b/exec-i386.h | ||
---|---|---|
27 | 27 |
extern FILE *logfile; |
28 | 28 |
extern int loglevel; |
29 | 29 |
extern int fprintf(FILE *, const char *, ...); |
30 |
extern int printf(const char *, ...); |
|
30 | 31 |
|
31 | 32 |
#ifdef __i386__ |
32 | 33 |
register unsigned int T0 asm("ebx"); |
... | ... | |
103 | 104 |
} CCTable; |
104 | 105 |
|
105 | 106 |
extern CCTable cc_table[]; |
107 |
|
|
108 |
void load_seg(int seg_reg, int selector); |
b/linux-user/main.c | ||
---|---|---|
1 | 1 |
/* |
2 |
* emu main |
|
2 |
* gemu main
|
|
3 | 3 |
* |
4 | 4 |
* Copyright (c) 2003 Fabrice Bellard |
5 | 5 |
* |
... | ... | |
80 | 80 |
return 0; |
81 | 81 |
} |
82 | 82 |
|
83 |
/* default linux values for the selectors */ |
|
84 |
#define __USER_CS (0x23) |
|
85 |
#define __USER_DS (0x2B) |
|
83 | 86 |
|
84 |
/* XXX: currently we use LDT entries */ |
|
85 |
#define __USER_CS (0x23|4) |
|
86 |
#define __USER_DS (0x2B|4) |
|
87 |
void write_dt(void *ptr, unsigned long addr, unsigned long limit, |
|
88 |
int seg32_bit) |
|
89 |
{ |
|
90 |
unsigned int e1, e2, limit_in_pages; |
|
91 |
limit_in_pages = 0; |
|
92 |
if (limit > 0xffff) { |
|
93 |
limit = limit >> 12; |
|
94 |
limit_in_pages = 1; |
|
95 |
} |
|
96 |
e1 = (addr << 16) | (limit & 0xffff); |
|
97 |
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); |
|
98 |
e2 |= limit_in_pages << 23; /* byte granularity */ |
|
99 |
e2 |= seg32_bit << 22; /* 32 bit segment */ |
|
100 |
stl((uint8_t *)ptr, e1); |
|
101 |
stl((uint8_t *)ptr + 4, e2); |
|
102 |
} |
|
103 |
|
|
104 |
uint64_t gdt_table[6]; |
|
87 | 105 |
|
88 | 106 |
void usage(void) |
89 | 107 |
{ |
... | ... | |
94 | 112 |
exit(1); |
95 | 113 |
} |
96 | 114 |
|
115 |
|
|
116 |
|
|
97 | 117 |
int main(int argc, char **argv) |
98 | 118 |
{ |
99 | 119 |
const char *filename; |
... | ... | |
149 | 169 |
|
150 | 170 |
env = cpu_x86_init(); |
151 | 171 |
|
172 |
/* linux register setup */ |
|
152 | 173 |
env->regs[R_EAX] = regs->eax; |
153 | 174 |
env->regs[R_EBX] = regs->ebx; |
154 | 175 |
env->regs[R_ECX] = regs->ecx; |
... | ... | |
157 | 178 |
env->regs[R_EDI] = regs->edi; |
158 | 179 |
env->regs[R_EBP] = regs->ebp; |
159 | 180 |
env->regs[R_ESP] = regs->esp; |
160 |
env->segs[R_CS] = __USER_CS; |
|
161 |
env->segs[R_DS] = __USER_DS; |
|
162 |
env->segs[R_ES] = __USER_DS; |
|
163 |
env->segs[R_SS] = __USER_DS; |
|
164 |
env->segs[R_FS] = __USER_DS; |
|
165 |
env->segs[R_GS] = __USER_DS; |
|
166 | 181 |
env->pc = regs->eip; |
167 | 182 |
|
168 |
#if 0 |
|
169 |
LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; |
|
170 |
LDT[__USER_CS >> 3].dwSelLimit = 0xfffff; |
|
171 |
LDT[__USER_CS >> 3].lpSelBase = NULL; |
|
172 |
|
|
173 |
LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; |
|
174 |
LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; |
|
175 |
LDT[__USER_DS >> 3].lpSelBase = NULL; |
|
176 |
#endif |
|
183 |
/* linux segment setup */ |
|
184 |
env->gdt.base = (void *)gdt_table; |
|
185 |
env->gdt.limit = sizeof(gdt_table) - 1; |
|
186 |
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1); |
|
187 |
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1); |
|
188 |
cpu_x86_load_seg(env, R_CS, __USER_CS); |
|
189 |
cpu_x86_load_seg(env, R_DS, __USER_DS); |
|
190 |
cpu_x86_load_seg(env, R_ES, __USER_DS); |
|
191 |
cpu_x86_load_seg(env, R_SS, __USER_DS); |
|
192 |
cpu_x86_load_seg(env, R_FS, __USER_DS); |
|
193 |
cpu_x86_load_seg(env, R_GS, __USER_DS); |
|
177 | 194 |
|
178 | 195 |
for(;;) { |
179 | 196 |
int err; |
... | ... | |
186 | 203 |
if (pc[0] == 0xcd && pc[1] == 0x80) { |
187 | 204 |
/* syscall */ |
188 | 205 |
env->pc += 2; |
189 |
env->regs[R_EAX] = do_syscall(env->regs[R_EAX], |
|
206 |
env->regs[R_EAX] = do_syscall(env, |
|
207 |
env->regs[R_EAX], |
|
190 | 208 |
env->regs[R_EBX], |
191 | 209 |
env->regs[R_ECX], |
192 | 210 |
env->regs[R_EDX], |
b/linux-user/qemu.h | ||
---|---|---|
48 | 48 |
|
49 | 49 |
void target_set_brk(char *new_brk); |
50 | 50 |
void syscall_init(void); |
51 |
long do_syscall(int num, long arg1, long arg2, long arg3, |
|
51 |
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|
52 | 52 |
long arg4, long arg5, long arg6); |
53 | 53 |
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2))); |
54 | 54 |
|
b/linux-user/syscall.c | ||
---|---|---|
69 | 69 |
#include "syscall_defs.h" |
70 | 70 |
|
71 | 71 |
#ifdef TARGET_I386 |
72 |
#include "cpu-i386.h" |
|
72 | 73 |
#include "syscall-i386.h" |
73 | 74 |
#endif |
74 | 75 |
|
... | ... | |
607 | 608 |
.align = { __alignof__(struct target_termios), __alignof__(struct host_termios) }, |
608 | 609 |
}; |
609 | 610 |
|
611 |
#ifdef TARGET_I386 |
|
612 |
|
|
613 |
/* NOTE: there is really one LDT for all the threads */ |
|
614 |
uint8_t *ldt_table; |
|
615 |
|
|
616 |
static int read_ldt(void *ptr, unsigned long bytecount) |
|
617 |
{ |
|
618 |
int size; |
|
619 |
|
|
620 |
if (!ldt_table) |
|
621 |
return 0; |
|
622 |
size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE; |
|
623 |
if (size > bytecount) |
|
624 |
size = bytecount; |
|
625 |
memcpy(ptr, ldt_table, size); |
|
626 |
return size; |
|
627 |
} |
|
628 |
|
|
629 |
/* XXX: add locking support */ |
|
630 |
static int write_ldt(CPUX86State *env, |
|
631 |
void *ptr, unsigned long bytecount, int oldmode) |
|
632 |
{ |
|
633 |
struct target_modify_ldt_ldt_s ldt_info; |
|
634 |
int seg_32bit, contents, read_exec_only, limit_in_pages; |
|
635 |
int seg_not_present, useable; |
|
636 |
uint32_t *lp, entry_1, entry_2; |
|
637 |
|
|
638 |
if (bytecount != sizeof(ldt_info)) |
|
639 |
return -EINVAL; |
|
640 |
memcpy(&ldt_info, ptr, sizeof(ldt_info)); |
|
641 |
tswap32s(&ldt_info.entry_number); |
|
642 |
tswapls((long *)&ldt_info.base_addr); |
|
643 |
tswap32s(&ldt_info.limit); |
|
644 |
tswap32s(&ldt_info.flags); |
|
645 |
|
|
646 |
if (ldt_info.entry_number >= TARGET_LDT_ENTRIES) |
|
647 |
return -EINVAL; |
|
648 |
seg_32bit = ldt_info.flags & 1; |
|
649 |
contents = (ldt_info.flags >> 1) & 3; |
|
650 |
read_exec_only = (ldt_info.flags >> 3) & 1; |
|
651 |
limit_in_pages = (ldt_info.flags >> 4) & 1; |
|
652 |
seg_not_present = (ldt_info.flags >> 5) & 1; |
|
653 |
useable = (ldt_info.flags >> 6) & 1; |
|
654 |
|
|
655 |
if (contents == 3) { |
|
656 |
if (oldmode) |
|
657 |
return -EINVAL; |
|
658 |
if (seg_not_present == 0) |
|
659 |
return -EINVAL; |
|
660 |
} |
|
661 |
/* allocate the LDT */ |
|
662 |
if (!ldt_table) { |
|
663 |
ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); |
|
664 |
if (!ldt_table) |
|
665 |
return -ENOMEM; |
|
666 |
memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE); |
|
667 |
env->ldt.base = ldt_table; |
|
668 |
env->ldt.limit = 0xffff; |
|
669 |
} |
|
670 |
|
|
671 |
/* NOTE: same code as Linux kernel */ |
|
672 |
/* Allow LDTs to be cleared by the user. */ |
|
673 |
if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { |
|
674 |
if (oldmode || |
|
675 |
(contents == 0 && |
|
676 |
read_exec_only == 1 && |
|
677 |
seg_32bit == 0 && |
|
678 |
limit_in_pages == 0 && |
|
679 |
seg_not_present == 1 && |
|
680 |
useable == 0 )) { |
|
681 |
entry_1 = 0; |
|
682 |
entry_2 = 0; |
|
683 |
goto install; |
|
684 |
} |
|
685 |
} |
|
686 |
|
|
687 |
entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | |
|
688 |
(ldt_info.limit & 0x0ffff); |
|
689 |
entry_2 = (ldt_info.base_addr & 0xff000000) | |
|
690 |
((ldt_info.base_addr & 0x00ff0000) >> 16) | |
|
691 |
(ldt_info.limit & 0xf0000) | |
|
692 |
((read_exec_only ^ 1) << 9) | |
|
693 |
(contents << 10) | |
|
694 |
((seg_not_present ^ 1) << 15) | |
|
695 |
(seg_32bit << 22) | |
|
696 |
(limit_in_pages << 23) | |
|
697 |
0x7000; |
|
698 |
if (!oldmode) |
|
699 |
entry_2 |= (useable << 20); |
|
700 |
|
|
701 |
/* Install the new entry ... */ |
|
702 |
install: |
|
703 |
lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3)); |
|
704 |
lp[0] = tswap32(entry_1); |
|
705 |
lp[1] = tswap32(entry_2); |
|
706 |
return 0; |
|
707 |
} |
|
708 |
|
|
709 |
/* specific and weird i386 syscalls */ |
|
710 |
int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount) |
|
711 |
{ |
|
712 |
int ret = -ENOSYS; |
|
713 |
|
|
714 |
switch (func) { |
|
715 |
case 0: |
|
716 |
ret = read_ldt(ptr, bytecount); |
|
717 |
break; |
|
718 |
case 1: |
|
719 |
ret = write_ldt(env, ptr, bytecount, 1); |
|
720 |
break; |
|
721 |
case 0x11: |
|
722 |
ret = write_ldt(env, ptr, bytecount, 0); |
|
723 |
break; |
|
724 |
} |
|
725 |
return ret; |
|
726 |
} |
|
727 |
#endif |
|
728 |
|
|
610 | 729 |
void syscall_init(void) |
611 | 730 |
{ |
612 | 731 |
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); |
... | ... | |
616 | 735 |
#undef STRUCT_SPECIAL |
617 | 736 |
} |
618 | 737 |
|
619 |
long do_syscall(int num, long arg1, long arg2, long arg3, |
|
738 |
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
|
620 | 739 |
long arg4, long arg5, long arg6) |
621 | 740 |
{ |
622 | 741 |
long ret; |
... | ... | |
1095 | 1214 |
/* no need to transcode because we use the linux syscall */ |
1096 | 1215 |
ret = get_errno(sys_uname((struct new_utsname *)arg1)); |
1097 | 1216 |
break; |
1217 |
#ifdef TARGET_I386 |
|
1098 | 1218 |
case TARGET_NR_modify_ldt: |
1099 |
goto unimplemented; |
|
1219 |
ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3)); |
|
1220 |
break; |
|
1221 |
#endif |
|
1100 | 1222 |
case TARGET_NR_adjtimex: |
1101 | 1223 |
goto unimplemented; |
1102 | 1224 |
case TARGET_NR_mprotect: |
b/linux-user/syscall_types.h | ||
---|---|---|
61 | 61 |
|
62 | 62 |
STRUCT(hd_geometry, |
63 | 63 |
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG) |
64 |
|
b/op-i386.c | ||
---|---|---|
858 | 858 |
CC_SRC = eflags; |
859 | 859 |
} |
860 | 860 |
|
861 |
/* segment handling */ |
|
862 |
|
|
863 |
void load_seg(int seg_reg, int selector) |
|
864 |
{ |
|
865 |
SegmentCache *sc; |
|
866 |
SegmentDescriptorTable *dt; |
|
867 |
int index; |
|
868 |
uint32_t e1, e2; |
|
869 |
uint8_t *ptr; |
|
870 |
|
|
871 |
env->segs[seg_reg] = selector; |
|
872 |
sc = &env->seg_cache[seg_reg]; |
|
873 |
if (env->vm86) { |
|
874 |
sc->base = (void *)(selector << 4); |
|
875 |
sc->limit = 0xffff; |
|
876 |
sc->seg_32bit = 0; |
|
877 |
} else { |
|
878 |
if (selector & 0x4) |
|
879 |
dt = &env->ldt; |
|
880 |
else |
|
881 |
dt = &env->gdt; |
|
882 |
index = selector & ~7; |
|
883 |
if ((index + 7) > dt->limit) |
|
884 |
raise_exception(EXCP0D_GPF); |
|
885 |
ptr = dt->base + index; |
|
886 |
e1 = ldl(ptr); |
|
887 |
e2 = ldl(ptr + 4); |
|
888 |
sc->base = (void *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
|
889 |
sc->limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
|
890 |
if (e2 & (1 << 23)) |
|
891 |
sc->limit = (sc->limit << 12) | 0xfff; |
|
892 |
sc->seg_32bit = (e2 >> 22) & 1; |
|
893 |
#if 0 |
|
894 |
fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx seg_32bit=%d\n", |
|
895 |
selector, (unsigned long)sc->base, sc->limit, sc->seg_32bit); |
|
896 |
#endif |
|
897 |
} |
|
898 |
} |
|
899 |
|
|
900 |
void OPPROTO op_movl_seg_T0(void) |
|
901 |
{ |
|
902 |
load_seg(PARAM1, T0 & 0xffff); |
|
903 |
} |
|
904 |
|
|
905 |
void OPPROTO op_movl_T0_seg(void) |
|
906 |
{ |
|
907 |
T0 = env->segs[PARAM1]; |
|
908 |
} |
|
909 |
|
|
910 |
void OPPROTO op_addl_A0_seg(void) |
|
911 |
{ |
|
912 |
A0 += *(unsigned long *)((char *)env + PARAM1); |
|
913 |
} |
|
914 |
|
|
861 | 915 |
/* flags handling */ |
862 | 916 |
|
863 | 917 |
/* slow jumps cases (compute x86 flags) */ |
b/syscall-i386.h | ||
---|---|---|
758 | 758 |
#define TARGET_SOUND_MIXER_WRITE_ENHANCE 0xc0044d1f |
759 | 759 |
#define TARGET_SOUND_MIXER_WRITE_LOUD 0xc0044d1f |
760 | 760 |
#define TARGET_SOUND_MIXER_WRITE_RECSRC 0xc0044dff |
761 |
|
|
762 |
#define TARGET_LDT_ENTRIES 8192 |
|
763 |
#define TARGET_LDT_ENTRY_SIZE 8 |
|
764 |
|
|
765 |
struct target_modify_ldt_ldt_s { |
|
766 |
unsigned int entry_number; |
|
767 |
target_ulong base_addr; |
|
768 |
unsigned int limit; |
|
769 |
unsigned int flags; |
|
770 |
}; |
|
771 |
|
b/tests/test-i386.c | ||
---|---|---|
1 | 1 |
#include <stdlib.h> |
2 | 2 |
#include <stdio.h> |
3 |
#include <inttypes.h> |
|
3 | 4 |
#include <math.h> |
4 | 5 |
|
5 | 6 |
#define xglue(x, y) x ## y |
... | ... | |
612 | 613 |
TEST_BCD(aad, 0x12340407, CC_A, (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)); |
613 | 614 |
} |
614 | 615 |
|
616 |
/**********************************************/ |
|
617 |
/* segmentation tests */ |
|
618 |
|
|
619 |
#include <asm/ldt.h> |
|
620 |
#include <linux/unistd.h> |
|
621 |
|
|
622 |
_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount) |
|
623 |
|
|
624 |
uint8_t seg_data1[4096]; |
|
625 |
uint8_t seg_data2[4096]; |
|
626 |
|
|
627 |
#define MK_SEL(n) (((n) << 3) | 4) |
|
628 |
|
|
629 |
/* NOTE: we use Linux modify_ldt syscall */ |
|
630 |
void test_segs(void) |
|
631 |
{ |
|
632 |
struct modify_ldt_ldt_s ldt; |
|
633 |
long long ldt_table[3]; |
|
634 |
int i, res, res2; |
|
635 |
char tmp; |
|
636 |
|
|
637 |
ldt.entry_number = 1; |
|
638 |
ldt.base_addr = (unsigned long)&seg_data1; |
|
639 |
ldt.limit = (sizeof(seg_data1) + 0xfff) >> 12; |
|
640 |
ldt.seg_32bit = 1; |
|
641 |
ldt.contents = MODIFY_LDT_CONTENTS_DATA; |
|
642 |
ldt.read_exec_only = 0; |
|
643 |
ldt.limit_in_pages = 1; |
|
644 |
ldt.seg_not_present = 0; |
|
645 |
ldt.useable = 1; |
|
646 |
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ |
|
647 |
|
|
648 |
ldt.entry_number = 2; |
|
649 |
ldt.base_addr = (unsigned long)&seg_data2; |
|
650 |
ldt.limit = (sizeof(seg_data2) + 0xfff) >> 12; |
|
651 |
ldt.seg_32bit = 1; |
|
652 |
ldt.contents = MODIFY_LDT_CONTENTS_DATA; |
|
653 |
ldt.read_exec_only = 0; |
|
654 |
ldt.limit_in_pages = 1; |
|
655 |
ldt.seg_not_present = 0; |
|
656 |
ldt.useable = 1; |
|
657 |
modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */ |
|
658 |
|
|
659 |
modify_ldt(0, &ldt_table, sizeof(ldt_table)); /* read ldt entries */ |
|
660 |
for(i=0;i<3;i++) |
|
661 |
printf("%d: %016Lx\n", i, ldt_table[i]); |
|
662 |
|
|
663 |
/* do some tests with fs or gs */ |
|
664 |
asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1))); |
|
665 |
asm volatile ("movl %0, %%gs" : : "r" (MK_SEL(2))); |
|
666 |
|
|
667 |
seg_data1[1] = 0xaa; |
|
668 |
seg_data2[1] = 0x55; |
|
669 |
|
|
670 |
asm volatile ("fs movzbl 0x1, %0" : "=r" (res)); |
|
671 |
printf("FS[1] = %02x\n", res); |
|
672 |
|
|
673 |
asm volatile ("gs movzbl 0x1, %0" : "=r" (res)); |
|
674 |
printf("GS[1] = %02x\n", res); |
|
675 |
|
|
676 |
/* tests with ds/ss (implicit segment case) */ |
|
677 |
tmp = 0xa5; |
|
678 |
asm volatile ("pushl %%ebp\n\t" |
|
679 |
"pushl %%ds\n\t" |
|
680 |
"movl %2, %%ds\n\t" |
|
681 |
"movl %3, %%ebp\n\t" |
|
682 |
"movzbl 0x1, %0\n\t" |
|
683 |
"movzbl (%%ebp), %1\n\t" |
|
684 |
"popl %%ds\n\t" |
|
685 |
"popl %%ebp\n\t" |
|
686 |
: "=r" (res), "=r" (res2) |
|
687 |
: "r" (MK_SEL(1)), "r" (&tmp)); |
|
688 |
printf("DS[1] = %02x\n", res); |
|
689 |
printf("SS[tmp] = %02x\n", res2); |
|
690 |
} |
|
615 | 691 |
|
616 | 692 |
static void *call_end __init_call = NULL; |
617 | 693 |
|
... | ... | |
628 | 704 |
test_bsx(); |
629 | 705 |
test_mul(); |
630 | 706 |
test_jcc(); |
631 |
test_lea(); |
|
632 | 707 |
test_floats(); |
633 | 708 |
test_bcd(); |
709 |
test_lea(); |
|
710 |
test_segs(); |
|
634 | 711 |
return 0; |
635 | 712 |
} |
b/translate-i386.c | ||
---|---|---|
34 | 34 |
#include "dis-asm.h" |
35 | 35 |
#endif |
36 | 36 |
|
37 |
#ifndef offsetof |
|
38 |
#define offsetof(type, field) ((size_t) &((type *)0)->field) |
|
39 |
#endif |
|
40 |
|
|
37 | 41 |
static uint8_t *gen_code_ptr; |
38 | 42 |
int __op_param1, __op_param2, __op_param3; |
39 | 43 |
|
... | ... | |
71 | 75 |
int prefix; |
72 | 76 |
int aflag, dflag; |
73 | 77 |
uint8_t *pc; /* current pc */ |
74 |
int cc_op; /* current CC operation */ |
|
75 |
int f_st; |
|
78 |
int is_jmp; /* 1 = means jump (stop translation), 2 means CPU |
|
79 |
static state change (stop translation) */ |
|
80 |
/* current block context */ |
|
81 |
int code32; /* 32 bit code segment */ |
|
82 |
int cc_op; /* current CC operation */ |
|
83 |
int addseg; /* non zero if either DS/ES/SS have a non zero base */ |
|
84 |
int f_st; /* currently unused */ |
|
76 | 85 |
} DisasContext; |
77 | 86 |
|
78 | 87 |
/* i386 arith/logic operations */ |
... | ... | |
763 | 772 |
static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) |
764 | 773 |
{ |
765 | 774 |
int havesib; |
766 |
int havebase; |
|
767 | 775 |
int base, disp; |
768 |
int index = 0; |
|
769 |
int scale = 0; |
|
770 |
int reg1, reg2, opreg; |
|
771 |
int mod, rm, code; |
|
776 |
int index; |
|
777 |
int scale; |
|
778 |
int opreg; |
|
779 |
int mod, rm, code, override, must_add_seg; |
|
780 |
|
|
781 |
/* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */ |
|
782 |
/* XXX: fix lea case */ |
|
783 |
override = -1; |
|
784 |
must_add_seg = s->addseg; |
|
785 |
if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS | |
|
786 |
PREFIX_ES | PREFIX_FS | PREFIX_GS)) { |
|
787 |
if (s->prefix & PREFIX_ES) |
|
788 |
override = R_ES; |
|
789 |
else if (s->prefix & PREFIX_CS) |
|
790 |
override = R_CS; |
|
791 |
else if (s->prefix & PREFIX_SS) |
|
792 |
override = R_SS; |
|
793 |
else if (s->prefix & PREFIX_DS) |
|
794 |
override = R_DS; |
|
795 |
else if (s->prefix & PREFIX_FS) |
|
796 |
override = R_FS; |
|
797 |
else |
|
798 |
override = R_GS; |
|
799 |
must_add_seg = 1; |
|
800 |
} |
|
772 | 801 |
|
773 | 802 |
mod = (modrm >> 6) & 3; |
774 | 803 |
rm = modrm & 7; |
... | ... | |
776 | 805 |
if (s->aflag) { |
777 | 806 |
|
778 | 807 |
havesib = 0; |
779 |
havebase = 1; |
|
780 | 808 |
base = rm; |
809 |
index = 0; |
|
810 |
scale = 0; |
|
781 | 811 |
|
782 | 812 |
if (base == 4) { |
783 | 813 |
havesib = 1; |
... | ... | |
790 | 820 |
switch (mod) { |
791 | 821 |
case 0: |
792 | 822 |
if (base == 5) { |
793 |
havebase = 0;
|
|
823 |
base = -1;
|
|
794 | 824 |
disp = ldl(s->pc); |
795 | 825 |
s->pc += 4; |
796 | 826 |
} else { |
... | ... | |
806 | 836 |
s->pc += 4; |
807 | 837 |
break; |
808 | 838 |
} |
809 |
|
|
810 |
reg1 = OR_ZERO; |
|
811 |
reg2 = OR_ZERO; |
|
812 |
|
|
813 |
if (havebase || (havesib && (index != 4 || scale != 0))) { |
|
814 |
if (havebase) |
|
815 |
reg1 = OR_EAX + base; |
|
816 |
if (havesib && index != 4) { |
|
817 |
if (havebase) |
|
818 |
reg2 = index + OR_EAX; |
|
819 |
else |
|
820 |
reg1 = index + OR_EAX; |
|
821 |
} |
|
822 |
} |
|
823 |
/* XXX: disp only ? */ |
|
824 |
if (reg2 == OR_ZERO) { |
|
825 |
/* op: disp + (reg1 << scale) */ |
|
826 |
if (reg1 == OR_ZERO) { |
|
827 |
gen_op_movl_A0_im(disp); |
|
828 |
} else if (scale == 0 && disp == 0) { |
|
829 |
gen_op_movl_A0_reg[reg1](); |
|
830 |
} else { |
|
831 |
gen_op_movl_A0_im(disp); |
|
832 |
gen_op_addl_A0_reg_sN[scale][reg1](); |
|
833 |
} |
|
839 |
|
|
840 |
if (base >= 0) { |
|
841 |
gen_op_movl_A0_reg[base](); |
|
842 |
if (disp != 0) |
|
843 |
gen_op_addl_A0_im(disp); |
|
834 | 844 |
} else { |
835 |
/* op: disp + reg1 + (reg2 << scale) */ |
|
836 |
if (disp != 0) { |
|
837 |
gen_op_movl_A0_im(disp); |
|
838 |
gen_op_addl_A0_reg_sN[0][reg1](); |
|
839 |
} else { |
|
840 |
gen_op_movl_A0_reg[reg1](); |
|
845 |
gen_op_movl_A0_im(disp); |
|
846 |
} |
|
847 |
if (havesib && (index != 4 || scale != 0)) { |
|
848 |
gen_op_addl_A0_reg_sN[scale][index](); |
|
849 |
} |
|
850 |
if (must_add_seg) { |
|
851 |
if (override < 0) { |
|
852 |
if (base == R_EBP || base == R_ESP) |
|
853 |
override = R_SS; |
|
854 |
else |
|
855 |
override = R_DS; |
|
841 | 856 |
} |
842 |
gen_op_addl_A0_reg_sN[scale][reg2]();
|
|
857 |
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
|
|
843 | 858 |
} |
844 | 859 |
} else { |
845 | 860 |
switch (mod) { |
... | ... | |
848 | 863 |
disp = lduw(s->pc); |
849 | 864 |
s->pc += 2; |
850 | 865 |
gen_op_movl_A0_im(disp); |
866 |
rm = 0; /* avoid SS override */ |
|
851 | 867 |
goto no_rm; |
852 | 868 |
} else { |
853 | 869 |
disp = 0; |
... | ... | |
896 | 912 |
if (disp != 0) |
897 | 913 |
gen_op_addl_A0_im(disp); |
898 | 914 |
gen_op_andl_A0_ffff(); |
899 |
no_rm: ; |
|
915 |
no_rm: |
|
916 |
if (must_add_seg) { |
|
917 |
if (override < 0) { |
|
918 |
if (rm == 2 || rm == 3 || rm == 6) |
|
919 |
override = R_SS; |
|
920 |
else |
|
921 |
override = R_DS; |
|
922 |
} |
|
923 |
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base)); |
|
924 |
} |
|
900 | 925 |
} |
926 |
|
|
901 | 927 |
opreg = OR_A0; |
902 | 928 |
disp = 0; |
903 | 929 |
*reg_ptr = opreg; |
... | ... | |
1082 | 1108 |
} |
1083 | 1109 |
} |
1084 | 1110 |
|
1111 |
/* move T0 to seg_reg and compute if the CPU state may change */ |
|
1112 |
void gen_movl_seg_T0(DisasContext *s, int seg_reg) |
|
1113 |
{ |
|
1114 |
gen_op_movl_seg_T0(seg_reg); |
|
1115 |
if (!s->addseg && seg_reg < R_FS) |
|
1116 |
s->is_jmp = 2; /* abort translation because the register may |
|
1117 |
have a non zero base */ |
|
1118 |
} |
|
1119 |
|
|
1085 | 1120 |
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr |
1086 | 1121 |
is set to true if the instruction sets the PC (last instruction of |
1087 | 1122 |
a basic block) */ |
1088 |
long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
|
|
1123 |
long disas_insn(DisasContext *s, uint8_t *pc_start) |
|
1089 | 1124 |
{ |
1090 | 1125 |
int b, prefixes, aflag, dflag; |
1091 | 1126 |
int shift, ot; |
... | ... | |
1093 | 1128 |
|
1094 | 1129 |
s->pc = pc_start; |
1095 | 1130 |
prefixes = 0; |
1096 |
aflag = 1;
|
|
1097 |
dflag = 1;
|
|
1131 |
aflag = s->code32;
|
|
1132 |
dflag = s->code32;
|
|
1098 | 1133 |
// cur_pc = s->pc; /* for insn generation */ |
1099 | 1134 |
next_byte: |
1100 | 1135 |
b = ldub(s->pc); |
... | ... | |
1416 | 1451 |
gen_op_movl_T1_im((long)s->pc); |
1417 | 1452 |
gen_op_pushl_T1(); |
1418 | 1453 |
gen_op_jmp_T0(); |
1419 |
*is_jmp_ptr = 1;
|
|
1454 |
s->is_jmp = 1;
|
|
1420 | 1455 |
break; |
1421 | 1456 |
case 4: /* jmp Ev */ |
1422 | 1457 |
gen_op_jmp_T0(); |
1423 |
*is_jmp_ptr = 1;
|
|
1458 |
s->is_jmp = 1;
|
|
1424 | 1459 |
break; |
1425 | 1460 |
case 6: /* push Ev */ |
1426 | 1461 |
gen_op_pushl_T0(); |
... | ... | |
1555 | 1590 |
gen_op_popl_T0(); |
1556 | 1591 |
gen_op_mov_reg_T0[OT_LONG][R_EBP](); |
1557 | 1592 |
break; |
1593 |
case 0x06: /* push es */ |
|
1594 |
case 0x0e: /* push cs */ |
|
1595 |
case 0x16: /* push ss */ |
|
1596 |
case 0x1e: /* push ds */ |
|
1597 |
gen_op_movl_T0_seg(b >> 3); |
|
1598 |
gen_op_pushl_T0(); |
|
1599 |
break; |
|
1600 |
case 0x1a0: /* push fs */ |
|
1601 |
case 0x1a8: /* push gs */ |
|
1602 |
gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS); |
|
1603 |
gen_op_pushl_T0(); |
|
1604 |
break; |
|
1605 |
case 0x07: /* pop es */ |
|
1606 |
case 0x17: /* pop ss */ |
|
1607 |
case 0x1f: /* pop ds */ |
|
1608 |
gen_op_popl_T0(); |
|
1609 |
gen_movl_seg_T0(s, b >> 3); |
|
1610 |
break; |
|
1611 |
case 0x1a1: /* pop fs */ |
|
1612 |
case 0x1a9: /* pop gs */ |
|
1613 |
gen_op_popl_T0(); |
|
1614 |
gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS); |
|
1615 |
break; |
|
1616 |
|
|
1558 | 1617 |
/**************************/ |
1559 | 1618 |
/* mov */ |
1560 | 1619 |
case 0x88: |
... | ... | |
1598 | 1657 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
1599 | 1658 |
gen_op_mov_reg_T0[ot][reg](); |
1600 | 1659 |
break; |
1660 |
case 0x8e: /* mov seg, Gv */ |
|
1661 |
ot = dflag ? OT_LONG : OT_WORD; |
|
1662 |
modrm = ldub(s->pc++); |
|
1663 |
reg = (modrm >> 3) & 7; |
|
1664 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
|
1665 |
if (reg >= 6) |
|
1666 |
goto illegal_op; |
|
1667 |
gen_movl_seg_T0(s, reg); |
|
1668 |
break; |
|
1669 |
case 0x8c: /* mov Gv, seg */ |
|
1670 |
ot = dflag ? OT_LONG : OT_WORD; |
|
1671 |
modrm = ldub(s->pc++); |
|
1672 |
reg = (modrm >> 3) & 7; |
|
1673 |
if (reg >= 6) |
|
1674 |
goto illegal_op; |
|
1675 |
gen_op_movl_T0_seg(reg); |
|
1676 |
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
|
1677 |
break; |
|
1601 | 1678 |
|
1602 | 1679 |
case 0x1b6: /* movzbS Gv, Eb */ |
1603 | 1680 |
case 0x1b7: /* movzwS Gv, Eb */ |
... | ... | |
1648 | 1725 |
ot = dflag ? OT_LONG : OT_WORD; |
1649 | 1726 |
modrm = ldub(s->pc++); |
1650 | 1727 |
reg = (modrm >> 3) & 7; |
1651 |
|
|
1728 |
/* we must ensure that no segment is added */ |
|
1729 |
s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS | |
|
1730 |
PREFIX_ES | PREFIX_FS | PREFIX_GS); |
|
1731 |
val = s->addseg; |
|
1732 |
s->addseg = 0; |
|
1652 | 1733 |
gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
1734 |
s->addseg = val; |
|
1653 | 1735 |
gen_op_mov_reg_A0[ot - OT_WORD][reg](); |
1654 | 1736 |
break; |
1655 | 1737 |
|
... | ... | |
1711 | 1793 |
gen_op_st_T0_A0[ot](); |
1712 | 1794 |
gen_op_mov_reg_T1[ot][reg](); |
1713 | 1795 |
break; |
1796 |
case 0xc4: /* les Gv */ |
|
1797 |
op = R_ES; |
|
1798 |
goto do_lxx; |
|
1799 |
case 0xc5: /* lds Gv */ |
|
1800 |
op = R_DS; |
|
1801 |
goto do_lxx; |
|
1802 |
case 0x1b2: /* lss Gv */ |
|
1803 |
op = R_SS; |
|
1804 |
goto do_lxx; |
|
1805 |
case 0x1b4: /* lfs Gv */ |
|
1806 |
op = R_FS; |
|
1807 |
goto do_lxx; |
|
1808 |
case 0x1b5: /* lgs Gv */ |
|
1809 |
op = R_GS; |
|
1810 |
do_lxx: |
|
1811 |
ot = dflag ? OT_LONG : OT_WORD; |
|
1812 |
modrm = ldub(s->pc++); |
|
1813 |
reg = (modrm >> 3) & 7; |
|
1814 |
mod = (modrm >> 6) & 3; |
|
1815 |
if (mod == 3) |
|
1816 |
goto illegal_op; |
|
1817 |
gen_op_ld_T1_A0[ot](); |
|
1818 |
op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
|
1819 |
/* load the segment first to handle exceptions properly */ |
|
1820 |
gen_op_lduw_T0_A0(); |
|
1821 |
gen_movl_seg_T0(s, op); |
|
1822 |
/* then put the data */ |
|
1823 |
gen_op_mov_reg_T1[ot][reg](); |
|
1824 |
break; |
|
1714 | 1825 |
|
1715 | 1826 |
/************************/ |
1716 | 1827 |
/* shifts */ |
... | ... | |
2327 | 2438 |
gen_op_popl_T0(); |
2328 | 2439 |
gen_op_addl_ESP_im(val); |
2329 | 2440 |
gen_op_jmp_T0(); |
2330 |
*is_jmp_ptr = 1;
|
|
2441 |
s->is_jmp = 1;
|
|
2331 | 2442 |
break; |
2332 | 2443 |
case 0xc3: /* ret */ |
2333 | 2444 |
gen_op_popl_T0(); |
2334 | 2445 |
gen_op_jmp_T0(); |
2335 |
*is_jmp_ptr = 1;
|
|
2446 |
s->is_jmp = 1;
|
|
2336 | 2447 |
break; |
2337 | 2448 |
case 0xe8: /* call */ |
2338 | 2449 |
val = insn_get(s, OT_LONG); |
... | ... | |
2340 | 2451 |
gen_op_movl_T1_im((long)s->pc); |
2341 | 2452 |
gen_op_pushl_T1(); |
2342 | 2453 |
gen_op_jmp_im(val); |
2343 |
*is_jmp_ptr = 1;
|
|
2454 |
s->is_jmp = 1;
|
|
2344 | 2455 |
break; |
2345 | 2456 |
case 0xe9: /* jmp */ |
2346 | 2457 |
val = insn_get(s, OT_LONG); |
2347 | 2458 |
val += (long)s->pc; |
2348 | 2459 |
gen_op_jmp_im(val); |
2349 |
*is_jmp_ptr = 1;
|
|
2460 |
s->is_jmp = 1;
|
|
2350 | 2461 |
break; |
2351 | 2462 |
case 0xeb: /* jmp Jb */ |
2352 | 2463 |
val = (int8_t)insn_get(s, OT_BYTE); |
2353 | 2464 |
val += (long)s->pc; |
2354 | 2465 |
gen_op_jmp_im(val); |
2355 |
*is_jmp_ptr = 1;
|
|
2466 |
s->is_jmp = 1;
|
|
2356 | 2467 |
break; |
2357 | 2468 |
case 0x70 ... 0x7f: /* jcc Jb */ |
2358 | 2469 |
val = (int8_t)insn_get(s, OT_BYTE); |
... | ... | |
2367 | 2478 |
val += (long)s->pc; /* XXX: fix 16 bit wrap */ |
2368 | 2479 |
do_jcc: |
2369 | 2480 |
gen_jcc(s, b, val); |
2370 |
*is_jmp_ptr = 1;
|
|
2481 |
s->is_jmp = 1;
|
|
2371 | 2482 |
break; |
2372 | 2483 |
|
2373 | 2484 |
case 0x190 ... 0x19f: |
... | ... | |
2548 | 2659 |
break; |
2549 | 2660 |
case 0xcc: /* int3 */ |
2550 | 2661 |
gen_op_int3((long)pc_start); |
2551 |
*is_jmp_ptr = 1;
|
|
2662 |
s->is_jmp = 1;
|
|
2552 | 2663 |
break; |
2553 | 2664 |
case 0xcd: /* int N */ |
2554 | 2665 |
val = ldub(s->pc++); |
2555 | 2666 |
/* XXX: currently we ignore the interrupt number */ |
2556 | 2667 |
gen_op_int_im((long)pc_start); |
2557 |
*is_jmp_ptr = 1;
|
|
2668 |
s->is_jmp = 1;
|
|
2558 | 2669 |
break; |
2559 | 2670 |
case 0xce: /* into */ |
2560 | 2671 |
if (s->cc_op != CC_OP_DYNAMIC) |
2561 | 2672 |
gen_op_set_cc_op(s->cc_op); |
2562 | 2673 |
gen_op_into((long)pc_start, (long)s->pc); |
2563 |
*is_jmp_ptr = 1;
|
|
2674 |
s->is_jmp = 1;
|
|
2564 | 2675 |
break; |
2565 | 2676 |
case 0x1c8 ... 0x1cf: /* bswap reg */ |
2566 | 2677 |
reg = b & 7; |
... | ... | |
2586 | 2697 |
return -1; |
2587 | 2698 |
} |
2588 | 2699 |
return (long)s->pc; |
2700 |
illegal_op: |
|
2701 |
error("illegal opcode pc=0x%08Lx", (long)pc_start); |
|
2702 |
return -1; |
|
2589 | 2703 |
} |
2590 | 2704 |
|
2591 | 2705 |
/* return the next pc */ |
2592 | 2706 |
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, |
2593 |
int *gen_code_size_ptr, uint8_t *pc_start) |
|
2707 |
int *gen_code_size_ptr, uint8_t *pc_start, |
|
2708 |
int flags) |
|
2594 | 2709 |
{ |
2595 | 2710 |
DisasContext dc1, *dc = &dc1; |
2596 | 2711 |
uint8_t *gen_code_end, *pc_ptr; |
2597 |
int is_jmp; |
|
2598 | 2712 |
long ret; |
2599 | 2713 |
#ifdef DEBUG_DISAS |
2600 | 2714 |
struct disassemble_info disasm_info; |
2601 | 2715 |
#endif |
2602 |
|
|
2716 |
dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; |
|
2717 |
dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
|
2718 |
dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; |
|
2603 | 2719 |
dc->cc_op = CC_OP_DYNAMIC; |
2604 | 2720 |
gen_code_ptr = gen_code_buf; |
2605 | 2721 |
gen_code_end = gen_code_buf + max_code_size - 4096; |
2606 | 2722 |
gen_start(); |
2607 | 2723 |
|
2608 |
is_jmp = 0; |
|
2724 |
dc->is_jmp = 0;
|
|
2609 | 2725 |
pc_ptr = pc_start; |
2610 | 2726 |
do { |
2611 |
ret = disas_insn(dc, pc_ptr, &is_jmp);
|
|
2727 |
ret = disas_insn(dc, pc_ptr); |
|
2612 | 2728 |
if (ret == -1) |
2613 | 2729 |
error("unknown instruction at PC=0x%x B=%02x %02x", |
2614 | 2730 |
pc_ptr, pc_ptr[0], pc_ptr[1]); |
2615 | 2731 |
pc_ptr = (void *)ret; |
2616 |
} while (!is_jmp && gen_code_ptr < gen_code_end); |
|
2732 |
} while (!dc->is_jmp && gen_code_ptr < gen_code_end);
|
|
2617 | 2733 |
/* we must store the eflags state if it is not already done */ |
2618 | 2734 |
if (dc->cc_op != CC_OP_DYNAMIC) |
2619 | 2735 |
gen_op_set_cc_op(dc->cc_op); |
2620 |
if (!is_jmp) {
|
|
2736 |
if (dc->is_jmp != 1) {
|
|
2621 | 2737 |
/* we add an additionnal jmp to update the simulated PC */ |
2622 | 2738 |
gen_op_jmp_im(ret); |
2623 | 2739 |
} |
Also available in: Unified diff