diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-15 16:46:30 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-15 16:46:30 +0000 |
commit | b8b6a50b552e1ddb9f0c563cbfb6f67aa0330b64 (patch) | |
tree | 70f78f7d7a4577ca95b9b05aff61b5b2f479aa6f | |
parent | 6e01bdaedc3fc42c88672fafe960d3371dabb63e (diff) | |
download | qemu-b8b6a50b552e1ddb9f0c563cbfb6f67aa0330b64.zip qemu-b8b6a50b552e1ddb9f0c563cbfb6f67aa0330b64.tar.gz qemu-b8b6a50b552e1ddb9f0c563cbfb6f67aa0330b64.tar.bz2 |
converted more helpers to TCG - fixed some SVM issues
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4459 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | target-i386/TODO | 13 | ||||
-rw-r--r-- | target-i386/exec.h | 26 | ||||
-rw-r--r-- | target-i386/helper.c | 309 | ||||
-rw-r--r-- | target-i386/helper.h | 50 | ||||
-rw-r--r-- | target-i386/op.c | 141 | ||||
-rw-r--r-- | target-i386/ops_sse.h | 4 | ||||
-rw-r--r-- | target-i386/ops_sse_header.h | 2 | ||||
-rw-r--r-- | target-i386/ops_template.h | 33 | ||||
-rw-r--r-- | target-i386/svm.h | 11 | ||||
-rw-r--r-- | target-i386/translate.c | 300 |
10 files changed, 404 insertions, 485 deletions
diff --git a/target-i386/TODO b/target-i386/TODO index 1bca8ba..53be196 100644 --- a/target-i386/TODO +++ b/target-i386/TODO @@ -3,12 +3,13 @@ Correctness issues: - rework eflags optimization (will be a consequence of TCG port) - SVM: rework the implementation: simplify code, move most intercept tests as dynamic, correct segment access, verify exception safety, - remove most of the added CPU state. + cpu save/restore, SMM save/restore. - arpl eflags computation is invalid - x86_64: fxsave/fxrestore intel/amd differences - x86_64: lcall/ljmp intel/amd differences ? - x86_64: cmpxchgl intel/amd differences ? -- x86_64: cmovl bug intel/amd differences ? +- x86_64: cmovl intel/amd differences ? +- cmpxchg16b + cmpxchg8b cpuid test - x86: monitor invalid - better code fetch (different exception handling + CS.limit support) - user/kernel PUSHL/POPL in helper.c @@ -19,10 +20,18 @@ Correctness issues: - full support of segment limit/rights - full x87 exception support - improve x87 bit exactness (use bochs code ?) +- DRx register support +- CR0.AC emulation +- SSE alignment checks +- fix SSE min/max with nans Optimizations/Features: - finish TCG port +- add SVM nested paging support +- add VMX support +- add AVX support +- add SSE5 support - evaluate x87 stack pointer statically - find a way to avoid translating several time the same TB if CR0.TS is set or not. diff --git a/target-i386/exec.h b/target-i386/exec.h index 72dc016..8f41b0d 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -105,16 +105,6 @@ typedef struct CCTable { extern CCTable cc_table[]; -void helper_load_seg(int seg_reg, int selector); -void helper_ljmp_protected_T0_T1(int next_eip); -void helper_lcall_real_T0_T1(int shift, int next_eip); -void helper_lcall_protected_T0_T1(int shift, int next_eip); -void helper_iret_real(int shift); -void helper_iret_protected(int shift, int next_eip); -void helper_lret_protected(int shift, int addend); -void helper_movl_crN_T0(int reg); -void helper_movl_drN_T0(int reg); -void helper_invlpg(target_ulong addr); void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0); void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); @@ -141,17 +131,10 @@ void OPPROTO op_movl_T0_eflags(void); #include "helper.h" -void helper_mulq_EAX_T0(void); -void helper_imulq_EAX_T0(void); -void helper_imulq_T0_T1(void); -void helper_cmpxchg8b(void); - -void check_iob_T0(void); -void check_iow_T0(void); -void check_iol_T0(void); -void check_iob_DX(void); -void check_iow_DX(void); -void check_iol_DX(void); +static inline void svm_check_intercept(uint32_t type) +{ + helper_svm_check_intercept_param(type, 0); +} #if !defined(CONFIG_USER_ONLY) @@ -363,7 +346,6 @@ extern const CPU86_LDouble f15rk[7]; void fpu_raise_exception(void); void restore_native_fp_state(CPUState *env); void save_native_fp_state(CPUState *env); -void vmexit(uint64_t exit_code, uint64_t exit_info_1); extern const uint8_t parity_table[256]; extern const uint8_t rclw_table[32]; diff --git a/target-i386/helper.c b/target-i386/helper.c index 0d0f5ff..da36f8b 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define CPU_NO_GLOBAL_REGS #include "exec.h" #include "host-utils.h" @@ -93,16 +94,16 @@ const CPU86_LDouble f15rk[7] = 3.32192809488736234781L, /*l2t*/ }; -/* thread support */ +/* broken thread support */ spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; -void cpu_lock(void) +void helper_lock(void) { spin_lock(&global_cpu_lock); } -void cpu_unlock(void) +void helper_unlock(void) { spin_unlock(&global_cpu_lock); } @@ -508,34 +509,49 @@ static inline void check_io(int addr, int size) } } -void check_iob_T0(void) +void helper_check_iob(uint32_t t0) { - check_io(T0, 1); + check_io(t0, 1); } -void check_iow_T0(void) +void helper_check_iow(uint32_t t0) { - check_io(T0, 2); + check_io(t0, 2); } -void check_iol_T0(void) +void helper_check_iol(uint32_t t0) { - check_io(T0, 4); + check_io(t0, 4); } -void check_iob_DX(void) +void helper_outb(uint32_t port, uint32_t data) { - check_io(EDX & 0xffff, 1); + cpu_outb(env, port, data & 0xff); } -void check_iow_DX(void) +target_ulong helper_inb(uint32_t port) { - check_io(EDX & 0xffff, 2); + return cpu_inb(env, port); } -void check_iol_DX(void) +void helper_outw(uint32_t port, uint32_t data) { - check_io(EDX & 0xffff, 4); + cpu_outw(env, port, data & 0xffff); +} + +target_ulong helper_inw(uint32_t port) +{ + return cpu_inw(env, port); +} + +void helper_outl(uint32_t port, uint32_t data) +{ + cpu_outl(env, port, data); +} + +target_ulong helper_inl(uint32_t port) +{ + return cpu_inl(env, port); } static inline unsigned int get_sp_mask(unsigned int e2) @@ -1275,7 +1291,7 @@ void raise_interrupt(int intno, int is_int, int error_code, int next_eip_addend) { if (!is_int) { - svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); + helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code); intno = check_exception(intno, &error_code); } @@ -1857,19 +1873,19 @@ void helper_das(void) FORCE_RET(); } -void helper_cmpxchg8b(void) +void helper_cmpxchg8b(target_ulong a0) { uint64_t d; int eflags; eflags = cc_table[CC_OP].compute_all(); - d = ldq(A0); + d = ldq(a0); if (d == (((uint64_t)EDX << 32) | EAX)) { - stq(A0, ((uint64_t)ECX << 32) | EBX); + stq(a0, ((uint64_t)ECX << 32) | EBX); eflags |= CC_Z; } else { - EDX = d >> 32; - EAX = d; + EDX = (uint32_t)(d >> 32); + EAX = (uint32_t)d; eflags &= ~CC_Z; } CC_SRC = eflags; @@ -1986,7 +2002,7 @@ void helper_cpuid(void) } } -void helper_enter_level(int level, int data32) +void helper_enter_level(int level, int data32, target_ulong t1) { target_ulong ssp; uint32_t esp_mask, esp, ebp; @@ -2004,7 +2020,7 @@ void helper_enter_level(int level, int data32) stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask))); } esp -= 4; - stl(ssp + (esp & esp_mask), T1); + stl(ssp + (esp & esp_mask), t1); } else { /* 16 bit */ esp -= 2; @@ -2014,12 +2030,12 @@ void helper_enter_level(int level, int data32) stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); } esp -= 2; - stw(ssp + (esp & esp_mask), T1); + stw(ssp + (esp & esp_mask), t1); } } #ifdef TARGET_X86_64 -void helper_enter64_level(int level, int data64) +void helper_enter64_level(int level, int data64, target_ulong t1) { target_ulong esp, ebp; ebp = EBP; @@ -2034,7 +2050,7 @@ void helper_enter64_level(int level, int data64) stq(esp, ldq(ebp)); } esp -= 8; - stq(esp, T1); + stq(esp, t1); } else { /* 16 bit */ esp -= 2; @@ -2044,7 +2060,7 @@ void helper_enter64_level(int level, int data64) stw(esp, lduw(ebp)); } esp -= 2; - stw(esp, T1); + stw(esp, t1); } } #endif @@ -2231,14 +2247,13 @@ void helper_load_seg(int seg_reg, int selector) } /* protected mode jump */ -void helper_ljmp_protected_T0_T1(int next_eip_addend) +void helper_ljmp_protected(int new_cs, target_ulong new_eip, + int next_eip_addend) { - int new_cs, gate_cs, type; + int gate_cs, type; uint32_t e1, e2, cpl, dpl, rpl, limit; - target_ulong new_eip, next_eip; + target_ulong next_eip; - new_cs = T0; - new_eip = T1; if ((new_cs & 0xfffc) == 0) raise_exception_err(EXCP0D_GPF, 0); if (load_segment(&e1, &e2, new_cs) != 0) @@ -2322,14 +2337,14 @@ void helper_ljmp_protected_T0_T1(int next_eip_addend) } /* real mode call */ -void helper_lcall_real_T0_T1(int shift, int next_eip) +void helper_lcall_real(int new_cs, target_ulong new_eip1, + int shift, int next_eip) { - int new_cs, new_eip; + int new_eip; uint32_t esp, esp_mask; target_ulong ssp; - new_cs = T0; - new_eip = T1; + new_eip = new_eip1; esp = ESP; esp_mask = get_sp_mask(env->segs[R_SS].flags); ssp = env->segs[R_SS].base; @@ -2348,16 +2363,15 @@ void helper_lcall_real_T0_T1(int shift, int next_eip) } /* protected mode call */ -void helper_lcall_protected_T0_T1(int shift, int next_eip_addend) +void helper_lcall_protected(int new_cs, target_ulong new_eip, + int shift, int next_eip_addend) { - int new_cs, new_stack, i; + int new_stack, i; uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; uint32_t val, limit, old_sp_mask; - target_ulong ssp, old_ssp, next_eip, new_eip; + target_ulong ssp, old_ssp, next_eip; - new_cs = T0; - new_eip = T1; next_eip = env->eip + next_eip_addend; #ifdef DEBUG_PCALL if (loglevel & CPU_LOG_PCALL) { @@ -2922,34 +2936,55 @@ void helper_sysexit(void) #endif } -void helper_movl_crN_T0(int reg) +void helper_movl_crN_T0(int reg, target_ulong t0) { #if !defined(CONFIG_USER_ONLY) switch(reg) { case 0: - cpu_x86_update_cr0(env, T0); + cpu_x86_update_cr0(env, t0); break; case 3: - cpu_x86_update_cr3(env, T0); + cpu_x86_update_cr3(env, t0); break; case 4: - cpu_x86_update_cr4(env, T0); + cpu_x86_update_cr4(env, t0); break; case 8: - cpu_set_apic_tpr(env, T0); - env->cr[8] = T0; + cpu_set_apic_tpr(env, t0); + env->cr[8] = t0; break; default: - env->cr[reg] = T0; + env->cr[reg] = t0; break; } #endif } +void helper_lmsw(target_ulong t0) +{ + /* only 4 lower bits of CR0 are modified. PE cannot be set to zero + if already set to one. */ + t0 = (env->cr[0] & ~0xe) | (t0 & 0xf); + helper_movl_crN_T0(0, t0); +} + +void helper_clts(void) +{ + env->cr[0] &= ~CR0_TS_MASK; + env->hflags &= ~HF_TS_MASK; +} + +#if !defined(CONFIG_USER_ONLY) +target_ulong helper_movtl_T0_cr8(void) +{ + return cpu_get_apic_tpr(env); +} +#endif + /* XXX: do more */ -void helper_movl_drN_T0(int reg) +void helper_movl_drN_T0(int reg, target_ulong t0) { - env->dr[reg] = T0; + env->dr[reg] = t0; } void helper_invlpg(target_ulong addr) @@ -2975,10 +3010,10 @@ void helper_rdpmc(void) raise_exception(EXCP0D_GPF); } - if (!svm_check_intercept_param(SVM_EXIT_RDPMC, 0)) { - /* currently unimplemented */ - raise_exception_err(EXCP06_ILLOP, 0); - } + helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0); + + /* currently unimplemented */ + raise_exception_err(EXCP06_ILLOP, 0); } #if defined(CONFIG_USER_ONLY) @@ -3118,7 +3153,7 @@ void helper_rdmsr(void) } #endif -void helper_lsl(uint32_t selector) +uint32_t helper_lsl(uint32_t selector) { unsigned int limit; uint32_t e1, e2, eflags; @@ -3153,15 +3188,15 @@ void helper_lsl(uint32_t selector) if (dpl < cpl || dpl < rpl) { fail: CC_SRC = eflags & ~CC_Z; - return; + return 0; } } limit = get_seg_limit(e1, e2); - T1 = limit; CC_SRC = eflags | CC_Z; + return limit; } -void helper_lar(uint32_t selector) +uint32_t helper_lar(uint32_t selector) { uint32_t e1, e2, eflags; int rpl, dpl, cpl, type; @@ -3200,11 +3235,11 @@ void helper_lar(uint32_t selector) if (dpl < cpl || dpl < rpl) { fail: CC_SRC = eflags & ~CC_Z; - return; + return 0; } } - T1 = e2 & 0x00f0ff00; CC_SRC = eflags | CC_Z; + return e2 & 0x00f0ff00; } void helper_verr(uint32_t selector) @@ -4412,36 +4447,36 @@ static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) return 0; } -void helper_mulq_EAX_T0(void) +void helper_mulq_EAX_T0(target_ulong t0) { uint64_t r0, r1; - mulu64(&r0, &r1, EAX, T0); + mulu64(&r0, &r1, EAX, t0); EAX = r0; EDX = r1; CC_DST = r0; CC_SRC = r1; } -void helper_imulq_EAX_T0(void) +void helper_imulq_EAX_T0(target_ulong t0) { uint64_t r0, r1; - muls64(&r0, &r1, EAX, T0); + muls64(&r0, &r1, EAX, t0); EAX = r0; EDX = r1; CC_DST = r0; CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); } -void helper_imulq_T0_T1(void) +target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1) { uint64_t r0, r1; - muls64(&r0, &r1, T0, T1); - T0 = r0; + muls64(&r0, &r1, t0, t1); CC_DST = r0; CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); + return r0; } void helper_divq_EAX(target_ulong t0) @@ -4553,24 +4588,23 @@ void helper_reset_inhibit_irq(void) env->hflags &= ~HF_INHIBIT_IRQ_MASK; } -void helper_boundw(void) +void helper_boundw(target_ulong a0, int v) { - int low, high, v; - low = ldsw(A0); - high = ldsw(A0 + 2); - v = (int16_t)T0; + int low, high; + low = ldsw(a0); + high = ldsw(a0 + 2); + v = (int16_t)v; if (v < low || v > high) { raise_exception(EXCP05_BOUND); } FORCE_RET(); } -void helper_boundl(void) +void helper_boundl(target_ulong a0, int v) { - int low, high, v; - low = ldl(A0); - high = ldl(A0 + 4); - v = T0; + int low, high; + low = ldl(a0); + high = ldl(a0 + 4); if (v < low || v > high) { raise_exception(EXCP05_BOUND); } @@ -4661,18 +4695,35 @@ void helper_clgi(void) #if defined(CONFIG_USER_ONLY) -void helper_vmrun(void) { } -void helper_vmmcall(void) { } -void helper_vmload(void) { } -void helper_vmsave(void) { } -void helper_skinit(void) { } -void helper_invlpga(void) { } -void vmexit(uint64_t exit_code, uint64_t exit_info_1) { } -int svm_check_intercept_param(uint32_t type, uint64_t param) +void helper_vmrun(void) +{ +} +void helper_vmmcall(void) +{ +} +void helper_vmload(void) +{ +} +void helper_vmsave(void) +{ +} +void helper_skinit(void) +{ +} +void helper_invlpga(void) +{ +} +void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) +{ +} +void helper_svm_check_intercept_param(uint32_t type, uint64_t param) { - return 0; } +void helper_svm_check_io(uint32_t port, uint32_t param, + uint32_t next_eip_addend) +{ +} #else static inline uint32_t @@ -4702,7 +4753,6 @@ void helper_vmrun(void) fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr); env->vm_vmcb = addr; - regs_to_env(); /* save the current CPU state in the hsave page */ stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); @@ -4801,8 +4851,6 @@ void helper_vmrun(void) helper_stgi(); - regs_to_env(); - /* maybe we need to inject an event */ event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); if (event_inj & SVM_EVTINJ_VALID) { @@ -4927,95 +4975,98 @@ void helper_invlpga(void) tlb_flush(env, 0); } -int svm_check_intercept_param(uint32_t type, uint64_t param) +void helper_svm_check_intercept_param(uint32_t type, uint64_t param) { switch(type) { case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) { - vmexit(type, param); - return 1; + helper_vmexit(type, param); } break; case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8: if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) { - vmexit(type, param); - return 1; + helper_vmexit(type, param); } break; case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) { - vmexit(type, param); - return 1; + helper_vmexit(type, param); } break; case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8: if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) { - vmexit(type, param); - return 1; + helper_vmexit(type, param); } break; case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16: if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) { - vmexit(type, param); - return 1; + helper_vmexit(type, param); } break; case SVM_EXIT_IOIO: - if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) { - /* FIXME: this should be read in at vmrun (faster this way?) */ - uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); - uint16_t port = (uint16_t) (param >> 16); - - uint16_t mask = (1 << ((param >> 4) & 7)) - 1; - if(lduw_phys(addr + port / 8) & (mask << (port & 7))) - vmexit(type, param); - } break; case SVM_EXIT_MSR: if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) { /* FIXME: this should be read in at vmrun (faster this way?) */ uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa)); + uint32_t t0, t1; switch((uint32_t)ECX) { case 0 ... 0x1fff: - T0 = (ECX * 2) % 8; - T1 = ECX / 8; + t0 = (ECX * 2) % 8; + t1 = ECX / 8; break; case 0xc0000000 ... 0xc0001fff: - T0 = (8192 + ECX - 0xc0000000) * 2; - T1 = (T0 / 8); - T0 %= 8; + t0 = (8192 + ECX - 0xc0000000) * 2; + t1 = (t0 / 8); + t0 %= 8; break; case 0xc0010000 ... 0xc0011fff: - T0 = (16384 + ECX - 0xc0010000) * 2; - T1 = (T0 / 8); - T0 %= 8; + t0 = (16384 + ECX - 0xc0010000) * 2; + t1 = (t0 / 8); + t0 %= 8; break; default: - vmexit(type, param); - return 1; + helper_vmexit(type, param); + t0 = 0; + t1 = 0; + break; } - if (ldub_phys(addr + T1) & ((1 << param) << T0)) - vmexit(type, param); - return 1; + if (ldub_phys(addr + t1) & ((1 << param) << t0)) + helper_vmexit(type, param); } break; default: if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) { - vmexit(type, param); - return 1; + helper_vmexit(type, param); } break; } - return 0; } -void vmexit(uint64_t exit_code, uint64_t exit_info_1) +void helper_svm_check_io(uint32_t port, uint32_t param, + uint32_t next_eip_addend) +{ + if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) { + /* FIXME: this should be read in at vmrun (faster this way?) */ + uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa)); + uint16_t mask = (1 << ((param >> 4) & 7)) - 1; + if(lduw_phys(addr + port / 8) & (mask << (port & 7))) { + /* next EIP */ + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), + env->eip + next_eip_addend); + helper_vmexit(SVM_EXIT_IOIO, param | (port << 16)); + } + } +} + +/* Note: currently only 32 bits of exit_code are used */ +void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) { uint32_t int_ctl; if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile,"vmexit(%016" PRIx64 ", %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", + fprintf(logfile,"vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n", exit_code, exit_info_1, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), EIP); @@ -5105,8 +5156,7 @@ void vmexit(uint64_t exit_code, uint64_t exit_info_1) /* other setups */ cpu_x86_set_cpl(env, 0); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code_hi), (uint32_t)(exit_code >> 32)); - stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); + stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code); stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1); helper_clgi(); @@ -5137,7 +5187,6 @@ void vmexit(uint64_t exit_code, uint64_t exit_info_1) env->error_code = 0; env->old_exception = -1; - regs_to_env(); cpu_loop_exit(); } diff --git a/target-i386/helper.h b/target-i386/helper.h index 3bce500..c4452f7 100644 --- a/target-i386/helper.h +++ b/target-i386/helper.h @@ -1,5 +1,7 @@ #define TCG_HELPER_PROTO +void helper_lock(void); +void helper_unlock(void); void helper_divb_AL(target_ulong t0); void helper_idivb_AL(target_ulong t0); void helper_divw_AX(target_ulong t0); @@ -7,6 +9,9 @@ void helper_idivw_AX(target_ulong t0); void helper_divl_EAX(target_ulong t0); void helper_idivl_EAX(target_ulong t0); #ifdef TARGET_X86_64 +void helper_mulq_EAX_T0(target_ulong t0); +void helper_imulq_EAX_T0(target_ulong t0); +target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1); void helper_divq_EAX(target_ulong t0); void helper_idivq_EAX(target_ulong t0); #endif @@ -18,26 +23,34 @@ void helper_aas(void); void helper_daa(void); void helper_das(void); -void helper_lsl(uint32_t selector); -void helper_lar(uint32_t selector); +uint32_t helper_lsl(uint32_t selector); +uint32_t helper_lar(uint32_t selector); void helper_verr(uint32_t selector); void helper_verw(uint32_t selector); void helper_lldt(int selector); void helper_ltr(int selector); void helper_load_seg(int seg_reg, int selector); -void helper_ljmp_protected_T0_T1(int next_eip); -void helper_lcall_real_T0_T1(int shift, int next_eip); -void helper_lcall_protected_T0_T1(int shift, int next_eip); +void helper_ljmp_protected(int new_cs, target_ulong new_eip, + int next_eip_addend); +void helper_lcall_real(int new_cs, target_ulong new_eip1, + int shift, int next_eip); +void helper_lcall_protected(int new_cs, target_ulong new_eip, + int shift, int next_eip_addend); void helper_iret_real(int shift); void helper_iret_protected(int shift, int next_eip); void helper_lret_protected(int shift, int addend); -void helper_movl_crN_T0(int reg); -void helper_movl_drN_T0(int reg); +void helper_movl_crN_T0(int reg, target_ulong t0); +void helper_lmsw(target_ulong t0); +void helper_clts(void); +#if !defined(CONFIG_USER_ONLY) +target_ulong helper_movtl_T0_cr8(void); +#endif +void helper_movl_drN_T0(int reg, target_ulong t0); void helper_invlpg(target_ulong addr); -void helper_enter_level(int level, int data32); +void helper_enter_level(int level, int data32, target_ulong t1); #ifdef TARGET_X86_64 -void helper_enter64_level(int level, int data64); +void helper_enter64_level(int level, int data64, target_ulong t1); #endif void helper_sysenter(void); void helper_sysexit(void); @@ -55,9 +68,10 @@ void helper_cli(void); void helper_sti(void); void helper_set_inhibit_irq(void); void helper_reset_inhibit_irq(void); -void helper_boundw(void); -void helper_boundl(void); +void helper_boundw(target_ulong a0, int v); +void helper_boundl(target_ulong a0, int v); void helper_rsm(void); +void helper_cmpxchg8b(target_ulong a0); void helper_single_step(void); void helper_cpuid(void); void helper_rdtsc(void); @@ -65,6 +79,20 @@ void helper_rdpmc(void); void helper_rdmsr(void); void helper_wrmsr(void); +void helper_check_iob(uint32_t t0); +void helper_check_iow(uint32_t t0); +void helper_check_iol(uint32_t t0); +void helper_outb(uint32_t port, uint32_t data); +target_ulong helper_inb(uint32_t port); +void helper_outw(uint32_t port, uint32_t data); +target_ulong helper_inw(uint32_t port); +void helper_outl(uint32_t port, uint32_t data); +target_ulong helper_inl(uint32_t port); + +void helper_svm_check_intercept_param(uint32_t type, uint64_t param); +void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1); +void helper_svm_check_io(uint32_t port, uint32_t param, + uint32_t next_eip_addend); void helper_vmrun(void); void helper_vmmcall(void); void helper_vmload(void); diff --git a/target-i386/op.c b/target-i386/op.c index 69f3aae..3b43e2c 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -276,17 +276,17 @@ void OPPROTO op_imull_T0_T1(void) #ifdef TARGET_X86_64 void OPPROTO op_mulq_EAX_T0(void) { - helper_mulq_EAX_T0(); + helper_mulq_EAX_T0(T0); } void OPPROTO op_imulq_EAX_T0(void) { - helper_imulq_EAX_T0(); + helper_imulq_EAX_T0(T0); } void OPPROTO op_imulq_T0_T1(void) { - helper_imulq_T0_T1(); + T0 = helper_imulq_T0_T1(T0, T1); } #endif @@ -351,7 +351,7 @@ void OPPROTO op_into(void) void OPPROTO op_cmpxchg8b(void) { - helper_cmpxchg8b(); + helper_cmpxchg8b(A0); } /* multiple size ops */ @@ -522,12 +522,6 @@ void OPPROTO op_das(void) /* segment handling */ -/* never use it with R_CS */ -void OPPROTO op_movl_seg_T0(void) -{ - helper_load_seg(PARAM1, T0); -} - /* faster VM86 version */ void OPPROTO op_movl_seg_T0_vm(void) { @@ -548,12 +542,20 @@ void OPPROTO op_movl_T0_seg(void) void OPPROTO op_lsl(void) { - helper_lsl(T0); + uint32_t val; + val = helper_lsl(T0); + if (CC_SRC & CC_Z) + T1 = val; + FORCE_RET(); } void OPPROTO op_lar(void) { - helper_lar(T0); + uint32_t val; + val = helper_lar(T0); + if (CC_SRC & CC_Z) + T1 = val; + FORCE_RET(); } void OPPROTO op_verr(void) @@ -585,104 +587,6 @@ void OPPROTO op_arpl_update(void) CC_SRC = (eflags & ~CC_Z) | T1; } -/* T0: segment, T1:eip */ -void OPPROTO op_ljmp_protected_T0_T1(void) -{ - helper_ljmp_protected_T0_T1(PARAM1); -} - -void OPPROTO op_lcall_real_T0_T1(void) -{ - helper_lcall_real_T0_T1(PARAM1, PARAM2); -} - -void OPPROTO op_lcall_protected_T0_T1(void) -{ - helper_lcall_protected_T0_T1(PARAM1, PARAM2); -} - -void OPPROTO op_iret_real(void) -{ - helper_iret_real(PARAM1); -} - -void OPPROTO op_iret_protected(void) -{ - helper_iret_protected(PARAM1, PARAM2); -} - -void OPPROTO op_lret_protected(void) -{ - helper_lret_protected(PARAM1, PARAM2); -} - -/* CR registers access. */ -void OPPROTO op_movl_crN_T0(void) -{ - helper_movl_crN_T0(PARAM1); -} - -/* These pseudo-opcodes check for SVM intercepts. */ -void OPPROTO op_svm_check_intercept(void) -{ - A0 = PARAM1 & PARAM2; - svm_check_intercept(PARAMQ1); -} - -void OPPROTO op_svm_check_intercept_param(void) -{ - A0 = PARAM1 & PARAM2; - svm_check_intercept_param(PARAMQ1, T1); -} - -void OPPROTO op_svm_vmexit(void) -{ - A0 = PARAM1 & PARAM2; - vmexit(PARAMQ1, T1); -} - -void OPPROTO op_geneflags(void) -{ - CC_SRC = cc_table[CC_OP].compute_all(); -} - -/* This pseudo-opcode checks for IO intercepts. */ -#if !defined(CONFIG_USER_ONLY) -void OPPROTO op_svm_check_intercept_io(void) -{ - A0 = PARAM1 & PARAM2; - /* PARAMQ1 = TYPE (0 = OUT, 1 = IN; 4 = STRING; 8 = REP) - T0 = PORT - T1 = next eip */ - stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), T1); - /* ASIZE does not appear on real hw */ - svm_check_intercept_param(SVM_EXIT_IOIO, - (PARAMQ1 & ~SVM_IOIO_ASIZE_MASK) | - ((T0 & 0xffff) << 16)); -} -#endif - -#if !defined(CONFIG_USER_ONLY) -void OPPROTO op_movtl_T0_cr8(void) -{ - T0 = cpu_get_apic_tpr(env); -} -#endif - -/* DR registers access */ -void OPPROTO op_movl_drN_T0(void) -{ - helper_movl_drN_T0(PARAM1); -} - -void OPPROTO op_lmsw_T0(void) -{ - /* only 4 lower bits of CR0 are modified. PE cannot be set to zero - if already set to one. */ - T0 = (env->cr[0] & ~0xe) | (T0 & 0xf); - helper_movl_crN_T0(0); -} - void OPPROTO op_movl_T0_env(void) { T0 = *(uint32_t *)((char *)env + PARAM1); @@ -718,12 +622,6 @@ void OPPROTO op_movtl_env_T1(void) *(target_ulong *)((char *)env + PARAM1) = T1; } -void OPPROTO op_clts(void) -{ - env->cr[0] &= ~CR0_TS_MASK; - env->hflags &= ~HF_TS_MASK; -} - /* flags handling */ void OPPROTO op_jmp_label(void) @@ -1028,17 +926,6 @@ void OPPROTO op_fcomi_dummy(void) T0 = 0; } -/* threading support */ -void OPPROTO op_lock(void) -{ - cpu_lock(); -} - -void OPPROTO op_unlock(void) -{ - cpu_unlock(); -} - /* SSE support */ void OPPROTO op_com_dummy(void) { diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h index 010cfea..7568681 100644 --- a/target-i386/ops_sse.h +++ b/target-i386/ops_sse.h @@ -471,12 +471,12 @@ void glue(helper_psadbw, SUFFIX) (Reg *d, Reg *s) #endif } -void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s) +void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s, target_ulong a0) { int i; for(i = 0; i < (8 << SHIFT); i++) { if (s->B(i) & 0x80) - stb(A0 + i, d->B(i)); + stb(a0 + i, d->B(i)); } FORCE_RET(); } diff --git a/target-i386/ops_sse_header.h b/target-i386/ops_sse_header.h index 07cfea4..f8e01f4 100644 --- a/target-i386/ops_sse_header.h +++ b/target-i386/ops_sse_header.h @@ -104,7 +104,7 @@ void glue(helper_pmuludq, SUFFIX) (Reg *d, Reg *s); void glue(helper_pmaddwd, SUFFIX) (Reg *d, Reg *s); void glue(helper_psadbw, SUFFIX) (Reg *d, Reg *s); -void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s); +void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s, target_ulong a0); void glue(helper_movl_mm_T0, SUFFIX) (Reg *d, uint32_t val); #ifdef TARGET_X86_64 void glue(helper_movq_mm_T0, SUFFIX) (Reg *d, uint64_t val); diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h index d1df07f..a599deb 100644 --- a/target-i386/ops_template.h +++ b/target-i386/ops_template.h @@ -554,39 +554,6 @@ void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void) T0 = DF << SHIFT; } -/* port I/O */ -#if DATA_BITS <= 32 -void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) -{ - glue(cpu_out, SUFFIX)(env, T0, T1 & DATA_MASK); -} - -void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) -{ - T1 = glue(cpu_in, SUFFIX)(env, T0); -} - -void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void) -{ - T0 = glue(cpu_in, SUFFIX)(env, EDX & 0xffff); -} - -void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void) -{ - glue(cpu_out, SUFFIX)(env, EDX & 0xffff, T0); -} - -void OPPROTO glue(glue(op_check_io, SUFFIX), _T0)(void) -{ - glue(glue(check_io, SUFFIX), _T0)(); -} - -void OPPROTO glue(glue(op_check_io, SUFFIX), _DX)(void) -{ - glue(glue(check_io, SUFFIX), _DX)(); -} -#endif - #undef DATA_BITS #undef SHIFT_MASK #undef SHIFT1_MASK diff --git a/target-i386/svm.h b/target-i386/svm.h index f99f47e..add52fc 100644 --- a/target-i386/svm.h +++ b/target-i386/svm.h @@ -71,8 +71,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area { uint32_t int_vector; uint32_t int_state; uint8_t reserved_3[4]; - uint32_t exit_code; - uint32_t exit_code_hi; + uint64_t exit_code; uint64_t exit_info_1; uint64_t exit_info_2; uint32_t exit_int_info; @@ -323,14 +322,6 @@ struct __attribute__ ((__packed__)) vmcb { /* function references */ -void helper_stgi(void); -void vmexit(uint64_t exit_code, uint64_t exit_info_1); -int svm_check_intercept_param(uint32_t type, uint64_t param); -static inline int svm_check_intercept(unsigned int type) { - return svm_check_intercept_param(type, 0); -} - - #define INTERCEPTED(mask) (env->intercept & mask) #define INTERCEPTEDw(var, mask) (env->intercept ## var & mask) #define INTERCEPTEDl(var, mask) (env->intercept ## var & mask) diff --git a/target-i386/translate.c b/target-i386/translate.c index 97c6051..78b2449 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -60,7 +60,7 @@ /* global register indexes */ static TCGv cpu_env, cpu_T[2], cpu_A0; /* local register indexes (only used inside old micro ops) */ -static TCGv cpu_tmp0, cpu_tmp1, cpu_tmp2, cpu_ptr0, cpu_ptr1; +static TCGv cpu_tmp0, cpu_tmp1, cpu_tmp2, cpu_tmp3, cpu_ptr0, cpu_ptr1; #ifdef TARGET_X86_64 static int x86_64_hregs; @@ -903,52 +903,54 @@ static GenOpFunc1 *gen_op_string_jnz_sub[2][4] = { }, }; -static GenOpFunc *gen_op_in_DX_T0[3] = { - gen_op_inb_DX_T0, - gen_op_inw_DX_T0, - gen_op_inl_DX_T0, +static void *helper_in_func[3] = { + helper_inb, + helper_inw, + helper_inl, }; -static GenOpFunc *gen_op_out_DX_T0[3] = { - gen_op_outb_DX_T0, - gen_op_outw_DX_T0, - gen_op_outl_DX_T0, +static void *helper_out_func[3] = { + helper_outb, + helper_outw, + helper_outl, }; -static GenOpFunc *gen_op_in[3] = { - gen_op_inb_T0_T1, - gen_op_inw_T0_T1, - gen_op_inl_T0_T1, +static void *gen_check_io_func[3] = { + helper_check_iob, + helper_check_iow, + helper_check_iol, }; -static GenOpFunc *gen_op_out[3] = { - gen_op_outb_T0_T1, - gen_op_outw_T0_T1, - gen_op_outl_T0_T1, -}; - -static GenOpFunc *gen_check_io_T0[3] = { - gen_op_check_iob_T0, - gen_op_check_iow_T0, - gen_op_check_iol_T0, -}; - -static GenOpFunc *gen_check_io_DX[3] = { - gen_op_check_iob_DX, - gen_op_check_iow_DX, - gen_op_check_iol_DX, -}; - -static void gen_check_io(DisasContext *s, int ot, int use_dx, target_ulong cur_eip) +static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip, + uint32_t svm_flags) { + int state_saved; + target_ulong next_eip; + + state_saved = 0; if (s->pe && (s->cpl > s->iopl || s->vm86)) { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - if (use_dx) - gen_check_io_DX[ot](); - else - gen_check_io_T0[ot](); + state_saved = 1; + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_0_1(gen_check_io_func[ot], + cpu_tmp2); + } + if(s->flags & (1ULL << INTERCEPT_IOIO_PROT)) { + if (!state_saved) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_jmp_im(cur_eip); + state_saved = 1; + } + svm_flags |= (1 << (4 + ot)); + next_eip = s->pc - s->cs_base; + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_0_3(helper_svm_check_io, + cpu_tmp2, + tcg_const_i32(svm_flags), + tcg_const_i32(next_eip - cur_eip)); } } @@ -1080,7 +1082,10 @@ static inline void gen_ins(DisasContext *s, int ot) gen_string_movl_A0_EDI(s); gen_op_movl_T0_0(); gen_op_st_T0_A0(ot + s->mem_index); - gen_op_in_DX_T0[ot](); + gen_op_mov_TN_reg(OT_WORD, 1, R_EDX); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[1]); + tcg_gen_andi_i32(cpu_tmp2, cpu_tmp2, 0xffff); + tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[0], cpu_tmp2); gen_op_st_T0_A0(ot + s->mem_index); gen_op_movl_T0_Dshift[ot](); #ifdef TARGET_X86_64 @@ -1099,7 +1104,13 @@ static inline void gen_outs(DisasContext *s, int ot) { gen_string_movl_A0_ESI(s); gen_op_ld_T0_A0(ot + s->mem_index); - gen_op_out_DX_T0[ot](); + + gen_op_mov_TN_reg(OT_WORD, 1, R_EDX); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[1]); + tcg_gen_andi_i32(cpu_tmp2, cpu_tmp2, 0xffff); + tcg_gen_trunc_tl_i32(cpu_tmp3, cpu_T[0]); + tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2, cpu_tmp3); + gen_op_movl_T0_Dshift[ot](); #ifdef TARGET_X86_64 if (s->aflag == 2) { @@ -1976,7 +1987,8 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(cur_eip); - gen_op_movl_seg_T0(seg_reg); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_0_2(helper_load_seg, tcg_const_i32(seg_reg), cpu_tmp2); /* abort translation because the addseg value may change or because ss32 may change. For R_SS, translation must always stop as a special handling must be done to disable hardware @@ -1990,28 +2002,6 @@ static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip) } } -#define SVM_movq_T1_im(x) gen_movtl_T1_im(x) - -static inline int -gen_svm_check_io(DisasContext *s, target_ulong pc_start, uint64_t type) -{ -#if !defined(CONFIG_USER_ONLY) - if(s->flags & (1ULL << INTERCEPT_IOIO_PROT)) { - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - SVM_movq_T1_im(s->pc - s->cs_base); - gen_jmp_im(pc_start - s->cs_base); - gen_op_geneflags(); - gen_op_svm_check_intercept_io((uint32_t)(type >> 32), (uint32_t)type); - s->cc_op = CC_OP_DYNAMIC; - /* FIXME: maybe we could move the io intercept vector to the TB as well - so we know if this is an EOB or not ... let's assume it's not - for now. */ - } -#endif - return 0; -} - static inline int svm_is_rep(int prefixes) { return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0); @@ -2019,7 +2009,7 @@ static inline int svm_is_rep(int prefixes) static inline int gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, - uint64_t type, uint64_t param) + uint32_t type, uint64_t param) { if(!(s->flags & (INTERCEPT_SVM_MASK))) /* no SVM activated */ @@ -2029,12 +2019,10 @@ gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, case SVM_EXIT_READ_CR0 ... SVM_EXIT_EXCP_BASE - 1: if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); - SVM_movq_T1_im(param); - gen_op_geneflags(); - gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type); + tcg_gen_helper_0_2(helper_svm_check_intercept_param, + tcg_const_i32(type), tcg_const_i64(param)); /* this is a special case as we do not know if the interception occurs so we assume there was none */ return 0; @@ -2042,12 +2030,10 @@ gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, if(s->flags & (1ULL << INTERCEPT_MSR_PROT)) { if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_DYNAMIC; } gen_jmp_im(pc_start - s->cs_base); - SVM_movq_T1_im(param); - gen_op_geneflags(); - gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type); + tcg_gen_helper_0_2(helper_svm_check_intercept_param, + tcg_const_i32(type), tcg_const_i64(param)); /* this is a special case as we do not know if the interception occurs so we assume there was none */ return 0; @@ -2057,12 +2043,10 @@ gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, if(s->flags & (1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR))) { if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); - s->cc_op = CC_OP_EFLAGS; } gen_jmp_im(pc_start - s->cs_base); - SVM_movq_T1_im(param); - gen_op_geneflags(); - gen_op_svm_vmexit(type >> 32, type); + tcg_gen_helper_0_2(helper_vmexit, + tcg_const_i32(type), tcg_const_i64(param)); /* we can optimize this one so TBs don't get longer than up to vmexit */ gen_eob(s); @@ -2276,9 +2260,10 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_st_T0_A0(ot + s->mem_index); if (level) { /* XXX: must save state */ - tcg_gen_helper_0_2(helper_enter64_level, + tcg_gen_helper_0_3(helper_enter64_level, tcg_const_i32(level), - tcg_const_i32((ot == OT_QUAD))); + tcg_const_i32((ot == OT_QUAD)), + cpu_T[1]); } gen_op_mov_reg_T1(ot, R_EBP); gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); @@ -2301,9 +2286,10 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) gen_op_st_T0_A0(ot + s->mem_index); if (level) { /* XXX: must save state */ - tcg_gen_helper_0_2(helper_enter_level, + tcg_gen_helper_0_3(helper_enter_level, tcg_const_i32(level), - tcg_const_i32(s->dflag)); + tcg_const_i32(s->dflag), + cpu_T[1]); } gen_op_mov_reg_T1(ot, R_EBP); gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); @@ -3208,22 +3194,6 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) } else { /* generic MMX or SSE operation */ switch(b) { - case 0xf7: - /* maskmov : we must prepare A0 */ - if (mod != 3) - goto illegal_op; -#ifdef TARGET_X86_64 - if (s->aflag == 2) { - gen_op_movq_A0_reg(R_EDI); - } else -#endif - { - gen_op_movl_A0_reg(R_EDI); - if (s->aflag == 0) - gen_op_andl_A0_ffff(); - } - gen_add_A0_ds_seg(s); - break; case 0x70: /* pshufx insn */ case 0xc6: /* pshufx insn */ case 0xc2: /* compare insns */ @@ -3295,6 +3265,26 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1); break; + case 0xf7: + /* maskmov : we must prepare A0 */ + if (mod != 3) + goto illegal_op; +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg(R_EDI); + } else +#endif + { + gen_op_movl_A0_reg(R_EDI); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } + gen_add_A0_ds_seg(s); + + tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); + tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); + tcg_gen_helper_0_3(sse_op2, cpu_ptr0, cpu_ptr1, cpu_A0); + break; default: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset); @@ -3440,7 +3430,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) /* lock generation */ if (prefixes & PREFIX_LOCK) - gen_op_lock(); + tcg_gen_helper_0_0(helper_lock); /* now check op code */ reswitch: @@ -3783,9 +3773,17 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_lcall_protected_T0_T1(dflag, s->pc - pc_start); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_0_4(helper_lcall_protected, + cpu_tmp2, cpu_T[1], + tcg_const_i32(dflag), + tcg_const_i32(s->pc - pc_start)); } else { - gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_0_4(helper_lcall_real, + cpu_tmp2, cpu_T[1], + tcg_const_i32(dflag), + tcg_const_i32(s->pc - s->cs_base)); } gen_eob(s); break; @@ -3804,7 +3802,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_ljmp_protected_T0_T1(s->pc - pc_start); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_0_3(helper_ljmp_protected, + cpu_tmp2, + cpu_T[1], + tcg_const_i32(s->pc - pc_start)); } else { gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); gen_op_movl_T0_T1(); @@ -4355,11 +4357,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_mov_TN_reg(ot, 0, reg); /* for xchg, lock is implicit */ if (!(prefixes & PREFIX_LOCK)) - gen_op_lock(); + tcg_gen_helper_0_0(helper_lock); gen_op_ld_T1_A0(ot + s->mem_index); gen_op_st_T0_A0(ot + s->mem_index); if (!(prefixes & PREFIX_LOCK)) - gen_op_unlock(); + tcg_gen_helper_0_0(helper_unlock); gen_op_mov_reg_T1(ot, reg); } break; @@ -5117,13 +5119,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - gen_check_io(s, ot, 1, pc_start - s->cs_base); gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - if (gen_svm_check_io(s, pc_start, - SVM_IOIO_TYPE_MASK | (1 << (4+ot)) | - svm_is_rep(prefixes) | 4 | (1 << (7+s->aflag)))) - break; + gen_check_io(s, ot, pc_start - s->cs_base, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { @@ -5136,13 +5135,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - gen_check_io(s, ot, 1, pc_start - s->cs_base); gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - if (gen_svm_check_io(s, pc_start, - (1 << (4+ot)) | svm_is_rep(prefixes) | - 4 | (1 << (7+s->aflag)))) - break; + gen_check_io(s, ot, pc_start - s->cs_base, + svm_is_rep(prefixes) | 4); if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); } else { @@ -5161,12 +5157,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag ? OT_LONG : OT_WORD; val = ldub_code(s->pc++); gen_op_movl_T0_im(val); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, - SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | - (1 << (4+ot)))) - break; - gen_op_in[ot](); + gen_check_io(s, ot, pc_start - s->cs_base, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2); gen_op_mov_reg_T1(ot, R_EAX); break; case 0xe6: @@ -5177,12 +5171,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag ? OT_LONG : OT_WORD; val = ldub_code(s->pc++); gen_op_movl_T0_im(val); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, svm_is_rep(prefixes) | - (1 << (4+ot)))) - break; + gen_check_io(s, ot, pc_start - s->cs_base, + svm_is_rep(prefixes)); gen_op_mov_TN_reg(ot, 1, R_EAX); - gen_op_out[ot](); + + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_andi_i32(cpu_tmp2, cpu_tmp2, 0xffff); + tcg_gen_trunc_tl_i32(cpu_tmp3, cpu_T[1]); + tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2, cpu_tmp3); break; case 0xec: case 0xed: @@ -5192,12 +5188,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, - SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | - (1 << (4+ot)))) - break; - gen_op_in[ot](); + gen_check_io(s, ot, pc_start - s->cs_base, + SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes)); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2); gen_op_mov_reg_T1(ot, R_EAX); break; case 0xee: @@ -5208,12 +5202,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) ot = dflag ? OT_LONG : OT_WORD; gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_andl_T0_ffff(); - gen_check_io(s, ot, 0, pc_start - s->cs_base); - if (gen_svm_check_io(s, pc_start, - svm_is_rep(prefixes) | (1 << (4+ot)))) - break; + gen_check_io(s, ot, pc_start - s->cs_base, + svm_is_rep(prefixes)); gen_op_mov_TN_reg(ot, 1, R_EAX); - gen_op_out[ot](); + + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); + tcg_gen_andi_i32(cpu_tmp2, cpu_tmp2, 0xffff); + tcg_gen_trunc_tl_i32(cpu_tmp3, cpu_T[1]); + tcg_gen_helper_0_2(helper_out_func[ot], cpu_tmp2, cpu_tmp3); break; /************************/ @@ -5246,7 +5242,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_lret_protected(s->dflag, val); + tcg_gen_helper_0_2(helper_lret_protected, + tcg_const_i32(s->dflag), + tcg_const_i32(val)); } else { gen_stack_A0(s); /* pop offset */ @@ -5273,20 +5271,22 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; if (!s->pe) { /* real mode */ - gen_op_iret_real(s->dflag); + tcg_gen_helper_0_1(helper_iret_real, tcg_const_i32(s->dflag)); s->cc_op = CC_OP_EFLAGS; } else if (s->vm86) { if (s->iopl != 3) { gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { - gen_op_iret_real(s->dflag); + tcg_gen_helper_0_1(helper_iret_real, tcg_const_i32(s->dflag)); s->cc_op = CC_OP_EFLAGS; } } else { if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_jmp_im(pc_start - s->cs_base); - gen_op_iret_protected(s->dflag, s->pc - s->cs_base); + tcg_gen_helper_0_2(helper_iret_protected, + tcg_const_i32(s->dflag), + tcg_const_i32(s->pc - s->cs_base)); s->cc_op = CC_OP_EFLAGS; } gen_eob(s); @@ -5723,10 +5723,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_mov_TN_reg(ot, 0, reg); gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_jmp_im(pc_start - s->cs_base); + tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]); if (ot == OT_WORD) - tcg_gen_helper_0_0(helper_boundw); + tcg_gen_helper_0_2(helper_boundw, cpu_A0, cpu_tmp2); else - tcg_gen_helper_0_0(helper_boundl); + tcg_gen_helper_0_2(helper_boundl, cpu_A0, cpu_tmp2); break; case 0x1c8 ... 0x1cf: /* bswap reg */ reg = (b & 7) | REX_B(s); @@ -6134,7 +6135,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0)) break; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); - gen_op_lmsw_T0(); + tcg_gen_helper_0_1(helper_lmsw, cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } @@ -6223,6 +6224,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } else { gen_op_mov_TN_reg(ot, 0, rm); } + gen_op_mov_TN_reg(ot, 1, reg); if (s->cc_op != CC_OP_DYNAMIC) gen_op_set_cc_op(s->cc_op); gen_op_arpl(); @@ -6299,14 +6301,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (b & 2) { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0 + reg); gen_op_mov_TN_reg(ot, 0, rm); - gen_op_movl_crN_T0(reg); + tcg_gen_helper_0_2(helper_movl_crN_T0, + tcg_const_i32(reg), cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0 + reg); #if !defined(CONFIG_USER_ONLY) if (reg == 8) - gen_op_movtl_T0_cr8(); + tcg_gen_helper_1_0(helper_movtl_T0_cr8, cpu_T[0]); else #endif gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg])); @@ -6338,7 +6341,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) if (b & 2) { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg); gen_op_mov_TN_reg(ot, 0, rm); - gen_op_movl_drN_T0(reg); + tcg_gen_helper_0_2(helper_movl_drN_T0, + tcg_const_i32(reg), cpu_T[0]); gen_jmp_im(s->pc - s->cs_base); gen_eob(s); } else { @@ -6353,7 +6357,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); } else { gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); - gen_op_clts(); + tcg_gen_helper_0_0(helper_clts); /* abort block because static cpu state changed */ gen_jmp_im(s->pc - s->cs_base); gen_eob(s); @@ -6485,11 +6489,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } /* lock generation */ if (s->prefix & PREFIX_LOCK) - gen_op_unlock(); + tcg_gen_helper_0_0(helper_unlock); return s->pc; illegal_op: if (s->prefix & PREFIX_LOCK) - gen_op_unlock(); + tcg_gen_helper_0_0(helper_unlock); /* XXX: ensure that no lock was generated */ gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); return s->pc; @@ -6861,7 +6865,8 @@ void optimize_flags_init(void) cpu_T[1] = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG2, "T1"); cpu_A0 = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG3, "A0"); #endif -#if defined(__i386__) +#if defined(__i386__) && (TARGET_LONG_BITS <= HOST_LONG_BITS) + /* XXX: must be suppressed once there are less fixed registers */ cpu_tmp1 = tcg_global_reg2_new_hack(TCG_TYPE_I64, TCG_AREG1, TCG_AREG2, "tmp1"); #endif } @@ -6957,10 +6962,11 @@ static inline int gen_intermediate_code_internal(CPUState *env, #endif cpu_tmp0 = tcg_temp_new(TCG_TYPE_TL); -#if !defined(__i386__) +#if !(defined(__i386__) && (TARGET_LONG_BITS <= HOST_LONG_BITS)) cpu_tmp1 = tcg_temp_new(TCG_TYPE_I64); #endif cpu_tmp2 = tcg_temp_new(TCG_TYPE_I32); + cpu_tmp3 = tcg_temp_new(TCG_TYPE_I32); cpu_ptr0 = tcg_temp_new(TCG_TYPE_PTR); cpu_ptr1 = tcg_temp_new(TCG_TYPE_PTR); |