From d2fd1af76777687697674e7a49eeceac83907f3e Mon Sep 17 00:00:00 2001 From: bellard Date: Wed, 14 Nov 2007 18:08:56 +0000 Subject: x86_64 linux user emulation git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3646 c046a42c-6fe2-441c-8c8c-71466251a162 --- linux-user/main.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 8 deletions(-) (limited to 'linux-user/main.c') diff --git a/linux-user/main.c b/linux-user/main.c index ac7a174d97..cfe2a0e369 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -147,8 +147,11 @@ static void write_dt(void *ptr, unsigned long addr, unsigned long limit, p[1] = tswapl(e2); } -static void set_gate(void *ptr, unsigned int type, unsigned int dpl, - unsigned long addr, unsigned int sel) +#if TARGET_X86_64 +uint64_t idt_table[512]; + +static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, + uint64_t addr, unsigned int sel) { unsigned int e1, e2; uint32_t *p; @@ -157,15 +160,34 @@ static void set_gate(void *ptr, unsigned int type, unsigned int dpl, p = ptr; p[0] = tswapl(e1); p[1] = tswapl(e2); + p[2] = addr >> 32; } - +/* only dpl matters as we do only user space emulation */ +static void set_idt(int n, unsigned int dpl) +{ + set_gate64(idt_table + n * 2, 0, dpl, 0, 0); +} +#else uint64_t idt_table[256]; +static void set_gate(void *ptr, unsigned int type, unsigned int dpl, + uint32_t addr, unsigned int sel) +{ + unsigned int e1, e2; + uint32_t *p; + e1 = (addr & 0xffff) | (sel << 16); + e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); + p = ptr; + p[0] = tswapl(e1); + p[1] = tswapl(e2); +} + /* only dpl matters as we do only user space emulation */ static void set_idt(int n, unsigned int dpl) { set_gate(idt_table + n, 0, dpl, 0, 0); } +#endif void cpu_loop(CPUX86State *env) { @@ -177,7 +199,7 @@ void cpu_loop(CPUX86State *env) trapnr = cpu_x86_exec(env); switch(trapnr) { case 0x80: - /* linux syscall */ + /* linux syscall from int $0x80 */ env->regs[R_EAX] = do_syscall(env, env->regs[R_EAX], env->regs[R_EBX], @@ -187,6 +209,20 @@ void cpu_loop(CPUX86State *env) env->regs[R_EDI], env->regs[R_EBP]); break; +#ifndef TARGET_ABI32 + case EXCP_SYSCALL: + /* linux syscall from syscall intruction */ + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], + env->regs[R_EDI], + env->regs[R_ESI], + env->regs[R_EDX], + env->regs[10], + env->regs[8], + env->regs[9]); + env->eip = env->exception_next_eip; + break; +#endif case EXCP0B_NOSEG: case EXCP0C_STACK: info.si_signo = SIGBUS; @@ -196,6 +232,7 @@ void cpu_loop(CPUX86State *env) queue_signal(info.si_signo, &info); break; case EXCP0D_GPF: + /* XXX: potential problem if ABI32 */ #ifndef TARGET_X86_64 if (env->eflags & VM_MASK) { handle_vm86_fault(env); @@ -2075,12 +2112,18 @@ int main(int argc, char **argv) env->cr[4] |= CR4_OSFXSR_MASK; env->hflags |= HF_OSFXSR_MASK; } +#ifndef TARGET_ABI32 + /* enable 64 bit mode */ + env->cr[4] |= CR4_PAE_MASK; + env->efer |= MSR_EFER_LMA; + env->hflags |= HF_LMA_MASK; +#endif /* flags setup : we activate the IRQs by default as in user mode */ env->eflags |= IF_MASK; /* linux register setup */ -#if defined(TARGET_X86_64) +#ifndef TARGET_ABI32 env->regs[R_EAX] = regs->rax; env->regs[R_EBX] = regs->rbx; env->regs[R_ECX] = regs->rcx; @@ -2131,24 +2174,38 @@ int main(int argc, char **argv) { uint64_t *gdt_table; gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES); - env->gdt.base = h2g(gdt_table); + env->gdt.base = h2g((unsigned long)gdt_table); env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; +#ifdef TARGET_ABI32 write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); +#else + /* 64 bit code segment */ + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | + DESC_L_MASK | + (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); +#endif write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); } cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_SS, __USER_DS); +#ifdef TARGET_ABI32 cpu_x86_load_seg(env, R_DS, __USER_DS); cpu_x86_load_seg(env, R_ES, __USER_DS); - cpu_x86_load_seg(env, R_SS, __USER_DS); cpu_x86_load_seg(env, R_FS, __USER_DS); cpu_x86_load_seg(env, R_GS, __USER_DS); - /* This hack makes Wine work... */ env->segs[R_FS].selector = 0; +#else + cpu_x86_load_seg(env, R_DS, 0); + cpu_x86_load_seg(env, R_ES, 0); + cpu_x86_load_seg(env, R_FS, 0); + cpu_x86_load_seg(env, R_GS, 0); +#endif #elif defined(TARGET_ARM) { int i; -- cgit v1.2.3