diff options
Diffstat (limited to 'target-i386/helper.c')
-rw-r--r-- | target-i386/helper.c | 309 |
1 files changed, 179 insertions, 130 deletions
diff --git a/target-i386/helper.c b/target-i386/helper.c index 0d0f5ff4d8..da36f8bd1d 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(); } |