Compare commits

...
16 Commits
Author SHA1 Message Date
bellard f6630e791b version
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@62 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:57:48 +00:00
bellard 168485b75b wine help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@61 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:57:34 +00:00
bellard 5cd4393b14 first vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@60 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:54:36 +00:00
bellard 7ed601b782 more syscalls
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@59 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:54:05 +00:00
bellard d1f2367bc0 changed flag names
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@58 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:53:34 +00:00
bellard 851e67a1b4 primitive vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@57 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:53:14 +00:00
bellard fc2b4c4879 eflags update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@56 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:52:44 +00:00
bellard 9c605cb135 added cmpxchg8b, cpuid, bound, eflags support, vm86 mode, 16bit/override string ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@55 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:51:35 +00:00
bellard 24f9e90b0e 16bit/override support in string operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@54 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:50:40 +00:00
bellard a4a0ffdb2b added cmpxchg8b, cpuid, bound, eflags support, vm86 mode
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@53 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:49:21 +00:00
bellard 0ea00c9a3c added number of arguments
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@52 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:47:34 +00:00
bellard e1d4294a45 more tests
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@51 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:45:07 +00:00
bellard c3c7c29246 added runcom
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@50 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:44:42 +00:00
bellard 31bb950be6 xchg lock, xlat instr
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@49 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-26 22:33:47 +00:00
bellard 8083a3e508 dirent fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@48 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-24 23:12:16 +00:00
bellard 644c433cb3 ld.so load fix
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@47 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-24 23:00:36 +00:00
19 changed files with 1907 additions and 1027 deletions

No files matched your search

