Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6630e791b | ||
|
|
168485b75b | ||
|
|
5cd4393b14 | ||
|
|
7ed601b782 | ||
|
|
d1f2367bc0 | ||
|
|
851e67a1b4 | ||
|
|
fc2b4c4879 | ||
|
|
9c605cb135 | ||
|
|
24f9e90b0e | ||
|
|
a4a0ffdb2b | ||
|
|
0ea00c9a3c | ||
|
|
e1d4294a45 | ||
|
|
c3c7c29246 | ||
|
|
31bb950be6 | ||
|
|
8083a3e508 | ||
|
|
644c433cb3 |
No files matched your search
@@ -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
|
||||
|
||||
|
||||
+20
-14
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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 = ®s1;
|
||||
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
+25
-226
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
@@ -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
@@ -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, ®_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, ®_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, ®_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, ®_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, ®_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) {
|
||||
|
||||
Reference in new issue
Block a user