Loading Changelog +33 −0 Original line number Diff line number Diff line version 0.1.4: - more accurate VM86 emulation (can launch small DOS 16 bit executables in wine). - fixed push/pop fs/gs - added iret instruction. version 0.1.3: - S390 support (Ulrich Weigand) - glibc 2.3.x compile fix (Ulrich Weigand) - socketcall endian fix (Ulrich Weigand) - struct sockaddr endian fix (Ulrich Weigand) - sendmsg/recvmsg endian fix (Ulrich Weigand) - execve endian fix (Ulrich Weigand) - fdset endian fix (Ulrich Weigand) - partial setsockopt syscall support (Ulrich Weigand) - more accurate pushf/popf emulation - first partial vm86() syscall support (can be used with runcom example). - added bound, cmpxchg8b, cpuid instructions - added 16 bit addressing support/override for string operations - poll() fix version 0.1.2: - compile fixes - xlat instruction - xchg instruction memory lock - added simple vm86 example (not working with QEMU yet). The 54 byte DOS executable 'pi_10.com' program was released by Bertram Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html). version 0.1.1: - glibc 2.2 compilation fixes - added -s and -L options - binary distribution of x86 glibc and wine - big endian fixes in ELF loader and getdents. version 0.1: Loading TODO +3 −2 Original line number Diff line number Diff line - fix thread locks - fix thread stack liberation - fix x86 stack allocation - optimize translated cache chaining (DLL PLT-like system) - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) - finish signal handing (fp87 state, more siginfo conversions) - verify thread support (clone() and various locks) - vm86 syscall support - overrides/16bit for string ops - make it self runnable (use same trick as ld.so : include its own relocator and libc) - improved 16 bit support - fix FPU exceptions (in particular: gen_op_fpush not before mem load) cpu-i386.h +18 −18 Original line number Diff line number Diff line Loading @@ -68,24 +68,24 @@ #define VIP_MASK 0x00100000 #define ID_MASK 0x00200000 #define EXCP00_DIVZ 1 #define EXCP01_SSTP 2 #define EXCP02_NMI 3 #define EXCP03_INT3 4 #define EXCP04_INTO 5 #define EXCP05_BOUND 6 #define EXCP06_ILLOP 7 #define EXCP07_PREX 8 #define EXCP08_DBLE 9 #define EXCP09_XERR 10 #define EXCP0A_TSS 11 #define EXCP0B_NOSEG 12 #define EXCP0C_STACK 13 #define EXCP0D_GPF 14 #define EXCP0E_PAGE 15 #define EXCP10_COPR 17 #define EXCP11_ALGN 18 #define EXCP12_MCHK 19 #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 #define EXCP02_NMI 2 #define EXCP03_INT3 3 #define EXCP04_INTO 4 #define EXCP05_BOUND 5 #define EXCP06_ILLOP 6 #define EXCP07_PREX 7 #define EXCP08_DBLE 8 #define EXCP09_XERR 9 #define EXCP0A_TSS 10 #define EXCP0B_NOSEG 11 #define EXCP0C_STACK 12 #define EXCP0D_GPF 13 #define EXCP0E_PAGE 14 #define EXCP10_COPR 16 #define EXCP11_ALGN 17 #define EXCP12_MCHK 18 #define EXCP_INTERRUPT 256 /* async interruption */ Loading linux-user/main.c +167 −64 Original line number Diff line number Diff line Loading @@ -106,41 +106,39 @@ uint64_t gdt_table[6]; //#define DEBUG_VM86 void cpu_loop(struct CPUX86State *env) static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) { int err; uint8_t *pc; target_siginfo_t info; return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1; } for(;;) { err = cpu_x86_exec(env); pc = env->seg_cache[R_CS].base + env->eip; switch(err) { case EXCP0D_GPF: 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; static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) { return (uint8_t *)((seg << 4) + (reg & 0xffff)); } /* 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; static inline void pushw(CPUX86State *env, int val) { env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | ((env->regs[R_ESP] - 2) & 0xffff); *(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val; } static inline unsigned int get_vflags(CPUX86State *env) { unsigned int eflags; eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); if (eflags & VIF_MASK) eflags |= IF_MASK; return eflags; } void save_v86_state(CPUX86State *env) { TaskState *ts = env->opaque; #ifdef DEBUG_VM86 printf("ret=0x%x\n", ret); printf("save_v86_state\n"); #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]); Loading @@ -157,8 +155,10 @@ void cpu_loop(struct CPUX86State *env) 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]); ts->target_v86->regs.eflags = tswap32(env->eflags); /* restore 32 bit registers */ env->regs[R_EAX] = ts->vm86_saved_regs.eax; 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; Loading @@ -175,8 +175,103 @@ void cpu_loop(struct CPUX86State *env) 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); } /* return from vm86 mode to 32 bit. The vm86() syscall will return 'retval' */ static inline void return_to_32bit(CPUX86State *env, int retval) { #ifdef DEBUG_VM86 printf("return_to_32bit: ret=0x%x\n", retval); #endif save_v86_state(env); env->regs[R_EAX] = retval; } /* handle VM86 interrupt (NOTE: the CPU core currently does not support TSS interrupt revectoring, so this code is always executed) */ static void do_int(CPUX86State *env, int intno) { TaskState *ts = env->opaque; uint32_t *int_ptr, segoffs; if (env->segs[R_CS] == TARGET_BIOSSEG) goto cannot_handle; /* XXX: I am not sure this is really useful */ if (is_revectored(intno, &ts->target_v86->int_revectored)) goto cannot_handle; if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, &ts->target_v86->int21_revectored)) goto cannot_handle; int_ptr = (uint32_t *)(intno << 2); segoffs = tswap32(*int_ptr); if ((segoffs >> 16) == TARGET_BIOSSEG) goto cannot_handle; #ifdef DEBUG_VM86 printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", intno, segoffs >> 16, segoffs & 0xffff); #endif /* save old state */ pushw(env, get_vflags(env)); pushw(env, env->segs[R_CS]); pushw(env, env->eip); /* goto interrupt handler */ env->eip = segoffs & 0xffff; cpu_x86_load_seg(env, R_CS, segoffs >> 16); env->eflags &= ~(VIF_MASK | TF_MASK); return; cannot_handle: #ifdef DEBUG_VM86 printf("VM86: return to 32 bits int 0x%x\n", intno); #endif return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); } void cpu_loop(struct CPUX86State *env) { int trapnr; uint8_t *pc; target_siginfo_t info; env->regs[R_EAX] = ret; for(;;) { trapnr = cpu_x86_exec(env); pc = env->seg_cache[R_CS].base + env->eip; switch(trapnr) { case EXCP0D_GPF: if (env->eflags & VM_MASK) { #ifdef DEBUG_VM86 printf("VM86 exception %04x:%08x %02x %02x\n", env->segs[R_CS], env->eip, pc[0], pc[1]); #endif /* VM86 mode */ switch(pc[0]) { case 0xcd: /* int */ env->eip += 2; do_int(env, pc[1]); break; case 0x66: switch(pc[1]) { case 0xfb: /* sti */ case 0x9d: /* popf */ case 0xcf: /* iret */ env->eip += 2; return_to_32bit(env, TARGET_VM86_STI); break; default: goto vm86_gpf; } break; case 0xfb: /* sti */ case 0x9d: /* popf */ case 0xcf: /* iret */ env->eip++; return_to_32bit(env, TARGET_VM86_STI); break; default: vm86_gpf: /* real VM86 GPF exception */ return_to_32bit(env, TARGET_VM86_UNKNOWN); break; } } else { if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ Loading @@ -200,20 +295,28 @@ void cpu_loop(struct CPUX86State *env) } break; case EXCP00_DIVZ: if (env->eflags & VM_MASK) { do_int(env, trapnr); } else { /* division by zero */ info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = TARGET_FPE_INTDIV; info._sifields._sigfault._addr = env->eip; queue_signal(info.si_signo, &info); } break; case EXCP04_INTO: case EXCP05_BOUND: if (env->eflags & VM_MASK) { do_int(env, trapnr); } else { 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 EXCP06_ILLOP: info.si_signo = SIGILL; Loading @@ -226,8 +329,8 @@ void cpu_loop(struct CPUX86State *env) /* just indicate that signals should be handled asap */ break; default: fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", (long)pc, err); fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); } process_pending_signals(env); Loading linux-user/qemu.h +1 −0 Original line number Diff line number Diff line Loading @@ -74,5 +74,6 @@ void cpu_loop(CPUX86State *env); void process_pending_signals(void *cpu_env); void signal_init(void); int queue_signal(int sig, target_siginfo_t *info); void save_v86_state(CPUX86State *env); #endif Loading
Changelog +33 −0 Original line number Diff line number Diff line version 0.1.4: - more accurate VM86 emulation (can launch small DOS 16 bit executables in wine). - fixed push/pop fs/gs - added iret instruction. version 0.1.3: - S390 support (Ulrich Weigand) - glibc 2.3.x compile fix (Ulrich Weigand) - socketcall endian fix (Ulrich Weigand) - struct sockaddr endian fix (Ulrich Weigand) - sendmsg/recvmsg endian fix (Ulrich Weigand) - execve endian fix (Ulrich Weigand) - fdset endian fix (Ulrich Weigand) - partial setsockopt syscall support (Ulrich Weigand) - more accurate pushf/popf emulation - first partial vm86() syscall support (can be used with runcom example). - added bound, cmpxchg8b, cpuid instructions - added 16 bit addressing support/override for string operations - poll() fix version 0.1.2: - compile fixes - xlat instruction - xchg instruction memory lock - added simple vm86 example (not working with QEMU yet). The 54 byte DOS executable 'pi_10.com' program was released by Bertram Felgenhauer (more information at http://www.boo.net/~jasonp/pipage.html). version 0.1.1: - glibc 2.2 compilation fixes - added -s and -L options - binary distribution of x86 glibc and wine - big endian fixes in ELF loader and getdents. version 0.1: Loading
TODO +3 −2 Original line number Diff line number Diff line - fix thread locks - fix thread stack liberation - fix x86 stack allocation - optimize translated cache chaining (DLL PLT-like system) - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit issues, fix 16 bit uid issues) - finish signal handing (fp87 state, more siginfo conversions) - verify thread support (clone() and various locks) - vm86 syscall support - overrides/16bit for string ops - make it self runnable (use same trick as ld.so : include its own relocator and libc) - improved 16 bit support - fix FPU exceptions (in particular: gen_op_fpush not before mem load)
cpu-i386.h +18 −18 Original line number Diff line number Diff line Loading @@ -68,24 +68,24 @@ #define VIP_MASK 0x00100000 #define ID_MASK 0x00200000 #define EXCP00_DIVZ 1 #define EXCP01_SSTP 2 #define EXCP02_NMI 3 #define EXCP03_INT3 4 #define EXCP04_INTO 5 #define EXCP05_BOUND 6 #define EXCP06_ILLOP 7 #define EXCP07_PREX 8 #define EXCP08_DBLE 9 #define EXCP09_XERR 10 #define EXCP0A_TSS 11 #define EXCP0B_NOSEG 12 #define EXCP0C_STACK 13 #define EXCP0D_GPF 14 #define EXCP0E_PAGE 15 #define EXCP10_COPR 17 #define EXCP11_ALGN 18 #define EXCP12_MCHK 19 #define EXCP00_DIVZ 0 #define EXCP01_SSTP 1 #define EXCP02_NMI 2 #define EXCP03_INT3 3 #define EXCP04_INTO 4 #define EXCP05_BOUND 5 #define EXCP06_ILLOP 6 #define EXCP07_PREX 7 #define EXCP08_DBLE 8 #define EXCP09_XERR 9 #define EXCP0A_TSS 10 #define EXCP0B_NOSEG 11 #define EXCP0C_STACK 12 #define EXCP0D_GPF 13 #define EXCP0E_PAGE 14 #define EXCP10_COPR 16 #define EXCP11_ALGN 17 #define EXCP12_MCHK 18 #define EXCP_INTERRUPT 256 /* async interruption */ Loading
linux-user/main.c +167 −64 Original line number Diff line number Diff line Loading @@ -106,41 +106,39 @@ uint64_t gdt_table[6]; //#define DEBUG_VM86 void cpu_loop(struct CPUX86State *env) static inline int is_revectored(int nr, struct target_revectored_struct *bitmap) { int err; uint8_t *pc; target_siginfo_t info; return (tswap32(bitmap->__map[nr >> 5]) >> (nr & 0x1f)) & 1; } for(;;) { err = cpu_x86_exec(env); pc = env->seg_cache[R_CS].base + env->eip; switch(err) { case EXCP0D_GPF: 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; static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg) { return (uint8_t *)((seg << 4) + (reg & 0xffff)); } /* 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; static inline void pushw(CPUX86State *env, int val) { env->regs[R_ESP] = (env->regs[R_ESP] & ~0xffff) | ((env->regs[R_ESP] - 2) & 0xffff); *(uint16_t *)seg_to_linear(env->segs[R_SS], env->regs[R_ESP]) = val; } static inline unsigned int get_vflags(CPUX86State *env) { unsigned int eflags; eflags = env->eflags & ~(VM_MASK | RF_MASK | IF_MASK); if (eflags & VIF_MASK) eflags |= IF_MASK; return eflags; } void save_v86_state(CPUX86State *env) { TaskState *ts = env->opaque; #ifdef DEBUG_VM86 printf("ret=0x%x\n", ret); printf("save_v86_state\n"); #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]); Loading @@ -157,8 +155,10 @@ void cpu_loop(struct CPUX86State *env) 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]); ts->target_v86->regs.eflags = tswap32(env->eflags); /* restore 32 bit registers */ env->regs[R_EAX] = ts->vm86_saved_regs.eax; 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; Loading @@ -175,8 +175,103 @@ void cpu_loop(struct CPUX86State *env) 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); } /* return from vm86 mode to 32 bit. The vm86() syscall will return 'retval' */ static inline void return_to_32bit(CPUX86State *env, int retval) { #ifdef DEBUG_VM86 printf("return_to_32bit: ret=0x%x\n", retval); #endif save_v86_state(env); env->regs[R_EAX] = retval; } /* handle VM86 interrupt (NOTE: the CPU core currently does not support TSS interrupt revectoring, so this code is always executed) */ static void do_int(CPUX86State *env, int intno) { TaskState *ts = env->opaque; uint32_t *int_ptr, segoffs; if (env->segs[R_CS] == TARGET_BIOSSEG) goto cannot_handle; /* XXX: I am not sure this is really useful */ if (is_revectored(intno, &ts->target_v86->int_revectored)) goto cannot_handle; if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, &ts->target_v86->int21_revectored)) goto cannot_handle; int_ptr = (uint32_t *)(intno << 2); segoffs = tswap32(*int_ptr); if ((segoffs >> 16) == TARGET_BIOSSEG) goto cannot_handle; #ifdef DEBUG_VM86 printf("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", intno, segoffs >> 16, segoffs & 0xffff); #endif /* save old state */ pushw(env, get_vflags(env)); pushw(env, env->segs[R_CS]); pushw(env, env->eip); /* goto interrupt handler */ env->eip = segoffs & 0xffff; cpu_x86_load_seg(env, R_CS, segoffs >> 16); env->eflags &= ~(VIF_MASK | TF_MASK); return; cannot_handle: #ifdef DEBUG_VM86 printf("VM86: return to 32 bits int 0x%x\n", intno); #endif return_to_32bit(env, TARGET_VM86_INTx | (intno << 8)); } void cpu_loop(struct CPUX86State *env) { int trapnr; uint8_t *pc; target_siginfo_t info; env->regs[R_EAX] = ret; for(;;) { trapnr = cpu_x86_exec(env); pc = env->seg_cache[R_CS].base + env->eip; switch(trapnr) { case EXCP0D_GPF: if (env->eflags & VM_MASK) { #ifdef DEBUG_VM86 printf("VM86 exception %04x:%08x %02x %02x\n", env->segs[R_CS], env->eip, pc[0], pc[1]); #endif /* VM86 mode */ switch(pc[0]) { case 0xcd: /* int */ env->eip += 2; do_int(env, pc[1]); break; case 0x66: switch(pc[1]) { case 0xfb: /* sti */ case 0x9d: /* popf */ case 0xcf: /* iret */ env->eip += 2; return_to_32bit(env, TARGET_VM86_STI); break; default: goto vm86_gpf; } break; case 0xfb: /* sti */ case 0x9d: /* popf */ case 0xcf: /* iret */ env->eip++; return_to_32bit(env, TARGET_VM86_STI); break; default: vm86_gpf: /* real VM86 GPF exception */ return_to_32bit(env, TARGET_VM86_UNKNOWN); break; } } else { if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ Loading @@ -200,20 +295,28 @@ void cpu_loop(struct CPUX86State *env) } break; case EXCP00_DIVZ: if (env->eflags & VM_MASK) { do_int(env, trapnr); } else { /* division by zero */ info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = TARGET_FPE_INTDIV; info._sifields._sigfault._addr = env->eip; queue_signal(info.si_signo, &info); } break; case EXCP04_INTO: case EXCP05_BOUND: if (env->eflags & VM_MASK) { do_int(env, trapnr); } else { 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 EXCP06_ILLOP: info.si_signo = SIGILL; Loading @@ -226,8 +329,8 @@ void cpu_loop(struct CPUX86State *env) /* just indicate that signals should be handled asap */ break; default: fprintf(stderr, "0x%08lx: Unknown exception CPU %d, aborting\n", (long)pc, err); fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", (long)pc, trapnr); abort(); } process_pending_signals(env); Loading
linux-user/qemu.h +1 −0 Original line number Diff line number Diff line Loading @@ -74,5 +74,6 @@ void cpu_loop(CPUX86State *env); void process_pending_signals(void *cpu_env); void signal_init(void); int queue_signal(int sig, target_siginfo_t *info); void save_v86_state(CPUX86State *env); #endif