+6 -2
View File
@@ -23,8 +23,12 @@ libraries installed on your PC. For example:
./qemu -L / /bin/ls
* On non x86 CPUs, you need first to download at least an x86 glibc
(qemu-i386-glibc21.tar.gz on the qemu web page). Then you can launch
the precompiled 'ls' x86 executable:
(qemu-i386-glibc21.tar.gz on the qemu web page). Ensure that
LD_LIBRARY_PATH is not set:
unset LD_LIBRARY_PATH
Then you can launch the precompiled 'ls' x86 executable:
./qemu /usr/local/qemu-i386/bin/ls
+1 -1
View File
@@ -1 +1 @@
0.1.1
0.1.3
+20 -14
View File
@@ -48,6 +48,7 @@
#define R_FS 4
#define R_GS 5
/* eflags masks */
#define CC_C 0x0001
#define CC_P 0x0004
#define CC_A 0x0010
@@ -55,15 +56,17 @@
#define CC_S 0x0080
#define CC_O 0x0800
#define TRAP_FLAG 0x0100
#define INTERRUPT_FLAG 0x0200
#define DIRECTION_FLAG 0x0400
#define IOPL_FLAG_MASK 0x3000
#define NESTED_FLAG 0x4000
#define BYTE_FL 0x8000 /* Intel reserved! */
#define RF_FLAG 0x10000
#define VM_FLAG 0x20000
/* AC 0x40000 */
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
#define DF_MASK 0x00000400
#define IOPL_MASK 0x00003000
#define NT_MASK 0x00004000
#define RF_MASK 0x00010000
#define VM_MASK 0x00020000
#define AC_MASK 0x00040000
#define VIF_MASK 0x00080000
#define VIP_MASK 0x00100000
#define ID_MASK 0x00200000
#define EXCP00_DIVZ 1
#define EXCP01_SSTP 2
@@ -158,7 +161,9 @@ typedef struct CPUX86State {
/* standard registers */
uint32_t regs[8];
uint32_t eip;
uint32_t eflags;
uint32_t eflags; /* eflags register. During CPU emulation, CC
flags and DF are set to zero because they are
store elsewhere */
/* emulator internal eflags handling */
uint32_t cc_src;
@@ -183,13 +188,13 @@ typedef struct CPUX86State {
SegmentDescriptorTable ldt;
SegmentDescriptorTable idt;
/* various CPU modes */
int vm86;
/* exception/interrupt handling */
jmp_buf jmp_env;
int exception_index;
int interrupt_request;
/* user data */
void *opaque;
} CPUX86State;
/* all CPU memory access use these macros */
@@ -418,7 +423,8 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
#define GEN_FLAG_CODE32_SHIFT 0
#define GEN_FLAG_ADDSEG_SHIFT 1
#define GEN_FLAG_SS32_SHIFT 2
#define GEN_FLAG_ST_SHIFT 3
#define GEN_FLAG_VM_SHIFT 3
#define GEN_FLAG_ST_SHIFT 4
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr,
+6 -3
View File
@@ -282,7 +282,9 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
error("inconsistent argument numbering in %s", name);
}
if (gen_switch) {
if (gen_switch == 2) {
fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args);
} else if (gen_switch == 1) {
/* output C code */
fprintf(outfile, "case INDEX_%s: {\n", name);
@@ -559,12 +561,13 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
}
if (do_print_enum) {
fprintf(outfile, "DEF(end)\n");
fprintf(outfile, "DEF(end, 0)\n");
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
const char *name, *p;
name = strtab + sym->st_name;
if (strstart(name, OP_PREFIX, &p)) {
fprintf(outfile, "DEF(%s)\n", p);
gen_code(name, sym->st_value, sym->st_size, outfile,
text, relocs, nb_relocs, reloc_sh_type, symtab, strtab, 2);
}
}
} else {
+6 -5
View File
@@ -330,9 +330,10 @@ int cpu_x86_exec(CPUX86State *env1)
#endif
/* put eflags in CPU temporary format */
T0 = env->eflags;
op_movl_eflags_T0();
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((env->eflags >> 10) & 1));
CC_OP = CC_OP_EFLAGS;
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
env->interrupt_request = 0;
/* prepare setjmp context for exception handling */
@@ -354,6 +355,7 @@ int cpu_x86_exec(CPUX86State *env1)
(unsigned long)env->seg_cache[R_ES].base |
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT;
flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT);
cs_base = env->seg_cache[R_CS].base;
pc = cs_base + env->eip;
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
@@ -390,8 +392,7 @@ int cpu_x86_exec(CPUX86State *env1)
ret = env->exception_index;
/* restore flags in standard format */
op_movl_T0_eflags();
env->eflags = T0;
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
/* restore global registers */
#ifdef reg_EAX
@@ -489,7 +490,7 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
/* for glibc 2.1 */
#define REG_EIP EIP
#endif
pc = uc->uc_mcontext.gregs[EIP];
pc = uc->uc_mcontext.gregs[REG_EIP];
pold_set = &uc->uc_sigmask;
return handle_cpu_signal(pc, pold_set);
#else
+4 -4
View File
@@ -360,9 +360,6 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
put_user (tswapl(val), dlinfo++)
if (exec) { /* Put this here for an ELF program interpreter */
struct elf_phdr * eppnt;
eppnt = (struct elf_phdr *)((unsigned long)exec->e_phoff);
NEW_AUX_ENT (AT_PHDR, (unsigned int)(load_addr + exec->e_phoff));
NEW_AUX_ENT (AT_PHENT, (unsigned int)(sizeof (struct elf_phdr)));
NEW_AUX_ENT (AT_PHNUM, (unsigned int)(exec->e_phnum));
@@ -418,6 +415,9 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
*/
load_addr = INTERP_LOADADDR;
#ifdef BSWAP_NEEDED
bswap_ehdr(interp_elf_ex);
#endif
/* First of all, some simple consistency checks */
if ((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
@@ -425,6 +425,7 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
return ~0UL;
}
/* Now read in all of the header information */
if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > X86_PAGE_SIZE)
@@ -452,7 +453,6 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
(char *) elf_phdata,
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
}
if (retval < 0) {
perror("load_elf_interp");
exit(-1);
+90 -18
View File
@@ -104,35 +104,99 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit,
uint64_t gdt_table[6];
//#define DEBUG_VM86
void cpu_loop(struct CPUX86State *env)
{
int err;
uint8_t *pc;
target_siginfo_t info;
for(;;) {
err = cpu_x86_exec(env);
pc = env->seg_cache[R_CS].base + env->eip;
switch(err) {
case EXCP0D_GPF:
if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */
env->eip += 2;
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP]);
if (env->eflags & VM_MASK) {
TaskState *ts;
int ret;
#ifdef DEBUG_VM86
printf("VM86 exception %04x:%08x %02x\n",
env->segs[R_CS], env->eip, pc[0]);
#endif
/* VM86 mode */
ts = env->opaque;
/* XXX: add all cases */
switch(pc[0]) {
case 0xcd: /* int */
env->eip += 2;
ret = TARGET_VM86_INTx | (pc[1] << 8);
break;
default:
/* real VM86 GPF exception */
ret = TARGET_VM86_UNKNOWN;
break;
}
#ifdef DEBUG_VM86
printf("ret=0x%x\n", ret);
#endif
/* put the VM86 registers in the userspace register structure */
ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]);
ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]);
ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]);
ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]);
ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]);
ts->target_v86->regs.eip = tswap32(env->eip);
ts->target_v86->regs.cs = tswap16(env->segs[R_CS]);
ts->target_v86->regs.ss = tswap16(env->segs[R_SS]);
ts->target_v86->regs.ds = tswap16(env->segs[R_DS]);
ts->target_v86->regs.es = tswap16(env->segs[R_ES]);
ts->target_v86->regs.fs = tswap16(env->segs[R_FS]);
ts->target_v86->regs.gs = tswap16(env->segs[R_GS]);
/* restore 32 bit registers */
env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
env->regs[R_EDX] = ts->vm86_saved_regs.edx;
env->regs[R_ESI] = ts->vm86_saved_regs.esi;
env->regs[R_EDI] = ts->vm86_saved_regs.edi;
env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
env->regs[R_ESP] = ts->vm86_saved_regs.esp;
env->eflags = ts->vm86_saved_regs.eflags;
env->eip = ts->vm86_saved_regs.eip;
cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
env->regs[R_EAX] = ret;
} else {
/* XXX: more precise info */
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = 0;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */
env->eip += 2;
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
env->regs[R_ECX],
env->regs[R_EDX],
env->regs[R_ESI],
env->regs[R_EDI],
env->regs[R_EBP]);
} else {
/* XXX: more precise info */
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = 0;
info._sifields._sigfault._addr = 0;
queue_signal(info.si_signo, &info);
}
}
break;
case EXCP00_DIVZ:
@@ -188,12 +252,15 @@ void usage(void)
/* XXX: currently only used for async signals (see signal.c) */
CPUX86State *global_env;
/* used to free thread contexts */
TaskState *first_task_state;
int main(int argc, char **argv)
{
const char *filename;
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
CPUX86State *env;
int optind;
const char *r;
@@ -272,6 +339,11 @@ int main(int argc, char **argv)
env = cpu_x86_init();
global_env = env;
/* build Task State */
memset(ts, 0, sizeof(TaskState));
env->opaque = ts;
ts->used = 1;
/* linux register setup */
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
+27
View File
@@ -33,6 +33,33 @@ struct image_info {
int personality;
};
/* Information about the current linux thread */
struct vm86_saved_state {
uint32_t eax; /* return code */
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
uint32_t esp;
uint32_t eflags;
uint32_t eip;
uint16_t cs, ss, ds, es, fs, gs;
};
/* NOTE: we force a big alignment so that the stack stored after is
aligned too */
typedef struct TaskState {
struct TaskState *next;
struct target_vm86plus_struct *target_v86;
struct vm86_saved_state vm86_saved_regs;
int used; /* non zero if used */
uint8_t stack[0];
} __attribute__((aligned(16))) TaskState;
extern TaskState *first_task_state;
int elf_exec(const char *interp_prefix,
const char * filename, char ** argv, char ** envp,
struct target_pt_regs * regs, struct image_info *infop);
-2
View File
@@ -570,8 +570,6 @@ get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
return (void *)((esp - frame_size) & -8ul);
}
#define TF_MASK TRAP_FLAG
static void setup_frame(int sig, struct emulated_sigaction *ka,
target_sigset_t *set, CPUX86State *env)
{
+166 -37
View File
@@ -103,10 +103,10 @@ extern int personality(int);
extern int flock(int, int);
extern int setfsuid(int);
extern int setfsgid(int);
extern int setresuid(int,int,int);
extern int getresuid(int *,int *,int *);
extern int setresgid(int,int,int);
extern int getresgid(int *,int *,int *);
extern int setresuid(uid_t, uid_t, uid_t);
extern int getresuid(uid_t *, uid_t *, uid_t *);
extern int setresgid(gid_t, gid_t, gid_t);
extern int getresgid(gid_t *, gid_t *, gid_t *);
static inline long get_errno(long ret)
{
@@ -210,14 +210,14 @@ static inline void host_to_target_fds(target_long *target_fds,
}
static inline void target_to_host_timeval(struct timeval *tv,
struct target_timeval *target_tv)
const struct target_timeval *target_tv)
{
tv->tv_sec = tswapl(target_tv->tv_sec);
tv->tv_usec = tswapl(target_tv->tv_usec);
}
static inline void host_to_target_timeval(struct target_timeval *target_tv,
struct timeval *tv)
const struct timeval *tv)
{
target_tv->tv_sec = tswapl(tv->tv_sec);
target_tv->tv_usec = tswapl(tv->tv_usec);
@@ -238,8 +238,7 @@ static long do_select(long n,
efds_ptr = target_to_host_fds(&efds, target_efds, n);
if (target_tv) {
tv.tv_sec = tswapl(target_tv->tv_sec);
tv.tv_usec = tswapl(target_tv->tv_usec);
target_to_host_timeval(&tv, target_tv);
tv_ptr = &tv;
} else {
tv_ptr = NULL;
@@ -251,8 +250,7 @@ static long do_select(long n,
host_to_target_fds(target_efds, efds_ptr, n);
if (target_tv) {
target_tv->tv_sec = tswapl(tv.tv_sec);
target_tv->tv_usec = tswapl(tv.tv_usec);
host_to_target_timeval(target_tv, &tv);
}
}
return ret;
@@ -755,7 +753,7 @@ install:
}
/* specific and weird i386 syscalls */
int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount)
int do_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount)
{
int ret = -ENOSYS;
@@ -773,6 +771,79 @@ int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecou
return ret;
}
/* vm86 emulation */
#define SAFE_MASK (0xDD5)
int do_vm86(CPUX86State *env, long subfunction,
struct target_vm86plus_struct * target_v86)
{
TaskState *ts = env->opaque;
int ret;
switch (subfunction) {
case TARGET_VM86_REQUEST_IRQ:
case TARGET_VM86_FREE_IRQ:
case TARGET_VM86_GET_IRQ_BITS:
case TARGET_VM86_GET_AND_RESET_IRQ:
gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
ret = -EINVAL;
goto out;
case TARGET_VM86_PLUS_INSTALL_CHECK:
/* NOTE: on old vm86 stuff this will return the error
from verify_area(), because the subfunction is
interpreted as (invalid) address to vm86_struct.
So the installation check works.
*/
ret = 0;
goto out;
}
ts->target_v86 = target_v86;
/* save current CPU regs */
ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
ts->vm86_saved_regs.ebx = env->regs[R_EBX];
ts->vm86_saved_regs.ecx = env->regs[R_ECX];
ts->vm86_saved_regs.edx = env->regs[R_EDX];
ts->vm86_saved_regs.esi = env->regs[R_ESI];
ts->vm86_saved_regs.edi = env->regs[R_EDI];
ts->vm86_saved_regs.ebp = env->regs[R_EBP];
ts->vm86_saved_regs.esp = env->regs[R_ESP];
ts->vm86_saved_regs.eflags = env->eflags;
ts->vm86_saved_regs.eip = env->eip;
ts->vm86_saved_regs.cs = env->segs[R_CS];
ts->vm86_saved_regs.ss = env->segs[R_SS];
ts->vm86_saved_regs.ds = env->segs[R_DS];
ts->vm86_saved_regs.es = env->segs[R_ES];
ts->vm86_saved_regs.fs = env->segs[R_FS];
ts->vm86_saved_regs.gs = env->segs[R_GS];
/* build vm86 CPU state */
env->eflags = (env->eflags & ~SAFE_MASK) |
(tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
env->regs[R_EDX] = tswap32(target_v86->regs.edx);
env->regs[R_ESI] = tswap32(target_v86->regs.esi);
env->regs[R_EDI] = tswap32(target_v86->regs.edi);
env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
env->regs[R_ESP] = tswap32(target_v86->regs.esp);
env->eip = tswap32(target_v86->regs.eip);
cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
ret = tswap32(target_v86->regs.eax); /* eax will be restored at
the end of the syscall */
/* now the virtual CPU is ready for vm86 execution ! */
out:
return ret;
}
/* this stack is the equivalent of the kernel stack associated with a
thread/process */
#define NEW_STACK_SIZE 8192
@@ -788,19 +859,26 @@ static int clone_func(void *arg)
int do_fork(CPUX86State *env, unsigned int flags, unsigned long newsp)
{
int ret;
TaskState *ts;
uint8_t *new_stack;
CPUX86State *new_env;
if (flags & CLONE_VM) {
if (!newsp)
newsp = env->regs[R_ESP];
new_stack = malloc(NEW_STACK_SIZE);
ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
memset(ts, 0, sizeof(TaskState));
new_stack = ts->stack;
ts->used = 1;
/* add in task state list */
ts->next = first_task_state;
first_task_state = ts;
/* we create a new CPU instance. */
new_env = cpu_x86_init();
memcpy(new_env, env, sizeof(CPUX86State));
new_env->regs[R_ESP] = newsp;
new_env->regs[R_EAX] = 0;
new_env->opaque = ts;
ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
} else {
/* if no CLONE_VM, we consider it is a fork */
@@ -1281,8 +1359,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct timeval tv;
ret = get_errno(gettimeofday(&tv, NULL));
if (!is_error(ret)) {
target_tv->tv_sec = tswapl(tv.tv_sec);
target_tv->tv_usec = tswapl(tv.tv_usec);
host_to_target_timeval(target_tv, &tv);
}
}
break;
@@ -1290,8 +1367,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
{
struct target_timeval *target_tv = (void *)arg1;
struct timeval tv;
tv.tv_sec = tswapl(target_tv->tv_sec);
tv.tv_usec = tswapl(target_tv->tv_usec);
target_to_host_timeval(&tv, target_tv);
ret = get_errno(settimeofday(&tv, NULL));
}
break;
@@ -1487,8 +1563,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
case TARGET_NR_idle:
goto unimplemented;
case TARGET_NR_vm86old:
goto unimplemented;
case TARGET_NR_wait4:
{
int status;
@@ -1548,7 +1622,12 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
#ifdef TARGET_I386
case TARGET_NR_modify_ldt:
ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3));
ret = get_errno(do_modify_ldt(cpu_env, arg1, (void *)arg2, arg3));
break;
case TARGET_NR_vm86old:
goto unimplemented;
case TARGET_NR_vm86:
ret = do_vm86(cpu_env, arg1, (void *)arg2);
break;
#endif
case TARGET_NR_adjtimex:
@@ -1603,10 +1682,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
int reclen;
de = dirp;
while (len > 0) {
reclen = tswap16(de->d_reclen);
reclen = de->d_reclen;
if (reclen > len)
break;
de->d_reclen = reclen;
de->d_reclen = tswap16(reclen);
tswapls(&de->d_ino);
tswapls(&de->d_off);
de = (struct dirent *)((char *)de + reclen);
@@ -1626,10 +1705,10 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
int reclen;
de = dirp;
while (len > 0) {
reclen = tswap16(de->d_reclen);
reclen = de->d_reclen;
if (reclen > len)
break;
de->d_reclen = reclen;
de->d_reclen = tswap16(reclen);
tswap64s(&de->d_ino);
tswap64s(&de->d_off);
de = (struct dirent64 *)((char *)de + reclen);
@@ -1652,13 +1731,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
pfd = alloca(sizeof(struct pollfd) * nfds);
for(i = 0; i < nfds; i++) {
pfd->fd = tswap32(target_pfd->fd);
pfd->events = tswap16(target_pfd->events);
pfd[i].fd = tswap32(target_pfd[i].fd);
pfd[i].events = tswap16(target_pfd[i].events);
}
ret = get_errno(poll(pfd, nfds, timeout));
if (!is_error(ret)) {
for(i = 0; i < nfds; i++) {
target_pfd->revents = tswap16(pfd->revents);
target_pfd[i].revents = tswap16(pfd[i].revents);
}
}
}
@@ -1702,25 +1781,59 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(getsid(arg1));
break;
case TARGET_NR_fdatasync:
goto unimplemented;
ret = get_errno(fdatasync(arg1));
break;
case TARGET_NR__sysctl:
goto unimplemented;
case TARGET_NR_sched_setparam:
goto unimplemented;
{
struct sched_param *target_schp = (void *)arg2;
struct sched_param schp;
schp.sched_priority = tswap32(target_schp->sched_priority);
ret = get_errno(sched_setparam(arg1, &schp));
}
break;
case TARGET_NR_sched_getparam:
goto unimplemented;
{
struct sched_param *target_schp = (void *)arg2;
struct sched_param schp;
ret = get_errno(sched_getparam(arg1, &schp));
if (!is_error(ret)) {
target_schp->sched_priority = tswap32(schp.sched_priority);
}
}
break;
case TARGET_NR_sched_setscheduler:
goto unimplemented;
{
struct sched_param *target_schp = (void *)arg3;
struct sched_param schp;
schp.sched_priority = tswap32(target_schp->sched_priority);
ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
}
break;
case TARGET_NR_sched_getscheduler:
goto unimplemented;
ret = get_errno(sched_getscheduler(arg1));
break;
case TARGET_NR_sched_yield:
ret = get_errno(sched_yield());
break;
case TARGET_NR_sched_get_priority_max:
ret = get_errno(sched_get_priority_max(arg1));
break;
case TARGET_NR_sched_get_priority_min:
ret = get_errno(sched_get_priority_min(arg1));
break;
case TARGET_NR_sched_rr_get_interval:
goto unimplemented;
{
struct target_timespec *target_ts = (void *)arg2;
struct timespec ts;
ret = get_errno(sched_rr_get_interval(arg1, &ts));
if (!is_error(ret)) {
target_ts->tv_sec = tswapl(ts.tv_sec);
target_ts->tv_nsec = tswapl(ts.tv_nsec);
}
}
break;
case TARGET_NR_nanosleep:
{
struct target_timespec *target_req = (void *)arg1;
@@ -1767,11 +1880,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
}
break;
case TARGET_NR_vm86:
case TARGET_NR_query_module:
goto unimplemented;
case TARGET_NR_nfsservctl:
goto unimplemented;
case TARGET_NR_prctl:
goto unimplemented;
case TARGET_NR_pread:
goto unimplemented;
case TARGET_NR_pwrite:
goto unimplemented;
case TARGET_NR_chown:
@@ -1781,16 +1897,24 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(sys_getcwd1((char *)arg1, arg2));
break;
case TARGET_NR_capget:
goto unimplemented;
case TARGET_NR_capset:
goto unimplemented;
case TARGET_NR_sigaltstack:
goto unimplemented;
case TARGET_NR_sendfile:
goto unimplemented;
case TARGET_NR_getpmsg:
goto unimplemented;
case TARGET_NR_putpmsg:
goto unimplemented;
case TARGET_NR_vfork:
ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
break;
case TARGET_NR_ugetrlimit:
goto unimplemented;
case TARGET_NR_truncate64:
goto unimplemented;
case TARGET_NR_ftruncate64:
goto unimplemented;
case TARGET_NR_stat64:
@@ -1919,6 +2043,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(gettid());
break;
case TARGET_NR_readahead:
goto unimplemented;
case TARGET_NR_setxattr:
case TARGET_NR_lsetxattr:
case TARGET_NR_fsetxattr:
@@ -1931,10 +2056,14 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_removexattr:
case TARGET_NR_lremovexattr:
case TARGET_NR_fremovexattr:
goto unimplemented;
goto unimplemented_nowarn;
case TARGET_NR_set_thread_area:
case TARGET_NR_get_thread_area:
goto unimplemented_nowarn;
default:
unimplemented:
gemu_log("gemu: Unsupported syscall: %d\n", num);
gemu_log("qemu: Unsupported syscall: %d\n", num);
unimplemented_nowarn:
ret = -ENOSYS;
break;
}
+114 -10
View File
@@ -489,6 +489,11 @@ void OPPROTO op_addl_A0_im(void)
A0 += PARAM1;
}
void OPPROTO op_addl_A0_AL(void)
{
A0 += (EAX & 0xff);
}
void OPPROTO op_andl_A0_ffff(void)
{
A0 = A0 & 0xffff;
@@ -602,13 +607,51 @@ void OPPROTO op_into(void)
int eflags;
eflags = cc_table[CC_OP].compute_all();
if (eflags & CC_O) {
EIP = PARAM1;
raise_exception(EXCP04_INTO);
} else {
EIP = PARAM2;
}
}
void OPPROTO op_boundw(void)
{
int low, high, v;
low = ldsw((uint8_t *)A0);
high = ldsw((uint8_t *)A0 + 2);
v = (int16_t)T0;
if (v < low || v > high)
raise_exception(EXCP05_BOUND);
FORCE_RET();
}
void OPPROTO op_boundl(void)
{
int low, high, v;
low = ldl((uint8_t *)A0);
high = ldl((uint8_t *)A0 + 4);
v = T0;
if (v < low || v > high)
raise_exception(EXCP05_BOUND);
FORCE_RET();
}
void OPPROTO op_cmpxchg8b(void)
{
uint64_t d;
int eflags;
eflags = cc_table[CC_OP].compute_all();
d = ldq((uint8_t *)A0);
if (d == (((uint64_t)EDX << 32) | EAX)) {
stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
eflags |= CC_Z;
} else {
EDX = d >> 32;
EAX = d;
eflags &= ~CC_Z;
}
CC_SRC = eflags;
FORCE_RET();
}
/* string ops */
#define ldul ldl
@@ -788,7 +831,8 @@ void op_addw_ESP_im(void)
#ifndef __i386__
uint64_t emu_time;
#endif
void op_rdtsc(void)
void OPPROTO op_rdtsc(void)
{
uint64_t val;
#ifdef __i386__
@@ -801,6 +845,51 @@ void op_rdtsc(void)
EDX = val >> 32;
}
/* We simulate a pre-MMX pentium as in valgrind */
#define CPUID_FP87 (1 << 0)
#define CPUID_VME (1 << 1)
#define CPUID_DE (1 << 2)
#define CPUID_PSE (1 << 3)
#define CPUID_TSC (1 << 4)
#define CPUID_MSR (1 << 5)
#define CPUID_PAE (1 << 6)
#define CPUID_MCE (1 << 7)
#define CPUID_CX8 (1 << 8)
#define CPUID_APIC (1 << 9)
#define CPUID_SEP (1 << 11) /* sysenter/sysexit */
#define CPUID_MTRR (1 << 12)
#define CPUID_PGE (1 << 13)
#define CPUID_MCA (1 << 14)
#define CPUID_CMOV (1 << 15)
/* ... */
#define CPUID_MMX (1 << 23)
#define CPUID_FXSR (1 << 24)
#define CPUID_SSE (1 << 25)
#define CPUID_SSE2 (1 << 26)
void helper_cpuid(void)
{
if (EAX == 0) {
EAX = 1; /* max EAX index supported */
EBX = 0x756e6547;
ECX = 0x6c65746e;
EDX = 0x49656e69;
} else {
/* EAX = 1 info */
EAX = 0x52b;
EBX = 0;
ECX = 0;
EDX = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE |
CPUID_TSC | CPUID_MSR | CPUID_MCE |
CPUID_CX8;
}
}
void OPPROTO op_cpuid(void)
{
helper_cpuid();
}
/* bcd */
/* XXX: exception */
@@ -933,6 +1022,7 @@ void OPPROTO op_das(void)
/* segment handling */
/* XXX: use static VM86 information */
void load_seg(int seg_reg, int selector)
{
SegmentCache *sc;
@@ -943,7 +1033,7 @@ void load_seg(int seg_reg, int selector)
env->segs[seg_reg] = selector;
sc = &env->seg_cache[seg_reg];
if (env->vm86) {
if (env->eflags & VM_MASK) {
sc->base = (void *)(selector << 4);
sc->limit = 0xffff;
sc->seg_32bit = 0;
@@ -980,6 +1070,11 @@ void OPPROTO op_movl_T0_seg(void)
T0 = env->segs[PARAM1];
}
void OPPROTO op_movl_A0_seg(void)
{
A0 = *(unsigned long *)((char *)env + PARAM1);
}
void OPPROTO op_addl_A0_seg(void)
{
A0 += *(unsigned long *)((char *)env + PARAM1);
@@ -1139,10 +1234,16 @@ void OPPROTO op_set_cc_op(void)
CC_OP = PARAM1;
}
#define FL_UPDATE_MASK (TF_MASK | AC_MASK | ID_MASK)
void OPPROTO op_movl_eflags_T0(void)
{
CC_SRC = T0;
DF = 1 - (2 * ((T0 >> 10) & 1));
int eflags;
eflags = T0;
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
env->eflags = (env->eflags & ~FL_UPDATE_MASK) | (eflags & FL_UPDATE_MASK);
}
/* XXX: compute only O flag */
@@ -1150,13 +1251,16 @@ void OPPROTO op_movb_eflags_T0(void)
{
int of;
of = cc_table[CC_OP].compute_all() & CC_O;
CC_SRC = T0 | of;
CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of;
}
void OPPROTO op_movl_T0_eflags(void)
{
T0 = cc_table[CC_OP].compute_all();
T0 |= (DF & DIRECTION_FLAG);
int eflags;
eflags = cc_table[CC_OP].compute_all();
eflags |= (DF & DF_MASK);
eflags |= env->eflags & ~(VM_MASK | RF_MASK);
T0 = eflags;
}
void OPPROTO op_cld(void)
+245
View File
@@ -0,0 +1,245 @@
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_SI();
INC_DI();
}
void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(st, SUFFIX)(DI_ADDR, v);
INC_SI();
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
glue(st, SUFFIX)(DI_ADDR, EAX);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void)
{
int inc;
inc = (DF << SHIFT);
while (CX != 0) {
glue(st, SUFFIX)(DI_ADDR, EAX);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
inc = (DF << SHIFT);
INC_SI();
}
/* don't know if it is used */
void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v, inc;
v = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_DI();
CC_SRC = EAX;
CC_DST = EAX - v;
}
void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
/* NOTE: the flags are not modified if CX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
inc = (DF << SHIFT);
INC_SI();
INC_DI();
CC_SRC = v1;
CC_DST = v1 - v2;
}
void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 != v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
{
int v1, v2, inc;
if (CX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)(SI_ADDR);
v2 = glue(ldu, SUFFIX)(DI_ADDR);
INC_SI();
INC_DI();
DEC_CX();
if (v1 == v2)
break;
} while (CX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(dx, v);
inc = (DF << SHIFT);
INC_SI();
}
void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(ldu, SUFFIX)(SI_ADDR);
glue(cpu_x86_out, SUFFIX)(dx, v);
INC_SI();
DEC_CX();
}
FORCE_RET();
}
void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
dx = EDX & 0xffff;
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)(DI_ADDR, v);
inc = (DF << SHIFT);
INC_DI();
}
void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (CX != 0) {
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)(DI_ADDR, v);
INC_DI();
DEC_CX();
}
FORCE_RET();
}
#undef STRING_SUFFIX
#undef SI_ADDR
#undef DI_ADDR
#undef INC_SI
#undef INC_DI
#undef CX
#undef DEC_CX
+636 -534
View File
File diff suppressed because it is too large. Load diff
+25 -226
View File
@@ -806,238 +806,37 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
#endif
/* string operations */
/* XXX: maybe use lower level instructions to ease exception handling */
/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
void OPPROTO glue(op_movs, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)ESI);
glue(st, SUFFIX)((void *)EDI, v);
ESI += (DF << SHIFT);
EDI += (DF << SHIFT);
}
#define STRING_SUFFIX _fast
#define SI_ADDR (void *)ESI
#define DI_ADDR (void *)EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
#define DEC_CX() ECX--
#include "op_string.h"
void OPPROTO glue(op_rep_movs, SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
glue(st, SUFFIX)((void *)EDI, v);
ESI += inc;
EDI += inc;
ECX--;
}
FORCE_RET();
}
#define STRING_SUFFIX _a32
#define SI_ADDR (uint8_t *)A0 + ESI
#define DI_ADDR env->seg_cache[R_ES].base + EDI
#define INC_SI() ESI += inc
#define INC_DI() EDI += inc
#define CX ECX
#define DEC_CX() ECX--
#include "op_string.h"
void OPPROTO glue(op_stos, SUFFIX)(void)
{
glue(st, SUFFIX)((void *)EDI, EAX);
EDI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_stos, SUFFIX)(void)
{
int inc;
inc = (DF << SHIFT);
while (ECX != 0) {
glue(st, SUFFIX)((void *)EDI, EAX);
EDI += inc;
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(op_lods, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)ESI);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
ESI += (DF << SHIFT);
}
/* don't know if it is used */
void OPPROTO glue(op_rep_lods, SUFFIX)(void)
{
int v, inc;
inc = (DF << SHIFT);
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
#if SHIFT == 0
EAX = (EAX & ~0xff) | v;
#elif SHIFT == 1
EAX = (EAX & ~0xffff) | v;
#else
EAX = v;
#endif
ESI += inc;
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(op_scas, SUFFIX)(void)
{
int v;
v = glue(ldu, SUFFIX)((void *)EDI);
EDI += (DF << SHIFT);
CC_SRC = EAX;
CC_DST = EAX - v;
}
void OPPROTO glue(op_repz_scas, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
/* NOTE: the flags are not modified if ECX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)((void *)EDI);
EDI += inc;
ECX--;
if (v1 != v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(op_repnz_scas, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
/* NOTE: the flags are not modified if ECX == 0 */
v1 = EAX & DATA_MASK;
inc = (DF << SHIFT);
do {
v2 = glue(ldu, SUFFIX)((void *)EDI);
EDI += inc;
ECX--;
if (v1 == v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(op_cmps, SUFFIX)(void)
{
int v1, v2;
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
ESI += (DF << SHIFT);
EDI += (DF << SHIFT);
CC_SRC = v1;
CC_DST = v1 - v2;
}
void OPPROTO glue(op_repz_cmps, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
ESI += inc;
EDI += inc;
ECX--;
if (v1 != v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
void OPPROTO glue(op_repnz_cmps, SUFFIX)(void)
{
int v1, v2, inc;
if (ECX != 0) {
inc = (DF << SHIFT);
do {
v1 = glue(ldu, SUFFIX)((void *)ESI);
v2 = glue(ldu, SUFFIX)((void *)EDI);
ESI += inc;
EDI += inc;
ECX--;
if (v1 == v2)
break;
} while (ECX != 0);
CC_SRC = v1;
CC_DST = v1 - v2;
CC_OP = CC_OP_SUBB + SHIFT;
}
FORCE_RET();
}
#define STRING_SUFFIX _a16
#define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
#define DI_ADDR env->seg_cache[R_ES].base + (EDI & 0xffff)
#define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
#define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
#define CX (ECX & 0xffff)
#define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff)
#include "op_string.h"
/* port I/O */
void OPPROTO glue(op_outs, SUFFIX)(void)
{
int v, dx;
dx = EDX & 0xffff;
v = glue(ldu, SUFFIX)((void *)ESI);
glue(cpu_x86_out, SUFFIX)(dx, v);
ESI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_outs, SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (ECX != 0) {
v = glue(ldu, SUFFIX)((void *)ESI);
glue(cpu_x86_out, SUFFIX)(dx, v);
ESI += inc;
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(op_ins, SUFFIX)(void)
{
int v, dx;
dx = EDX & 0xffff;
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)((void *)EDI, v);
EDI += (DF << SHIFT);
}
void OPPROTO glue(op_rep_ins, SUFFIX)(void)
{
int v, dx, inc;
inc = (DF << SHIFT);
dx = EDX & 0xffff;
while (ECX != 0) {
v = glue(cpu_x86_in, SUFFIX)(dx);
glue(st, SUFFIX)((void *)EDI, v);
EDI += (DF << SHIFT);
ECX--;
}
FORCE_RET();
}
void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
{
glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK);
+41 -6
View File
@@ -92,14 +92,49 @@ qemu -L / /bin/ls
@item On non x86 CPUs, you need first to download at least an x86 glibc
(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Then you can
launch the precompiled @file{ls} x86 executable:
(@file{qemu-i386-glibc21.tar.gz} on the QEMU web page). Ensure that
@code{LD_LIBRARY_PATH} is not set:
@example
qemu /usr/local/qemu-i386/bin/ls
unset LD_LIBRARY_PATH
@end example
Then you can launch the precompiled @file{ls} x86 executable:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
@end example
You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that
QEMU is automatically launched by the Linux kernel when you try to
launch x86 executables. It requires the @code{binfmt_misc} module in the
Linux kernel.
@end itemize
@section Wine launch (Currently only tested when emulating x86 on x86)
@itemize
@item Ensure that you have a working QEMU with the x86 glibc
distribution (see previous section). In order to verify it, you must be
able to do:
@example
qemu /usr/local/qemu-i386/bin/ls-i386
@end example
@item Download the binary x86 wine install
(@file{qemu-i386-wine.tar.gz} on the QEMU web page).
@item Configure wine on your account. Look at the provided script
@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}.
@item Then you can try the example @file{putty.exe}:
@example
qemu /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program\ Files/putty.exe
@end example
You can look at @file{/usr/local/qemu-i386/bin/qemu-conf.sh} so that QEMU is automatically
launched by the Linux kernel when you try to launch x86 executables. It
requires the @code{binfmt_misc} module in the Linux kernel.
@end itemize
+210
View File
@@ -237,6 +237,36 @@
#define TARGET_NR_removexattr 235
#define TARGET_NR_lremovexattr 236
#define TARGET_NR_fremovexattr 237
#define TARGET_NR_tkill 238
#define TARGET_NR_sendfile64 239
#define TARGET_NR_futex 240
#define TARGET_NR_sched_setaffinity 241
#define TARGET_NR_sched_getaffinity 242
#define TARGET_NR_set_thread_area 243
#define TARGET_NR_get_thread_area 244
#define TARGET_NR_io_setup 245
#define TARGET_NR_io_destroy 246
#define TARGET_NR_io_getevents 247
#define TARGET_NR_io_submit 248
#define TARGET_NR_io_cancel 249
#define TARGET_NR_fadvise64 250
#define TARGET_NR_exit_group 252
#define TARGET_NR_lookup_dcookie 253
#define TARGET_NR_epoll_create 254
#define TARGET_NR_epoll_ctl 255
#define TARGET_NR_epoll_wait 256
#define TARGET_NR_remap_file_pages 257
#define TARGET_NR_set_tid_address 258
#define TARGET_NR_timer_create 259
#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
#define TARGET_SIG_BLOCK 0 /* for blocking signals */
#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
@@ -714,6 +744,10 @@ struct target_termios {
#define TARGET_LDT_ENTRIES 8192
#define TARGET_LDT_ENTRY_SIZE 8
#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
#define TARGET_GDT_ENTRY_TLS_MIN 6
#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
struct target_modify_ldt_ldt_s {
unsigned int entry_number;
target_ulong base_addr;
@@ -721,6 +755,182 @@ struct target_modify_ldt_ldt_s {
unsigned int flags;
};
#define TARGET_VM86_SIGNAL 0 /* return due to signal */
#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
/*
* Additional return values when invoking new vm86()
*/
#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
/*
* function codes when invoking new vm86()
*/
#define TARGET_VM86_PLUS_INSTALL_CHECK 0
#define TARGET_VM86_ENTER 1
#define TARGET_VM86_ENTER_NO_BYPASS 2
#define TARGET_VM86_REQUEST_IRQ 3
#define TARGET_VM86_FREE_IRQ 4
#define TARGET_VM86_GET_IRQ_BITS 5
#define TARGET_VM86_GET_AND_RESET_IRQ 6
/*
* This is the stack-layout seen by the user space program when we have
* done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
* is 'kernel_vm86_regs' (see below).
*/
struct target_vm86_regs {
/*
* normal regs, with special meaning for the segment descriptors..
*/
target_long ebx;
target_long ecx;
target_long edx;
target_long esi;
target_long edi;
target_long ebp;
target_long eax;
target_long __null_ds;
target_long __null_es;
target_long __null_fs;
target_long __null_gs;
target_long orig_eax;
target_long eip;
unsigned short cs, __csh;
target_long eflags;
target_long esp;
unsigned short ss, __ssh;
/*
* these are specific to v86 mode:
*/
unsigned short es, __esh;
unsigned short ds, __dsh;
unsigned short fs, __fsh;
unsigned short gs, __gsh;
};
struct target_revectored_struct {
target_ulong __map[8]; /* 256 bits */
};
struct target_vm86_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
};
/*
* flags masks
*/
#define TARGET_VM86_SCREEN_BITMAP 0x0001
struct target_vm86plus_info_struct {
target_ulong flags;
#define TARGET_force_return_for_pic (1 << 0)
#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
unsigned char vm86dbg_intxxtab[32]; /* for debugger */
};
struct target_vm86plus_struct {
struct target_vm86_regs regs;
target_ulong flags;
target_ulong screen_bitmap;
target_ulong cpu_type;
struct target_revectored_struct int_revectored;
struct target_revectored_struct int21_revectored;
struct target_vm86plus_info_struct vm86plus;
};
/* ipcs */
#define TARGET_SEMOP 1
#define TARGET_SEMGET 2
#define TARGET_SEMCTL 3
#define TARGET_MSGSND 11
#define TARGET_MSGRCV 12
#define TARGET_MSGGET 13
#define TARGET_MSGCTL 14
#define TARGET_SHMAT 21
#define TARGET_SHMDT 22
#define TARGET_SHMGET 23
#define TARGET_SHMCTL 24
struct target_msgbuf {
int mtype;
char mtext[1];
};
struct target_ipc_kludge {
unsigned int msgp; /* Really (struct msgbuf *) */
int msgtyp;
};
struct alpha_msgbuf {
long mtype;
char mtext[4096];
};
struct target_ipc_perm {
int key;
unsigned short uid;
unsigned short gid;
unsigned short cuid;
unsigned short cgid;
unsigned short mode;
unsigned short seq;
};
struct target_msqid_ds {
struct target_ipc_perm msg_perm;
unsigned int msg_first; /* really struct target_msg* */
unsigned int msg_last; /* really struct target_msg* */
unsigned int msg_stime; /* really target_time_t */
unsigned int msg_rtime; /* really target_time_t */
unsigned int msg_ctime; /* really target_time_t */
unsigned int wwait; /* really struct wait_queue* */
unsigned int rwait; /* really struct wait_queue* */
unsigned short msg_cbytes;
unsigned short msg_qnum;
unsigned short msg_qbytes;
unsigned short msg_lspid;
unsigned short msg_lrpid;
};
struct target_shmid_ds {
struct target_ipc_perm shm_perm;
int shm_segsz;
unsigned int shm_atime; /* really target_time_t */
unsigned int shm_dtime; /* really target_time_t */
unsigned int shm_ctime; /* really target_time_t */
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
unsigned short shm_npages;
unsigned long *shm_pages;
void *attaches; /* really struct shm_desc * */
};
#define TARGET_IPC_RMID 0
#define TARGET_IPC_SET 1
#define TARGET_IPC_STAT 2
union target_semun {
int val;
unsigned int buf; /* really struct semid_ds * */
unsigned int array; /* really unsigned short * */
unsigned int __buf; /* really struct seminfo * */
unsigned int __pad; /* really void* */
};
/* soundcard defines (XXX: move them to generic file syscall_defs.h) */
#define TARGET_SNDCTL_COPR_HALT 0xc0144307
+5 -1
View File
@@ -4,7 +4,7 @@ CFLAGS=-Wall -O2 -g
LDFLAGS=
ifeq ($(ARCH),i386)
TESTS=testclone testsig testthread sha1-i386 test-i386
TESTS=testclone testsig testthread sha1-i386 test-i386 runcom
endif
TESTS+=sha1
@@ -48,5 +48,9 @@ speed: sha1 sha1-i386
time ./sha1
time $(QEMU) ./sha1-i386
# vm86 test
runcom: runcom.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
clean:
rm -f *~ *.o $(TESTS)
+79
View File
@@ -714,6 +714,10 @@ void test_segs(void)
long long ldt_table[3];
int res, res2;
char tmp;
struct {
uint32_t offset;
uint16_t seg;
} __attribute__((packed)) segoff;
ldt.entry_number = 1;
ldt.base_addr = (unsigned long)&seg_data1;
@@ -772,6 +776,14 @@ void test_segs(void)
: "r" (MK_SEL(1)), "r" (&tmp));
printf("DS[1] = %02x\n", res);
printf("SS[tmp] = %02x\n", res2);
segoff.seg = MK_SEL(2);
segoff.offset = 0xabcdef12;
asm volatile("lfs %2, %0\n\t"
"movl %%fs, %1\n\t"
: "=r" (res), "=g" (res2)
: "m" (segoff));
printf("FS:reg = %04x:%08x\n", res2, res);
}
/* 16 bit code test */
@@ -812,6 +824,71 @@ void test_code16(void)
printf("func3() = 0x%08x\n", res);
}
void test_misc(void)
{
char table[256];
int res, i;
for(i=0;i<256;i++) table[i] = 256 - i;
res = 0x12345678;
asm ("xlat" : "=a" (res) : "b" (table), "0" (res));
printf("xlat: EAX=%08x\n", res);
}
uint8_t str_buffer[4096];
#define TEST_STRING1(OP, size, DF, REP)\
{\
int esi, edi, eax, ecx, eflags;\
\
esi = (long)(str_buffer + sizeof(str_buffer) / 2);\
edi = (long)(str_buffer + sizeof(str_buffer) / 2) + 16;\
eax = 0x12345678;\
ecx = 17;\
\
asm volatile ("pushl $0\n\t"\
"popf\n\t"\
DF "\n\t"\
REP #OP size "\n\t"\
"cld\n\t"\
"pushf\n\t"\
"popl %4\n\t"\
: "=S" (esi), "=D" (edi), "=a" (eax), "=c" (ecx), "=g" (eflags)\
: "0" (esi), "1" (edi), "2" (eax), "3" (ecx));\
printf("%-10s ESI=%08x EDI=%08x EAX=%08x ECX=%08x EFL=%04x\n",\
REP #OP size, esi, edi, eax, ecx,\
eflags & (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A));\
}
#define TEST_STRING(OP, REP)\
TEST_STRING1(OP, "b", "", REP);\
TEST_STRING1(OP, "w", "", REP);\
TEST_STRING1(OP, "l", "", REP);\
TEST_STRING1(OP, "b", "std", REP);\
TEST_STRING1(OP, "w", "std", REP);\
TEST_STRING1(OP, "l", "std", REP)
void test_string(void)
{
int i;
for(i = 0;i < sizeof(str_buffer); i++)
str_buffer[i] = i + 0x56;
TEST_STRING(stos, "");
TEST_STRING(stos, "rep ");
TEST_STRING(lods, ""); /* to verify stos */
TEST_STRING(lods, "rep ");
TEST_STRING(movs, "");
TEST_STRING(movs, "rep ");
TEST_STRING(lods, ""); /* to verify stos */
/* XXX: better tests */
TEST_STRING(scas, "");
TEST_STRING(scas, "repz ");
TEST_STRING(scas, "repnz ");
TEST_STRING(cmps, "");
TEST_STRING(cmps, "repz ");
TEST_STRING(cmps, "repnz ");
}
static void *call_end __init_call = NULL;
@@ -831,6 +908,8 @@ int main(int argc, char **argv)
test_floats();
test_bcd();
test_xchg();
test_string();
test_misc();
test_lea();
test_segs();
test_code16();
+226 -164
View File
@@ -76,21 +76,16 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop)
extern FILE *logfile;
extern int loglevel;
#define PREFIX_REPZ 1
#define PREFIX_REPNZ 2
#define PREFIX_LOCK 4
#define PREFIX_CS 8
#define PREFIX_SS 0x10
#define PREFIX_DS 0x20
#define PREFIX_ES 0x40
#define PREFIX_FS 0x80
#define PREFIX_GS 0x100
#define PREFIX_DATA 0x200
#define PREFIX_ADR 0x400
#define PREFIX_FWAIT 0x800
#define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 0x02
#define PREFIX_LOCK 0x04
#define PREFIX_DATA 0x08
#define PREFIX_ADR 0x10
#define PREFIX_FWAIT 0x20
typedef struct DisasContext {
/* current insn context */
int override; /* -1 if no override */
int prefix;
int aflag, dflag;
uint8_t *pc; /* pc = eip + cs_base */
@@ -103,6 +98,7 @@ typedef struct DisasContext {
int cc_op; /* current CC operation */
int addseg; /* non zero if either DS/ES/SS have a non zero base */
int f_st; /* currently unused */
int vm86; /* vm86 mode */
} DisasContext;
/* i386 arith/logic operations */
@@ -130,7 +126,7 @@ enum {
};
enum {
#define DEF(s) INDEX_op_ ## s,
#define DEF(s, n) INDEX_op_ ## s,
#include "opc-i386.h"
#undef DEF
NB_OPS,
@@ -556,76 +552,100 @@ static GenOpFunc *gen_op_st_T0_A0[3] = {
gen_op_stl_T0_A0,
};
static GenOpFunc *gen_op_movs[6] = {
gen_op_movsb,
gen_op_movsw,
gen_op_movsl,
gen_op_rep_movsb,
gen_op_rep_movsw,
gen_op_rep_movsl,
/* the _a32 and _a16 string operations use A0 as the base register. */
#define STRINGOP(x) \
gen_op_ ## x ## b_fast, \
gen_op_ ## x ## w_fast, \
gen_op_ ## x ## l_fast, \
gen_op_ ## x ## b_a32, \
gen_op_ ## x ## w_a32, \
gen_op_ ## x ## l_a32, \
gen_op_ ## x ## b_a16, \
gen_op_ ## x ## w_a16, \
gen_op_ ## x ## l_a16,
static GenOpFunc *gen_op_movs[9 * 2] = {
STRINGOP(movs)
STRINGOP(rep_movs)
};
static GenOpFunc *gen_op_stos[6] = {
gen_op_stosb,
gen_op_stosw,
gen_op_stosl,
gen_op_rep_stosb,
gen_op_rep_stosw,
gen_op_rep_stosl,
static GenOpFunc *gen_op_stos[9 * 2] = {
STRINGOP(stos)
STRINGOP(rep_stos)
};
static GenOpFunc *gen_op_lods[6] = {
gen_op_lodsb,
gen_op_lodsw,
gen_op_lodsl,
gen_op_rep_lodsb,
gen_op_rep_lodsw,
gen_op_rep_lodsl,
static GenOpFunc *gen_op_lods[9 * 2] = {
STRINGOP(lods)
STRINGOP(rep_lods)
};
static GenOpFunc *gen_op_scas[9] = {
gen_op_scasb,
gen_op_scasw,
gen_op_scasl,
gen_op_repz_scasb,
gen_op_repz_scasw,
gen_op_repz_scasl,
gen_op_repnz_scasb,
gen_op_repnz_scasw,
gen_op_repnz_scasl,
static GenOpFunc *gen_op_scas[9 * 3] = {
STRINGOP(scas)
STRINGOP(repz_scas)
STRINGOP(repnz_scas)
};
static GenOpFunc *gen_op_cmps[9] = {
gen_op_cmpsb,
gen_op_cmpsw,
gen_op_cmpsl,
gen_op_repz_cmpsb,
gen_op_repz_cmpsw,
gen_op_repz_cmpsl,
gen_op_repnz_cmpsb,
gen_op_repnz_cmpsw,
gen_op_repnz_cmpsl,
static GenOpFunc *gen_op_cmps[9 * 3] = {
STRINGOP(cmps)
STRINGOP(repz_cmps)
STRINGOP(repnz_cmps)
};
static GenOpFunc *gen_op_ins[6] = {
gen_op_insb,
gen_op_insw,
gen_op_insl,
gen_op_rep_insb,
gen_op_rep_insw,
gen_op_rep_insl,
static GenOpFunc *gen_op_ins[9 * 2] = {
STRINGOP(ins)
STRINGOP(rep_ins)
};
static GenOpFunc *gen_op_outs[6] = {
gen_op_outsb,
gen_op_outsw,
gen_op_outsl,
gen_op_rep_outsb,
gen_op_rep_outsw,
gen_op_rep_outsl,
static GenOpFunc *gen_op_outs[9 * 2] = {
STRINGOP(outs)
STRINGOP(rep_outs)
};
static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
{
int index, override;
override = s->override;
if (s->aflag) {
/* 32 bit address */
if (s->addseg && override < 0)
override = R_DS;
if (override >= 0) {
gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
index = 3 + ot;
} else {
index = ot;
}
} else {
if (override < 0)
override = R_DS;
gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
/* 16 address, always override */
index = 6 + ot;
}
func[index]();
}
static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func)
{
int index;
if (s->aflag) {
if (s->addseg) {
index = 3 + ot;
} else {
index = ot;
}
} else {
index = 6 + ot;
}
func[index]();
}
static GenOpFunc *gen_op_in[3] = {
gen_op_inb_T0_T1,
gen_op_inw_T0_T1,
@@ -849,26 +869,10 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
int opreg;
int mod, rm, code, override, must_add_seg;
/* XXX: add a generation time variable to tell if base == 0 in DS/ES/SS */
override = -1;
override = s->override;
must_add_seg = s->addseg;
if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS |
PREFIX_ES | PREFIX_FS | PREFIX_GS)) {
if (s->prefix & PREFIX_ES)
override = R_ES;
else if (s->prefix & PREFIX_CS)
override = R_CS;
else if (s->prefix & PREFIX_SS)
override = R_SS;
else if (s->prefix & PREFIX_DS)
override = R_DS;
else if (s->prefix & PREFIX_FS)
override = R_FS;
else
override = R_GS;
if (override >= 0)
must_add_seg = 1;
}
mod = (modrm >> 6) & 3;
rm = modrm & 7;
@@ -1343,7 +1347,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
prefixes = 0;
aflag = s->code32;
dflag = s->code32;
// cur_pc = s->pc; /* for insn generation */
s->override = -1;
next_byte:
b = ldub(s->pc);
s->pc++;
@@ -1359,22 +1363,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
prefixes |= PREFIX_LOCK;
goto next_byte;
case 0x2e:
prefixes |= PREFIX_CS;
s->override = R_CS;
goto next_byte;
case 0x36:
prefixes |= PREFIX_SS;
s->override = R_SS;
goto next_byte;
case 0x3e:
prefixes |= PREFIX_DS;
s->override = R_DS;
goto next_byte;
case 0x26:
prefixes |= PREFIX_ES;
s->override = R_ES;
goto next_byte;
case 0x64:
prefixes |= PREFIX_FS;
s->override = R_FS;
goto next_byte;
case 0x65:
prefixes |= PREFIX_GS;
s->override = R_GS;
goto next_byte;
case 0x66:
prefixes |= PREFIX_DATA;
@@ -1830,6 +1834,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
}
s->cc_op = CC_OP_SUBB + ot;
break;
case 0x1c7: /* cmpxchg8b */
modrm = ldub(s->pc++);
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_cmpxchg8b();
s->cc_op = CC_OP_EFLAGS;
break;
/**************************/
/* push/pop */
@@ -2027,8 +2042,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
modrm = ldub(s->pc++);
reg = (modrm >> 3) & 7;
/* we must ensure that no segment is added */
s->prefix &= ~(PREFIX_CS | PREFIX_SS | PREFIX_DS |
PREFIX_ES | PREFIX_FS | PREFIX_GS);
s->override = -1;
val = s->addseg;
s->addseg = 0;
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
@@ -2050,26 +2064,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
offset_addr = insn_get(s, OT_WORD);
gen_op_movl_A0_im(offset_addr);
/* handle override */
/* XXX: factorize that */
{
int override, must_add_seg;
override = R_DS;
must_add_seg = s->addseg;
if (s->prefix & (PREFIX_CS | PREFIX_SS | PREFIX_DS |
PREFIX_ES | PREFIX_FS | PREFIX_GS)) {
if (s->prefix & PREFIX_ES)
override = R_ES;
else if (s->prefix & PREFIX_CS)
override = R_CS;
else if (s->prefix & PREFIX_SS)
override = R_SS;
else if (s->prefix & PREFIX_DS)
override = R_DS;
else if (s->prefix & PREFIX_FS)
override = R_FS;
else
override = R_GS;
if (s->override >= 0) {
override = s->override;
must_add_seg = 1;
} else {
override = R_DS;
}
if (must_add_seg) {
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
@@ -2083,7 +2085,29 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_st_T0_A0[ot]();
}
break;
case 0xd7: /* xlat */
gen_op_movl_A0_reg[R_EBX]();
gen_op_addl_A0_AL();
if (s->aflag == 0)
gen_op_andl_A0_ffff();
/* handle override */
{
int override, must_add_seg;
must_add_seg = s->addseg;
override = R_DS;
if (s->override >= 0) {
override = s->override;
must_add_seg = 1;
} else {
override = R_DS;
}
if (must_add_seg) {
gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
}
}
gen_op_ldub_T0_A0();
gen_op_mov_reg_T0[OT_BYTE][R_EAX]();
break;
case 0xb0 ... 0xb7: /* mov R, Ib */
val = insn_get(s, OT_BYTE);
gen_op_movl_T0_im(val);
@@ -2121,8 +2145,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
} else {
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_mov_TN_reg[ot][0][reg]();
/* for xchg, lock is implicit */
if (!(prefixes & PREFIX_LOCK))
gen_op_lock();
gen_op_ld_T1_A0[ot]();
gen_op_st_T0_A0[ot]();
if (!(prefixes & PREFIX_LOCK))
gen_op_unlock();
gen_op_mov_reg_T1[ot][reg]();
}
break;
@@ -2147,6 +2176,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_ld_T1_A0[ot]();
gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
/* load the segment first to handle exceptions properly */
@@ -2620,16 +2650,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
break;
/************************/
/* string ops */
case 0xa4: /* movsS */
case 0xa5:
if ((b & 1) == 0)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) {
gen_op_movs[3 + ot]();
gen_string_ds(s, ot, gen_op_movs + 9);
} else {
gen_op_movs[ot]();
gen_string_ds(s, ot, gen_op_movs);
}
break;
@@ -2639,10 +2671,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) {
gen_op_stos[3 + ot]();
gen_string_es(s, ot, gen_op_stos + 9);
} else {
gen_op_stos[ot]();
gen_string_es(s, ot, gen_op_stos);
}
break;
case 0xac: /* lodsS */
@@ -2652,9 +2685,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else
ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) {
gen_op_lods[3 + ot]();
gen_string_ds(s, ot, gen_op_lods + 9);
} else {
gen_op_lods[ot]();
gen_string_ds(s, ot, gen_op_lods);
}
break;
case 0xae: /* scasS */
@@ -2662,19 +2695,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
if ((b & 1) == 0)
ot = OT_BYTE;
else
ot = dflag ? OT_LONG : OT_WORD;
ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPNZ) {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_op_scas[6 + ot]();
gen_string_es(s, ot, gen_op_scas + 9 * 2);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else if (prefixes & PREFIX_REPZ) {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_op_scas[3 + ot]();
gen_string_es(s, ot, gen_op_scas + 9);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else {
gen_op_scas[ot]();
gen_string_es(s, ot, gen_op_scas);
s->cc_op = CC_OP_SUBB + ot;
}
break;
@@ -2688,21 +2721,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
if (prefixes & PREFIX_REPNZ) {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_op_cmps[6 + ot]();
gen_string_ds(s, ot, gen_op_cmps + 9 * 2);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else if (prefixes & PREFIX_REPZ) {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_op_cmps[3 + ot]();
gen_string_ds(s, ot, gen_op_cmps + 9);
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
} else {
gen_op_cmps[ot]();
gen_string_ds(s, ot, gen_op_cmps);
s->cc_op = CC_OP_SUBB + ot;
}
break;
/************************/
/* port I/O */
case 0x6c: /* insS */
case 0x6d:
if ((b & 1) == 0)
@@ -2710,9 +2740,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else
ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) {
gen_op_ins[3 + ot]();
gen_string_es(s, ot, gen_op_ins + 9);
} else {
gen_op_ins[ot]();
gen_string_es(s, ot, gen_op_ins);
}
break;
case 0x6e: /* outsS */
@@ -2722,11 +2752,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
else
ot = dflag ? OT_LONG : OT_WORD;
if (prefixes & PREFIX_REPZ) {
gen_op_outs[3 + ot]();
gen_string_ds(s, ot, gen_op_outs + 9);
} else {
gen_op_outs[ot]();
gen_string_ds(s, ot, gen_op_outs);
}
break;
/************************/
/* port I/O */
case 0xe4:
case 0xe5:
if ((b & 1) == 0)
@@ -3112,14 +3145,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0xcd: /* int N */
val = ldub(s->pc++);
/* XXX: currently we ignore the interrupt number */
gen_op_int_im((long)pc_start);
gen_op_int_im(pc_start - s->cs_base);
s->is_jmp = 1;
break;
case 0xce: /* into */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_op_into((long)pc_start, (long)s->pc);
s->is_jmp = 1;
gen_op_into();
break;
case 0x62: /* bound */
ot = dflag ? OT_LONG : OT_WORD;
modrm = ldub(s->pc++);
reg = (modrm >> 3) & 7;
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
gen_op_mov_reg_T0[ot][reg]();
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
if (ot == OT_WORD)
gen_op_boundw();
else
gen_op_boundl();
break;
case 0x1c8 ... 0x1cf: /* bswap reg */
reg = b & 7;
@@ -3150,11 +3196,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x131: /* rdtsc */
gen_op_rdtsc();
break;
#if 0
case 0x1a2: /* cpuid */
gen_insn0(OP_ASM);
gen_op_cpuid();
break;
#endif
default:
goto illegal_op;
}
@@ -3361,28 +3405,30 @@ static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
[INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
[INDEX_op_scasb] = CC_OSZAPC,
[INDEX_op_scasw] = CC_OSZAPC,
[INDEX_op_scasl] = CC_OSZAPC,
[INDEX_op_repz_scasb] = CC_OSZAPC,
[INDEX_op_repz_scasw] = CC_OSZAPC,
[INDEX_op_repz_scasl] = CC_OSZAPC,
[INDEX_op_repnz_scasb] = CC_OSZAPC,
[INDEX_op_repnz_scasw] = CC_OSZAPC,
[INDEX_op_repnz_scasl] = CC_OSZAPC,
#undef STRINGOP
#define STRINGOP(x) \
[INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \
[INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \
[INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \
[INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \
[INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \
[INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \
[INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \
[INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \
[INDEX_op_ ## x ## l_a16] = CC_OSZAPC,
[INDEX_op_cmpsb] = CC_OSZAPC,
[INDEX_op_cmpsw] = CC_OSZAPC,
[INDEX_op_cmpsl] = CC_OSZAPC,
[INDEX_op_repz_cmpsb] = CC_OSZAPC,
[INDEX_op_repz_cmpsw] = CC_OSZAPC,
[INDEX_op_repz_cmpsl] = CC_OSZAPC,
[INDEX_op_repnz_cmpsb] = CC_OSZAPC,
[INDEX_op_repnz_cmpsw] = CC_OSZAPC,
[INDEX_op_repnz_cmpsl] = CC_OSZAPC,
STRINGOP(scas)
STRINGOP(repz_scas)
STRINGOP(repnz_scas)
STRINGOP(cmps)
STRINGOP(repz_cmps)
STRINGOP(repnz_cmps)
[INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchg8b] = CC_Z,
};
/* simpler form of an operation if no flags need to be generated */
@@ -3457,21 +3503,36 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
#ifdef DEBUG_DISAS
static const char *op_str[] = {
#define DEF(s) #s,
#define DEF(s, n) #s,
#include "opc-i386.h"
#undef DEF
};
static void dump_ops(const uint16_t *opc_buf)
static uint8_t op_nb_args[] = {
#define DEF(s, n) n,
#include "opc-i386.h"
#undef DEF
};
static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
{
const uint16_t *opc_ptr;
int c;
const uint32_t *opparam_ptr;
int c, n, i;
opc_ptr = opc_buf;
opparam_ptr = opparam_buf;
for(;;) {
c = *opc_ptr++;
fprintf(logfile, "0x%04x: %s\n", opc_ptr - opc_buf - 1, op_str[c]);
n = op_nb_args[c];
fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]);
for(i = 0; i < n; i++) {
fprintf(logfile, " 0x%x", opparam_ptr[i]);
}
fprintf(logfile, "\n");
if (c == INDEX_op_end)
break;
opparam_ptr += n;
}
}
@@ -3509,6 +3570,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1;
dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1;
dc->cc_op = CC_OP_DYNAMIC;
dc->cs_base = cs_base;
@@ -3572,7 +3634,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
fprintf(logfile, "\n");
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf);
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
@@ -3583,7 +3645,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "AFTER FLAGS OPT:\n");
dump_ops(gen_opc_buf);
dump_ops(gen_opc_buf, gen_opparam_buf);
fprintf(logfile, "\n");
}
#endif
@@ -3645,8 +3707,8 @@ CPUX86State *cpu_x86_init(void)
for(i = 0;i < 8; i++)
env->fptags[i] = 1;
env->fpuc = 0x37f;
/* flags setup */
env->eflags = 0;
/* flags setup : we activate the IRQs by default as in user mode */
env->eflags = 0x2 | IF_MASK;
/* init various static tables */
if (!inited) {