1cd71c089SLaurent Vivier /* 2cd71c089SLaurent Vivier * qemu user cpu loop 3cd71c089SLaurent Vivier * 4cd71c089SLaurent Vivier * Copyright (c) 2003-2008 Fabrice Bellard 5cd71c089SLaurent Vivier * 6cd71c089SLaurent Vivier * This program is free software; you can redistribute it and/or modify 7cd71c089SLaurent Vivier * it under the terms of the GNU General Public License as published by 8cd71c089SLaurent Vivier * the Free Software Foundation; either version 2 of the License, or 9cd71c089SLaurent Vivier * (at your option) any later version. 10cd71c089SLaurent Vivier * 11cd71c089SLaurent Vivier * This program is distributed in the hope that it will be useful, 12cd71c089SLaurent Vivier * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cd71c089SLaurent Vivier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14cd71c089SLaurent Vivier * GNU General Public License for more details. 15cd71c089SLaurent Vivier * 16cd71c089SLaurent Vivier * You should have received a copy of the GNU General Public License 17cd71c089SLaurent Vivier * along with this program; if not, see <http://www.gnu.org/licenses/>. 18cd71c089SLaurent Vivier */ 19cd71c089SLaurent Vivier 20cd71c089SLaurent Vivier #include "qemu/osdep.h" 21a8d25326SMarkus Armbruster #include "qemu-common.h" 22cd71c089SLaurent Vivier #include "qemu.h" 23cd71c089SLaurent Vivier #include "cpu_loop-common.h" 24cd71c089SLaurent Vivier 253f8258c1SLaurent Vivier /***********************************************************/ 263f8258c1SLaurent Vivier /* CPUX86 core interface */ 273f8258c1SLaurent Vivier 283f8258c1SLaurent Vivier uint64_t cpu_get_tsc(CPUX86State *env) 293f8258c1SLaurent Vivier { 303f8258c1SLaurent Vivier return cpu_get_host_ticks(); 313f8258c1SLaurent Vivier } 323f8258c1SLaurent Vivier 333f8258c1SLaurent Vivier static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 343f8258c1SLaurent Vivier int flags) 353f8258c1SLaurent Vivier { 363f8258c1SLaurent Vivier unsigned int e1, e2; 373f8258c1SLaurent Vivier uint32_t *p; 383f8258c1SLaurent Vivier e1 = (addr << 16) | (limit & 0xffff); 393f8258c1SLaurent Vivier e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); 403f8258c1SLaurent Vivier e2 |= flags; 413f8258c1SLaurent Vivier p = ptr; 423f8258c1SLaurent Vivier p[0] = tswap32(e1); 433f8258c1SLaurent Vivier p[1] = tswap32(e2); 443f8258c1SLaurent Vivier } 453f8258c1SLaurent Vivier 463f8258c1SLaurent Vivier static uint64_t *idt_table; 473f8258c1SLaurent Vivier #ifdef TARGET_X86_64 483f8258c1SLaurent Vivier static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, 493f8258c1SLaurent Vivier uint64_t addr, unsigned int sel) 503f8258c1SLaurent Vivier { 513f8258c1SLaurent Vivier uint32_t *p, e1, e2; 523f8258c1SLaurent Vivier e1 = (addr & 0xffff) | (sel << 16); 533f8258c1SLaurent Vivier e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 543f8258c1SLaurent Vivier p = ptr; 553f8258c1SLaurent Vivier p[0] = tswap32(e1); 563f8258c1SLaurent Vivier p[1] = tswap32(e2); 573f8258c1SLaurent Vivier p[2] = tswap32(addr >> 32); 583f8258c1SLaurent Vivier p[3] = 0; 593f8258c1SLaurent Vivier } 603f8258c1SLaurent Vivier /* only dpl matters as we do only user space emulation */ 613f8258c1SLaurent Vivier static void set_idt(int n, unsigned int dpl) 623f8258c1SLaurent Vivier { 633f8258c1SLaurent Vivier set_gate64(idt_table + n * 2, 0, dpl, 0, 0); 643f8258c1SLaurent Vivier } 653f8258c1SLaurent Vivier #else 663f8258c1SLaurent Vivier static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 673f8258c1SLaurent Vivier uint32_t addr, unsigned int sel) 683f8258c1SLaurent Vivier { 693f8258c1SLaurent Vivier uint32_t *p, e1, e2; 703f8258c1SLaurent Vivier e1 = (addr & 0xffff) | (sel << 16); 713f8258c1SLaurent Vivier e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 723f8258c1SLaurent Vivier p = ptr; 733f8258c1SLaurent Vivier p[0] = tswap32(e1); 743f8258c1SLaurent Vivier p[1] = tswap32(e2); 753f8258c1SLaurent Vivier } 763f8258c1SLaurent Vivier 773f8258c1SLaurent Vivier /* only dpl matters as we do only user space emulation */ 783f8258c1SLaurent Vivier static void set_idt(int n, unsigned int dpl) 793f8258c1SLaurent Vivier { 803f8258c1SLaurent Vivier set_gate(idt_table + n, 0, dpl, 0, 0); 813f8258c1SLaurent Vivier } 823f8258c1SLaurent Vivier #endif 833f8258c1SLaurent Vivier 84acf768a9SRichard Henderson static void gen_signal(CPUX86State *env, int sig, int code, abi_ptr addr) 85acf768a9SRichard Henderson { 86acf768a9SRichard Henderson target_siginfo_t info = { 87acf768a9SRichard Henderson .si_signo = sig, 88acf768a9SRichard Henderson .si_code = code, 89acf768a9SRichard Henderson ._sifields._sigfault._addr = addr 90acf768a9SRichard Henderson }; 91acf768a9SRichard Henderson 92acf768a9SRichard Henderson queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 93acf768a9SRichard Henderson } 94acf768a9SRichard Henderson 95*b26491b4SRichard Henderson #ifdef TARGET_X86_64 96*b26491b4SRichard Henderson static bool write_ok_or_segv(CPUX86State *env, abi_ptr addr, size_t len) 97*b26491b4SRichard Henderson { 98*b26491b4SRichard Henderson /* 99*b26491b4SRichard Henderson * For all the vsyscalls, NULL means "don't write anything" not 100*b26491b4SRichard Henderson * "write it at address 0". 101*b26491b4SRichard Henderson */ 102*b26491b4SRichard Henderson if (addr == 0 || access_ok(VERIFY_WRITE, addr, len)) { 103*b26491b4SRichard Henderson return true; 104*b26491b4SRichard Henderson } 105*b26491b4SRichard Henderson 106*b26491b4SRichard Henderson env->error_code = PG_ERROR_W_MASK | PG_ERROR_U_MASK; 107*b26491b4SRichard Henderson gen_signal(env, TARGET_SIGSEGV, TARGET_SEGV_MAPERR, addr); 108*b26491b4SRichard Henderson return false; 109*b26491b4SRichard Henderson } 110*b26491b4SRichard Henderson 111*b26491b4SRichard Henderson /* 112*b26491b4SRichard Henderson * Since v3.1, the kernel traps and emulates the vsyscall page. 113*b26491b4SRichard Henderson * Entry points other than the official generate SIGSEGV. 114*b26491b4SRichard Henderson */ 115*b26491b4SRichard Henderson static void emulate_vsyscall(CPUX86State *env) 116*b26491b4SRichard Henderson { 117*b26491b4SRichard Henderson int syscall; 118*b26491b4SRichard Henderson abi_ulong ret; 119*b26491b4SRichard Henderson uint64_t caller; 120*b26491b4SRichard Henderson 121*b26491b4SRichard Henderson /* 122*b26491b4SRichard Henderson * Validate the entry point. We have already validated the page 123*b26491b4SRichard Henderson * during translation to get here; now verify the offset. 124*b26491b4SRichard Henderson */ 125*b26491b4SRichard Henderson switch (env->eip & ~TARGET_PAGE_MASK) { 126*b26491b4SRichard Henderson case 0x000: 127*b26491b4SRichard Henderson syscall = TARGET_NR_gettimeofday; 128*b26491b4SRichard Henderson break; 129*b26491b4SRichard Henderson case 0x400: 130*b26491b4SRichard Henderson syscall = TARGET_NR_time; 131*b26491b4SRichard Henderson break; 132*b26491b4SRichard Henderson case 0x800: 133*b26491b4SRichard Henderson syscall = TARGET_NR_getcpu; 134*b26491b4SRichard Henderson break; 135*b26491b4SRichard Henderson default: 136*b26491b4SRichard Henderson goto sigsegv; 137*b26491b4SRichard Henderson } 138*b26491b4SRichard Henderson 139*b26491b4SRichard Henderson /* 140*b26491b4SRichard Henderson * Validate the return address. 141*b26491b4SRichard Henderson * Note that the kernel treats this the same as an invalid entry point. 142*b26491b4SRichard Henderson */ 143*b26491b4SRichard Henderson if (get_user_u64(caller, env->regs[R_ESP])) { 144*b26491b4SRichard Henderson goto sigsegv; 145*b26491b4SRichard Henderson } 146*b26491b4SRichard Henderson 147*b26491b4SRichard Henderson /* 148*b26491b4SRichard Henderson * Validate the the pointer arguments. 149*b26491b4SRichard Henderson */ 150*b26491b4SRichard Henderson switch (syscall) { 151*b26491b4SRichard Henderson case TARGET_NR_gettimeofday: 152*b26491b4SRichard Henderson if (!write_ok_or_segv(env, env->regs[R_EDI], 153*b26491b4SRichard Henderson sizeof(struct target_timeval)) || 154*b26491b4SRichard Henderson !write_ok_or_segv(env, env->regs[R_ESI], 155*b26491b4SRichard Henderson sizeof(struct target_timezone))) { 156*b26491b4SRichard Henderson return; 157*b26491b4SRichard Henderson } 158*b26491b4SRichard Henderson break; 159*b26491b4SRichard Henderson case TARGET_NR_time: 160*b26491b4SRichard Henderson if (!write_ok_or_segv(env, env->regs[R_EDI], sizeof(abi_long))) { 161*b26491b4SRichard Henderson return; 162*b26491b4SRichard Henderson } 163*b26491b4SRichard Henderson break; 164*b26491b4SRichard Henderson case TARGET_NR_getcpu: 165*b26491b4SRichard Henderson if (!write_ok_or_segv(env, env->regs[R_EDI], sizeof(uint32_t)) || 166*b26491b4SRichard Henderson !write_ok_or_segv(env, env->regs[R_ESI], sizeof(uint32_t))) { 167*b26491b4SRichard Henderson return; 168*b26491b4SRichard Henderson } 169*b26491b4SRichard Henderson break; 170*b26491b4SRichard Henderson default: 171*b26491b4SRichard Henderson g_assert_not_reached(); 172*b26491b4SRichard Henderson } 173*b26491b4SRichard Henderson 174*b26491b4SRichard Henderson /* 175*b26491b4SRichard Henderson * Perform the syscall. None of the vsyscalls should need restarting. 176*b26491b4SRichard Henderson */ 177*b26491b4SRichard Henderson ret = do_syscall(env, syscall, env->regs[R_EDI], env->regs[R_ESI], 178*b26491b4SRichard Henderson env->regs[R_EDX], env->regs[10], env->regs[8], 179*b26491b4SRichard Henderson env->regs[9], 0, 0); 180*b26491b4SRichard Henderson g_assert(ret != -TARGET_ERESTARTSYS); 181*b26491b4SRichard Henderson g_assert(ret != -TARGET_QEMU_ESIGRETURN); 182*b26491b4SRichard Henderson if (ret == -TARGET_EFAULT) { 183*b26491b4SRichard Henderson goto sigsegv; 184*b26491b4SRichard Henderson } 185*b26491b4SRichard Henderson env->regs[R_EAX] = ret; 186*b26491b4SRichard Henderson 187*b26491b4SRichard Henderson /* Emulate a ret instruction to leave the vsyscall page. */ 188*b26491b4SRichard Henderson env->eip = caller; 189*b26491b4SRichard Henderson env->regs[R_ESP] += 8; 190*b26491b4SRichard Henderson return; 191*b26491b4SRichard Henderson 192*b26491b4SRichard Henderson sigsegv: 193*b26491b4SRichard Henderson /* Like force_sig(SIGSEGV). */ 194*b26491b4SRichard Henderson gen_signal(env, TARGET_SIGSEGV, TARGET_SI_KERNEL, 0); 195*b26491b4SRichard Henderson } 196*b26491b4SRichard Henderson #endif 197*b26491b4SRichard Henderson 1983f8258c1SLaurent Vivier void cpu_loop(CPUX86State *env) 1993f8258c1SLaurent Vivier { 2006aa9e42fSRichard Henderson CPUState *cs = env_cpu(env); 2013f8258c1SLaurent Vivier int trapnr; 2023f8258c1SLaurent Vivier abi_ulong pc; 2033f8258c1SLaurent Vivier abi_ulong ret; 2043f8258c1SLaurent Vivier 2053f8258c1SLaurent Vivier for(;;) { 2063f8258c1SLaurent Vivier cpu_exec_start(cs); 2073f8258c1SLaurent Vivier trapnr = cpu_exec(cs); 2083f8258c1SLaurent Vivier cpu_exec_end(cs); 2093f8258c1SLaurent Vivier process_queued_cpu_work(cs); 2103f8258c1SLaurent Vivier 2113f8258c1SLaurent Vivier switch(trapnr) { 2123f8258c1SLaurent Vivier case 0x80: 2133f8258c1SLaurent Vivier /* linux syscall from int $0x80 */ 2143f8258c1SLaurent Vivier ret = do_syscall(env, 2153f8258c1SLaurent Vivier env->regs[R_EAX], 2163f8258c1SLaurent Vivier env->regs[R_EBX], 2173f8258c1SLaurent Vivier env->regs[R_ECX], 2183f8258c1SLaurent Vivier env->regs[R_EDX], 2193f8258c1SLaurent Vivier env->regs[R_ESI], 2203f8258c1SLaurent Vivier env->regs[R_EDI], 2213f8258c1SLaurent Vivier env->regs[R_EBP], 2223f8258c1SLaurent Vivier 0, 0); 2233f8258c1SLaurent Vivier if (ret == -TARGET_ERESTARTSYS) { 2243f8258c1SLaurent Vivier env->eip -= 2; 2253f8258c1SLaurent Vivier } else if (ret != -TARGET_QEMU_ESIGRETURN) { 2263f8258c1SLaurent Vivier env->regs[R_EAX] = ret; 2273f8258c1SLaurent Vivier } 2283f8258c1SLaurent Vivier break; 2293f8258c1SLaurent Vivier #ifndef TARGET_ABI32 2303f8258c1SLaurent Vivier case EXCP_SYSCALL: 2313f8258c1SLaurent Vivier /* linux syscall from syscall instruction */ 2323f8258c1SLaurent Vivier ret = do_syscall(env, 2333f8258c1SLaurent Vivier env->regs[R_EAX], 2343f8258c1SLaurent Vivier env->regs[R_EDI], 2353f8258c1SLaurent Vivier env->regs[R_ESI], 2363f8258c1SLaurent Vivier env->regs[R_EDX], 2373f8258c1SLaurent Vivier env->regs[10], 2383f8258c1SLaurent Vivier env->regs[8], 2393f8258c1SLaurent Vivier env->regs[9], 2403f8258c1SLaurent Vivier 0, 0); 2413f8258c1SLaurent Vivier if (ret == -TARGET_ERESTARTSYS) { 2423f8258c1SLaurent Vivier env->eip -= 2; 2433f8258c1SLaurent Vivier } else if (ret != -TARGET_QEMU_ESIGRETURN) { 2443f8258c1SLaurent Vivier env->regs[R_EAX] = ret; 2453f8258c1SLaurent Vivier } 2463f8258c1SLaurent Vivier break; 2473f8258c1SLaurent Vivier #endif 248*b26491b4SRichard Henderson #ifdef TARGET_X86_64 249*b26491b4SRichard Henderson case EXCP_VSYSCALL: 250*b26491b4SRichard Henderson emulate_vsyscall(env); 251*b26491b4SRichard Henderson break; 252*b26491b4SRichard Henderson #endif 2533f8258c1SLaurent Vivier case EXCP0B_NOSEG: 2543f8258c1SLaurent Vivier case EXCP0C_STACK: 255acf768a9SRichard Henderson gen_signal(env, TARGET_SIGBUS, TARGET_SI_KERNEL, 0); 2563f8258c1SLaurent Vivier break; 2573f8258c1SLaurent Vivier case EXCP0D_GPF: 2583f8258c1SLaurent Vivier /* XXX: potential problem if ABI32 */ 2593f8258c1SLaurent Vivier #ifndef TARGET_X86_64 2603f8258c1SLaurent Vivier if (env->eflags & VM_MASK) { 2613f8258c1SLaurent Vivier handle_vm86_fault(env); 262acf768a9SRichard Henderson break; 2633f8258c1SLaurent Vivier } 264acf768a9SRichard Henderson #endif 265acf768a9SRichard Henderson gen_signal(env, TARGET_SIGSEGV, TARGET_SI_KERNEL, 0); 2663f8258c1SLaurent Vivier break; 2673f8258c1SLaurent Vivier case EXCP0E_PAGE: 268acf768a9SRichard Henderson gen_signal(env, TARGET_SIGSEGV, 269acf768a9SRichard Henderson (env->error_code & 1 ? 270acf768a9SRichard Henderson TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR), 271acf768a9SRichard Henderson env->cr[2]); 2723f8258c1SLaurent Vivier break; 2733f8258c1SLaurent Vivier case EXCP00_DIVZ: 2743f8258c1SLaurent Vivier #ifndef TARGET_X86_64 2753f8258c1SLaurent Vivier if (env->eflags & VM_MASK) { 2763f8258c1SLaurent Vivier handle_vm86_trap(env, trapnr); 277acf768a9SRichard Henderson break; 2783f8258c1SLaurent Vivier } 279acf768a9SRichard Henderson #endif 280acf768a9SRichard Henderson gen_signal(env, TARGET_SIGFPE, TARGET_FPE_INTDIV, env->eip); 2813f8258c1SLaurent Vivier break; 2823f8258c1SLaurent Vivier case EXCP01_DB: 2833f8258c1SLaurent Vivier case EXCP03_INT3: 2843f8258c1SLaurent Vivier #ifndef TARGET_X86_64 2853f8258c1SLaurent Vivier if (env->eflags & VM_MASK) { 2863f8258c1SLaurent Vivier handle_vm86_trap(env, trapnr); 287acf768a9SRichard Henderson break; 2883f8258c1SLaurent Vivier } 289acf768a9SRichard Henderson #endif 290acf768a9SRichard Henderson if (trapnr == EXCP01_DB) { 291acf768a9SRichard Henderson gen_signal(env, TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->eip); 292acf768a9SRichard Henderson } else { 293acf768a9SRichard Henderson gen_signal(env, TARGET_SIGTRAP, TARGET_SI_KERNEL, 0); 2943f8258c1SLaurent Vivier } 2953f8258c1SLaurent Vivier break; 2963f8258c1SLaurent Vivier case EXCP04_INTO: 2973f8258c1SLaurent Vivier case EXCP05_BOUND: 2983f8258c1SLaurent Vivier #ifndef TARGET_X86_64 2993f8258c1SLaurent Vivier if (env->eflags & VM_MASK) { 3003f8258c1SLaurent Vivier handle_vm86_trap(env, trapnr); 301acf768a9SRichard Henderson break; 3023f8258c1SLaurent Vivier } 303acf768a9SRichard Henderson #endif 304acf768a9SRichard Henderson gen_signal(env, TARGET_SIGSEGV, TARGET_SI_KERNEL, 0); 3053f8258c1SLaurent Vivier break; 3063f8258c1SLaurent Vivier case EXCP06_ILLOP: 307acf768a9SRichard Henderson gen_signal(env, TARGET_SIGILL, TARGET_ILL_ILLOPN, env->eip); 3083f8258c1SLaurent Vivier break; 3093f8258c1SLaurent Vivier case EXCP_INTERRUPT: 3103f8258c1SLaurent Vivier /* just indicate that signals should be handled asap */ 3113f8258c1SLaurent Vivier break; 3123f8258c1SLaurent Vivier case EXCP_DEBUG: 313acf768a9SRichard Henderson gen_signal(env, TARGET_SIGTRAP, TARGET_TRAP_BRKPT, 0); 3143f8258c1SLaurent Vivier break; 3153f8258c1SLaurent Vivier case EXCP_ATOMIC: 3163f8258c1SLaurent Vivier cpu_exec_step_atomic(cs); 3173f8258c1SLaurent Vivier break; 3183f8258c1SLaurent Vivier default: 3193f8258c1SLaurent Vivier pc = env->segs[R_CS].base + env->eip; 3203f8258c1SLaurent Vivier EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 3213f8258c1SLaurent Vivier (long)pc, trapnr); 3223f8258c1SLaurent Vivier abort(); 3233f8258c1SLaurent Vivier } 3243f8258c1SLaurent Vivier process_pending_signals(env); 3253f8258c1SLaurent Vivier } 3263f8258c1SLaurent Vivier } 3273f8258c1SLaurent Vivier 328cd71c089SLaurent Vivier void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) 329cd71c089SLaurent Vivier { 3303f8258c1SLaurent Vivier env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; 3313f8258c1SLaurent Vivier env->hflags |= HF_PE_MASK | HF_CPL_MASK; 3323f8258c1SLaurent Vivier if (env->features[FEAT_1_EDX] & CPUID_SSE) { 3333f8258c1SLaurent Vivier env->cr[4] |= CR4_OSFXSR_MASK; 3343f8258c1SLaurent Vivier env->hflags |= HF_OSFXSR_MASK; 3353f8258c1SLaurent Vivier } 3363f8258c1SLaurent Vivier #ifndef TARGET_ABI32 3373f8258c1SLaurent Vivier /* enable 64 bit mode if possible */ 3383f8258c1SLaurent Vivier if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { 3393f8258c1SLaurent Vivier fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); 3403f8258c1SLaurent Vivier exit(EXIT_FAILURE); 3413f8258c1SLaurent Vivier } 3423f8258c1SLaurent Vivier env->cr[4] |= CR4_PAE_MASK; 3433f8258c1SLaurent Vivier env->efer |= MSR_EFER_LMA | MSR_EFER_LME; 3443f8258c1SLaurent Vivier env->hflags |= HF_LMA_MASK; 3453f8258c1SLaurent Vivier #endif 3463f8258c1SLaurent Vivier 3473f8258c1SLaurent Vivier /* flags setup : we activate the IRQs by default as in user mode */ 3483f8258c1SLaurent Vivier env->eflags |= IF_MASK; 3493f8258c1SLaurent Vivier 3503f8258c1SLaurent Vivier /* linux register setup */ 3513f8258c1SLaurent Vivier #ifndef TARGET_ABI32 3523f8258c1SLaurent Vivier env->regs[R_EAX] = regs->rax; 3533f8258c1SLaurent Vivier env->regs[R_EBX] = regs->rbx; 3543f8258c1SLaurent Vivier env->regs[R_ECX] = regs->rcx; 3553f8258c1SLaurent Vivier env->regs[R_EDX] = regs->rdx; 3563f8258c1SLaurent Vivier env->regs[R_ESI] = regs->rsi; 3573f8258c1SLaurent Vivier env->regs[R_EDI] = regs->rdi; 3583f8258c1SLaurent Vivier env->regs[R_EBP] = regs->rbp; 3593f8258c1SLaurent Vivier env->regs[R_ESP] = regs->rsp; 3603f8258c1SLaurent Vivier env->eip = regs->rip; 3613f8258c1SLaurent Vivier #else 3623f8258c1SLaurent Vivier env->regs[R_EAX] = regs->eax; 3633f8258c1SLaurent Vivier env->regs[R_EBX] = regs->ebx; 3643f8258c1SLaurent Vivier env->regs[R_ECX] = regs->ecx; 3653f8258c1SLaurent Vivier env->regs[R_EDX] = regs->edx; 3663f8258c1SLaurent Vivier env->regs[R_ESI] = regs->esi; 3673f8258c1SLaurent Vivier env->regs[R_EDI] = regs->edi; 3683f8258c1SLaurent Vivier env->regs[R_EBP] = regs->ebp; 3693f8258c1SLaurent Vivier env->regs[R_ESP] = regs->esp; 3703f8258c1SLaurent Vivier env->eip = regs->eip; 3713f8258c1SLaurent Vivier #endif 3723f8258c1SLaurent Vivier 3733f8258c1SLaurent Vivier /* linux interrupt setup */ 3743f8258c1SLaurent Vivier #ifndef TARGET_ABI32 3753f8258c1SLaurent Vivier env->idt.limit = 511; 3763f8258c1SLaurent Vivier #else 3773f8258c1SLaurent Vivier env->idt.limit = 255; 3783f8258c1SLaurent Vivier #endif 3793f8258c1SLaurent Vivier env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), 3803f8258c1SLaurent Vivier PROT_READ|PROT_WRITE, 3813f8258c1SLaurent Vivier MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 3823f8258c1SLaurent Vivier idt_table = g2h(env->idt.base); 3833f8258c1SLaurent Vivier set_idt(0, 0); 3843f8258c1SLaurent Vivier set_idt(1, 0); 3853f8258c1SLaurent Vivier set_idt(2, 0); 3863f8258c1SLaurent Vivier set_idt(3, 3); 3873f8258c1SLaurent Vivier set_idt(4, 3); 3883f8258c1SLaurent Vivier set_idt(5, 0); 3893f8258c1SLaurent Vivier set_idt(6, 0); 3903f8258c1SLaurent Vivier set_idt(7, 0); 3913f8258c1SLaurent Vivier set_idt(8, 0); 3923f8258c1SLaurent Vivier set_idt(9, 0); 3933f8258c1SLaurent Vivier set_idt(10, 0); 3943f8258c1SLaurent Vivier set_idt(11, 0); 3953f8258c1SLaurent Vivier set_idt(12, 0); 3963f8258c1SLaurent Vivier set_idt(13, 0); 3973f8258c1SLaurent Vivier set_idt(14, 0); 3983f8258c1SLaurent Vivier set_idt(15, 0); 3993f8258c1SLaurent Vivier set_idt(16, 0); 4003f8258c1SLaurent Vivier set_idt(17, 0); 4013f8258c1SLaurent Vivier set_idt(18, 0); 4023f8258c1SLaurent Vivier set_idt(19, 0); 4033f8258c1SLaurent Vivier set_idt(0x80, 3); 4043f8258c1SLaurent Vivier 4053f8258c1SLaurent Vivier /* linux segment setup */ 4063f8258c1SLaurent Vivier { 4073f8258c1SLaurent Vivier uint64_t *gdt_table; 4083f8258c1SLaurent Vivier env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, 4093f8258c1SLaurent Vivier PROT_READ|PROT_WRITE, 4103f8258c1SLaurent Vivier MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 4113f8258c1SLaurent Vivier env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; 4123f8258c1SLaurent Vivier gdt_table = g2h(env->gdt.base); 4133f8258c1SLaurent Vivier #ifdef TARGET_ABI32 4143f8258c1SLaurent Vivier write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 4153f8258c1SLaurent Vivier DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 4163f8258c1SLaurent Vivier (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 4173f8258c1SLaurent Vivier #else 4183f8258c1SLaurent Vivier /* 64 bit code segment */ 4193f8258c1SLaurent Vivier write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 4203f8258c1SLaurent Vivier DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 4213f8258c1SLaurent Vivier DESC_L_MASK | 4223f8258c1SLaurent Vivier (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 4233f8258c1SLaurent Vivier #endif 4243f8258c1SLaurent Vivier write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, 4253f8258c1SLaurent Vivier DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 4263f8258c1SLaurent Vivier (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); 4273f8258c1SLaurent Vivier } 4283f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_CS, __USER_CS); 4293f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_SS, __USER_DS); 4303f8258c1SLaurent Vivier #ifdef TARGET_ABI32 4313f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_DS, __USER_DS); 4323f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_ES, __USER_DS); 4333f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_FS, __USER_DS); 4343f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_GS, __USER_DS); 4353f8258c1SLaurent Vivier /* This hack makes Wine work... */ 4363f8258c1SLaurent Vivier env->segs[R_FS].selector = 0; 4373f8258c1SLaurent Vivier #else 4383f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_DS, 0); 4393f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_ES, 0); 4403f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_FS, 0); 4413f8258c1SLaurent Vivier cpu_x86_load_seg(env, R_GS, 0); 4423f8258c1SLaurent Vivier #endif 443cd71c089SLaurent Vivier } 444