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
This commit is contained in:
bellard 2008-05-15 16:46:30 +00:00
parent 6e01bdaedc
commit b8b6a50b55
10 changed files with 405 additions and 486 deletions

View File

@ -3,12 +3,13 @@ Correctness issues:
- rework eflags optimization (will be a consequence of TCG port) - rework eflags optimization (will be a consequence of TCG port)
- SVM: rework the implementation: simplify code, move most intercept - SVM: rework the implementation: simplify code, move most intercept
tests as dynamic, correct segment access, verify exception safety, 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 - arpl eflags computation is invalid
- x86_64: fxsave/fxrestore intel/amd differences - x86_64: fxsave/fxrestore intel/amd differences
- x86_64: lcall/ljmp intel/amd differences ? - x86_64: lcall/ljmp intel/amd differences ?
- x86_64: cmpxchgl 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 - x86: monitor invalid
- better code fetch (different exception handling + CS.limit support) - better code fetch (different exception handling + CS.limit support)
- user/kernel PUSHL/POPL in helper.c - user/kernel PUSHL/POPL in helper.c
@ -19,10 +20,18 @@ Correctness issues:
- full support of segment limit/rights - full support of segment limit/rights
- full x87 exception support - full x87 exception support
- improve x87 bit exactness (use bochs code ?) - improve x87 bit exactness (use bochs code ?)
- DRx register support
- CR0.AC emulation
- SSE alignment checks
- fix SSE min/max with nans
Optimizations/Features: Optimizations/Features:
- finish TCG port - finish TCG port
- add SVM nested paging support
- add VMX support
- add AVX support
- add SSE5 support
- evaluate x87 stack pointer statically - evaluate x87 stack pointer statically
- find a way to avoid translating several time the same TB if CR0.TS - find a way to avoid translating several time the same TB if CR0.TS
is set or not. is set or not.

View File

@ -105,16 +105,6 @@ typedef struct CCTable {
extern CCTable cc_table[]; 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_cr0(CPUX86State *env, uint32_t new_cr0);
void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3); void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4); 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" #include "helper.h"
void helper_mulq_EAX_T0(void); static inline void svm_check_intercept(uint32_t type)
void helper_imulq_EAX_T0(void); {
void helper_imulq_T0_T1(void); helper_svm_check_intercept_param(type, 0);
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);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
@ -363,7 +346,6 @@ extern const CPU86_LDouble f15rk[7];
void fpu_raise_exception(void); void fpu_raise_exception(void);
void restore_native_fp_state(CPUState *env); void restore_native_fp_state(CPUState *env);
void save_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 parity_table[256];
extern const uint8_t rclw_table[32]; extern const uint8_t rclw_table[32];

View File

@ -17,6 +17,7 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#define CPU_NO_GLOBAL_REGS
#include "exec.h" #include "exec.h"
#include "host-utils.h" #include "host-utils.h"
@ -93,16 +94,16 @@ const CPU86_LDouble f15rk[7] =
3.32192809488736234781L, /*l2t*/ 3.32192809488736234781L, /*l2t*/
}; };
/* thread support */ /* broken thread support */
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
void cpu_lock(void) void helper_lock(void)
{ {
spin_lock(&global_cpu_lock); spin_lock(&global_cpu_lock);
} }
void cpu_unlock(void) void helper_unlock(void)
{ {
spin_unlock(&global_cpu_lock); 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) 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) int next_eip_addend)
{ {
if (!is_int) { 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); intno = check_exception(intno, &error_code);
} }
@ -1857,19 +1873,19 @@ void helper_das(void)
FORCE_RET(); FORCE_RET();
} }
void helper_cmpxchg8b(void) void helper_cmpxchg8b(target_ulong a0)
{ {
uint64_t d; uint64_t d;
int eflags; int eflags;
eflags = cc_table[CC_OP].compute_all(); eflags = cc_table[CC_OP].compute_all();
d = ldq(A0); d = ldq(a0);
if (d == (((uint64_t)EDX << 32) | EAX)) { if (d == (((uint64_t)EDX << 32) | EAX)) {
stq(A0, ((uint64_t)ECX << 32) | EBX); stq(a0, ((uint64_t)ECX << 32) | EBX);
eflags |= CC_Z; eflags |= CC_Z;
} else { } else {
EDX = d >> 32; EDX = (uint32_t)(d >> 32);
EAX = d; EAX = (uint32_t)d;
eflags &= ~CC_Z; eflags &= ~CC_Z;
} }
CC_SRC = eflags; 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; target_ulong ssp;
uint32_t esp_mask, esp, ebp; 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))); stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
} }
esp -= 4; esp -= 4;
stl(ssp + (esp & esp_mask), T1); stl(ssp + (esp & esp_mask), t1);
} else { } else {
/* 16 bit */ /* 16 bit */
esp -= 2; esp -= 2;
@ -2014,12 +2030,12 @@ void helper_enter_level(int level, int data32)
stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask))); stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
} }
esp -= 2; esp -= 2;
stw(ssp + (esp & esp_mask), T1); stw(ssp + (esp & esp_mask), t1);
} }
} }
#ifdef TARGET_X86_64 #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; target_ulong esp, ebp;
ebp = EBP; ebp = EBP;
@ -2034,7 +2050,7 @@ void helper_enter64_level(int level, int data64)
stq(esp, ldq(ebp)); stq(esp, ldq(ebp));
} }
esp -= 8; esp -= 8;
stq(esp, T1); stq(esp, t1);
} else { } else {
/* 16 bit */ /* 16 bit */
esp -= 2; esp -= 2;
@ -2044,7 +2060,7 @@ void helper_enter64_level(int level, int data64)
stw(esp, lduw(ebp)); stw(esp, lduw(ebp));
} }
esp -= 2; esp -= 2;
stw(esp, T1); stw(esp, t1);
} }
} }
#endif #endif
@ -2231,14 +2247,13 @@ void helper_load_seg(int seg_reg, int selector)
} }
/* protected mode jump */ /* 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; 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) if ((new_cs & 0xfffc) == 0)
raise_exception_err(EXCP0D_GPF, 0); raise_exception_err(EXCP0D_GPF, 0);
if (load_segment(&e1, &e2, new_cs) != 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 */ /* 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; uint32_t esp, esp_mask;
target_ulong ssp; target_ulong ssp;
new_cs = T0; new_eip = new_eip1;
new_eip = T1;
esp = ESP; esp = ESP;
esp_mask = get_sp_mask(env->segs[R_SS].flags); esp_mask = get_sp_mask(env->segs[R_SS].flags);
ssp = env->segs[R_SS].base; ssp = env->segs[R_SS].base;
@ -2348,16 +2363,15 @@ void helper_lcall_real_T0_T1(int shift, int next_eip)
} }
/* protected mode call */ /* 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 e1, e2, cpl, dpl, rpl, selector, offset, param_count;
uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask; uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
uint32_t val, limit, old_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; next_eip = env->eip + next_eip_addend;
#ifdef DEBUG_PCALL #ifdef DEBUG_PCALL
if (loglevel & CPU_LOG_PCALL) { if (loglevel & CPU_LOG_PCALL) {
@ -2922,34 +2936,55 @@ void helper_sysexit(void)
#endif #endif
} }
void helper_movl_crN_T0(int reg) void helper_movl_crN_T0(int reg, target_ulong t0)
{ {
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
switch(reg) { switch(reg) {
case 0: case 0:
cpu_x86_update_cr0(env, T0); cpu_x86_update_cr0(env, t0);
break; break;
case 3: case 3:
cpu_x86_update_cr3(env, T0); cpu_x86_update_cr3(env, t0);
break; break;
case 4: case 4:
cpu_x86_update_cr4(env, T0); cpu_x86_update_cr4(env, t0);
break; break;
case 8: case 8:
cpu_set_apic_tpr(env, T0); cpu_set_apic_tpr(env, t0);
env->cr[8] = T0; env->cr[8] = t0;
break; break;
default: default:
env->cr[reg] = T0; env->cr[reg] = t0;
break; break;
} }
#endif #endif
} }
/* XXX: do more */ void helper_lmsw(target_ulong t0)
void helper_movl_drN_T0(int reg)
{ {
env->dr[reg] = 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, target_ulong t0)
{
env->dr[reg] = t0;
} }
void helper_invlpg(target_ulong addr) void helper_invlpg(target_ulong addr)
@ -2975,10 +3010,10 @@ void helper_rdpmc(void)
raise_exception(EXCP0D_GPF); raise_exception(EXCP0D_GPF);
} }
if (!svm_check_intercept_param(SVM_EXIT_RDPMC, 0)) { helper_svm_check_intercept_param(SVM_EXIT_RDPMC, 0);
/* currently unimplemented */
raise_exception_err(EXCP06_ILLOP, 0); /* currently unimplemented */
} raise_exception_err(EXCP06_ILLOP, 0);
} }
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
@ -3118,7 +3153,7 @@ void helper_rdmsr(void)
} }
#endif #endif
void helper_lsl(uint32_t selector) uint32_t helper_lsl(uint32_t selector)
{ {
unsigned int limit; unsigned int limit;
uint32_t e1, e2, eflags; uint32_t e1, e2, eflags;
@ -3153,15 +3188,15 @@ void helper_lsl(uint32_t selector)
if (dpl < cpl || dpl < rpl) { if (dpl < cpl || dpl < rpl) {
fail: fail:
CC_SRC = eflags & ~CC_Z; CC_SRC = eflags & ~CC_Z;
return; return 0;
} }
} }
limit = get_seg_limit(e1, e2); limit = get_seg_limit(e1, e2);
T1 = limit;
CC_SRC = eflags | CC_Z; 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; uint32_t e1, e2, eflags;
int rpl, dpl, cpl, type; int rpl, dpl, cpl, type;
@ -3200,11 +3235,11 @@ void helper_lar(uint32_t selector)
if (dpl < cpl || dpl < rpl) { if (dpl < cpl || dpl < rpl) {
fail: fail:
CC_SRC = eflags & ~CC_Z; CC_SRC = eflags & ~CC_Z;
return; return 0;
} }
} }
T1 = e2 & 0x00f0ff00;
CC_SRC = eflags | CC_Z; CC_SRC = eflags | CC_Z;
return e2 & 0x00f0ff00;
} }
void helper_verr(uint32_t selector) void helper_verr(uint32_t selector)
@ -4412,36 +4447,36 @@ static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
return 0; return 0;
} }
void helper_mulq_EAX_T0(void) void helper_mulq_EAX_T0(target_ulong t0)
{ {
uint64_t r0, r1; uint64_t r0, r1;
mulu64(&r0, &r1, EAX, T0); mulu64(&r0, &r1, EAX, t0);
EAX = r0; EAX = r0;
EDX = r1; EDX = r1;
CC_DST = r0; CC_DST = r0;
CC_SRC = r1; CC_SRC = r1;
} }
void helper_imulq_EAX_T0(void) void helper_imulq_EAX_T0(target_ulong t0)
{ {
uint64_t r0, r1; uint64_t r0, r1;
muls64(&r0, &r1, EAX, T0); muls64(&r0, &r1, EAX, t0);
EAX = r0; EAX = r0;
EDX = r1; EDX = r1;
CC_DST = r0; CC_DST = r0;
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); 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; uint64_t r0, r1;
muls64(&r0, &r1, T0, T1); muls64(&r0, &r1, t0, t1);
T0 = r0;
CC_DST = r0; CC_DST = r0;
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
return r0;
} }
void helper_divq_EAX(target_ulong t0) void helper_divq_EAX(target_ulong t0)
@ -4553,24 +4588,23 @@ void helper_reset_inhibit_irq(void)
env->hflags &= ~HF_INHIBIT_IRQ_MASK; env->hflags &= ~HF_INHIBIT_IRQ_MASK;
} }
void helper_boundw(void) void helper_boundw(target_ulong a0, int v)
{ {
int low, high, v; int low, high;
low = ldsw(A0); low = ldsw(a0);
high = ldsw(A0 + 2); high = ldsw(a0 + 2);
v = (int16_t)T0; v = (int16_t)v;
if (v < low || v > high) { if (v < low || v > high) {
raise_exception(EXCP05_BOUND); raise_exception(EXCP05_BOUND);
} }
FORCE_RET(); FORCE_RET();
} }
void helper_boundl(void) void helper_boundl(target_ulong a0, int v)
{ {
int low, high, v; int low, high;
low = ldl(A0); low = ldl(a0);
high = ldl(A0 + 4); high = ldl(a0 + 4);
v = T0;
if (v < low || v > high) { if (v < low || v > high) {
raise_exception(EXCP05_BOUND); raise_exception(EXCP05_BOUND);
} }
@ -4661,18 +4695,35 @@ void helper_clgi(void)
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
void helper_vmrun(void) { } void helper_vmrun(void)
void helper_vmmcall(void) { } {
void helper_vmload(void) { } }
void helper_vmsave(void) { } void helper_vmmcall(void)
void helper_skinit(void) { } {
void helper_invlpga(void) { } }
void vmexit(uint64_t exit_code, uint64_t exit_info_1) { } void helper_vmload(void)
int svm_check_intercept_param(uint32_t type, uint64_t param) {
}
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 #else
static inline uint32_t static inline uint32_t
@ -4702,7 +4753,6 @@ void helper_vmrun(void)
fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr); fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
env->vm_vmcb = addr; env->vm_vmcb = addr;
regs_to_env();
/* save the current CPU state in the hsave page */ /* save the current CPU state in the hsave page */
stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base); stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
@ -4801,8 +4851,6 @@ void helper_vmrun(void)
helper_stgi(); helper_stgi();
regs_to_env();
/* maybe we need to inject an event */ /* maybe we need to inject an event */
event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)); event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
if (event_inj & SVM_EVTINJ_VALID) { if (event_inj & SVM_EVTINJ_VALID) {
@ -4927,95 +4975,98 @@ void helper_invlpga(void)
tlb_flush(env, 0); 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) { switch(type) {
case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8: case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) { if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) {
vmexit(type, param); helper_vmexit(type, param);
return 1;
} }
break; break;
case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8: case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8:
if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) { if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) {
vmexit(type, param); helper_vmexit(type, param);
return 1;
} }
break; break;
case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8: case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) { if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) {
vmexit(type, param); helper_vmexit(type, param);
return 1;
} }
break; break;
case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8: case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8:
if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) { if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) {
vmexit(type, param); helper_vmexit(type, param);
return 1;
} }
break; break;
case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16: case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16:
if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) { if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) {
vmexit(type, param); helper_vmexit(type, param);
return 1;
} }
break; break;
case SVM_EXIT_IOIO: 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; break;
case SVM_EXIT_MSR: case SVM_EXIT_MSR:
if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) { if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) {
/* FIXME: this should be read in at vmrun (faster this way?) */ /* 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)); uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
uint32_t t0, t1;
switch((uint32_t)ECX) { switch((uint32_t)ECX) {
case 0 ... 0x1fff: case 0 ... 0x1fff:
T0 = (ECX * 2) % 8; t0 = (ECX * 2) % 8;
T1 = ECX / 8; t1 = ECX / 8;
break; break;
case 0xc0000000 ... 0xc0001fff: case 0xc0000000 ... 0xc0001fff:
T0 = (8192 + ECX - 0xc0000000) * 2; t0 = (8192 + ECX - 0xc0000000) * 2;
T1 = (T0 / 8); t1 = (t0 / 8);
T0 %= 8; t0 %= 8;
break; break;
case 0xc0010000 ... 0xc0011fff: case 0xc0010000 ... 0xc0011fff:
T0 = (16384 + ECX - 0xc0010000) * 2; t0 = (16384 + ECX - 0xc0010000) * 2;
T1 = (T0 / 8); t1 = (t0 / 8);
T0 %= 8; t0 %= 8;
break; break;
default: default:
vmexit(type, param); helper_vmexit(type, param);
return 1; t0 = 0;
t1 = 0;
break;
} }
if (ldub_phys(addr + T1) & ((1 << param) << T0)) if (ldub_phys(addr + t1) & ((1 << param) << t0))
vmexit(type, param); helper_vmexit(type, param);
return 1;
} }
break; break;
default: default:
if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) { if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) {
vmexit(type, param); helper_vmexit(type, param);
return 1;
} }
break; 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; uint32_t int_ctl;
if (loglevel & CPU_LOG_TB_IN_ASM) 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, exit_code, exit_info_1,
ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)), ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
EIP); EIP);
@ -5105,8 +5156,7 @@ void vmexit(uint64_t exit_code, uint64_t exit_info_1)
/* other setups */ /* other setups */
cpu_x86_set_cpl(env, 0); cpu_x86_set_cpl(env, 0);
stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code_hi), (uint32_t)(exit_code >> 32)); stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
stl_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); stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
helper_clgi(); helper_clgi();
@ -5137,7 +5187,6 @@ void vmexit(uint64_t exit_code, uint64_t exit_info_1)
env->error_code = 0; env->error_code = 0;
env->old_exception = -1; env->old_exception = -1;
regs_to_env();
cpu_loop_exit(); cpu_loop_exit();
} }

View File

@ -1,5 +1,7 @@
#define TCG_HELPER_PROTO #define TCG_HELPER_PROTO
void helper_lock(void);
void helper_unlock(void);
void helper_divb_AL(target_ulong t0); void helper_divb_AL(target_ulong t0);
void helper_idivb_AL(target_ulong t0); void helper_idivb_AL(target_ulong t0);
void helper_divw_AX(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_divl_EAX(target_ulong t0);
void helper_idivl_EAX(target_ulong t0); void helper_idivl_EAX(target_ulong t0);
#ifdef TARGET_X86_64 #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_divq_EAX(target_ulong t0);
void helper_idivq_EAX(target_ulong t0); void helper_idivq_EAX(target_ulong t0);
#endif #endif
@ -18,26 +23,34 @@ void helper_aas(void);
void helper_daa(void); void helper_daa(void);
void helper_das(void); void helper_das(void);
void helper_lsl(uint32_t selector); uint32_t helper_lsl(uint32_t selector);
void helper_lar(uint32_t selector); uint32_t helper_lar(uint32_t selector);
void helper_verr(uint32_t selector); void helper_verr(uint32_t selector);
void helper_verw(uint32_t selector); void helper_verw(uint32_t selector);
void helper_lldt(int selector); void helper_lldt(int selector);
void helper_ltr(int selector); void helper_ltr(int selector);
void helper_load_seg(int seg_reg, int selector); void helper_load_seg(int seg_reg, int selector);
void helper_ljmp_protected_T0_T1(int next_eip); void helper_ljmp_protected(int new_cs, target_ulong new_eip,
void helper_lcall_real_T0_T1(int shift, int next_eip); int next_eip_addend);
void helper_lcall_protected_T0_T1(int shift, int next_eip); 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_real(int shift);
void helper_iret_protected(int shift, int next_eip); void helper_iret_protected(int shift, int next_eip);
void helper_lret_protected(int shift, int addend); void helper_lret_protected(int shift, int addend);
void helper_movl_crN_T0(int reg); void helper_movl_crN_T0(int reg, target_ulong t0);
void helper_movl_drN_T0(int reg); 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_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 #ifdef TARGET_X86_64
void helper_enter64_level(int level, int data64); void helper_enter64_level(int level, int data64, target_ulong t1);
#endif #endif
void helper_sysenter(void); void helper_sysenter(void);
void helper_sysexit(void); void helper_sysexit(void);
@ -55,9 +68,10 @@ void helper_cli(void);
void helper_sti(void); void helper_sti(void);
void helper_set_inhibit_irq(void); void helper_set_inhibit_irq(void);
void helper_reset_inhibit_irq(void); void helper_reset_inhibit_irq(void);
void helper_boundw(void); void helper_boundw(target_ulong a0, int v);
void helper_boundl(void); void helper_boundl(target_ulong a0, int v);
void helper_rsm(void); void helper_rsm(void);
void helper_cmpxchg8b(target_ulong a0);
void helper_single_step(void); void helper_single_step(void);
void helper_cpuid(void); void helper_cpuid(void);
void helper_rdtsc(void); void helper_rdtsc(void);
@ -65,6 +79,20 @@ void helper_rdpmc(void);
void helper_rdmsr(void); void helper_rdmsr(void);
void helper_wrmsr(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_vmrun(void);
void helper_vmmcall(void); void helper_vmmcall(void);
void helper_vmload(void); void helper_vmload(void);

View File

@ -276,17 +276,17 @@ void OPPROTO op_imull_T0_T1(void)
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
void OPPROTO op_mulq_EAX_T0(void) void OPPROTO op_mulq_EAX_T0(void)
{ {
helper_mulq_EAX_T0(); helper_mulq_EAX_T0(T0);
} }
void OPPROTO op_imulq_EAX_T0(void) void OPPROTO op_imulq_EAX_T0(void)
{ {
helper_imulq_EAX_T0(); helper_imulq_EAX_T0(T0);
} }
void OPPROTO op_imulq_T0_T1(void) void OPPROTO op_imulq_T0_T1(void)
{ {
helper_imulq_T0_T1(); T0 = helper_imulq_T0_T1(T0, T1);
} }
#endif #endif
@ -351,7 +351,7 @@ void OPPROTO op_into(void)
void OPPROTO op_cmpxchg8b(void) void OPPROTO op_cmpxchg8b(void)
{ {
helper_cmpxchg8b(); helper_cmpxchg8b(A0);
} }
/* multiple size ops */ /* multiple size ops */
@ -522,12 +522,6 @@ void OPPROTO op_das(void)
/* segment handling */ /* segment handling */
/* never use it with R_CS */
void OPPROTO op_movl_seg_T0(void)
{
helper_load_seg(PARAM1, T0);
}
/* faster VM86 version */ /* faster VM86 version */
void OPPROTO op_movl_seg_T0_vm(void) void OPPROTO op_movl_seg_T0_vm(void)
{ {
@ -548,12 +542,20 @@ void OPPROTO op_movl_T0_seg(void)
void OPPROTO op_lsl(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) 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) void OPPROTO op_verr(void)
@ -585,104 +587,6 @@ void OPPROTO op_arpl_update(void)
CC_SRC = (eflags & ~CC_Z) | T1; 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) void OPPROTO op_movl_T0_env(void)
{ {
T0 = *(uint32_t *)((char *)env + PARAM1); T0 = *(uint32_t *)((char *)env + PARAM1);
@ -718,12 +622,6 @@ void OPPROTO op_movtl_env_T1(void)
*(target_ulong *)((char *)env + PARAM1) = T1; *(target_ulong *)((char *)env + PARAM1) = T1;
} }
void OPPROTO op_clts(void)
{
env->cr[0] &= ~CR0_TS_MASK;
env->hflags &= ~HF_TS_MASK;
}
/* flags handling */ /* flags handling */
void OPPROTO op_jmp_label(void) void OPPROTO op_jmp_label(void)
@ -1028,17 +926,6 @@ void OPPROTO op_fcomi_dummy(void)
T0 = 0; T0 = 0;
} }
/* threading support */
void OPPROTO op_lock(void)
{
cpu_lock();
}
void OPPROTO op_unlock(void)
{
cpu_unlock();
}
/* SSE support */ /* SSE support */
void OPPROTO op_com_dummy(void) void OPPROTO op_com_dummy(void)
{ {

View File

@ -471,12 +471,12 @@ void glue(helper_psadbw, SUFFIX) (Reg *d, Reg *s)
#endif #endif
} }
void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s) void glue(helper_maskmov, SUFFIX) (Reg *d, Reg *s, target_ulong a0)
{ {
int i; int i;
for(i = 0; i < (8 << SHIFT); i++) { for(i = 0; i < (8 << SHIFT); i++) {
if (s->B(i) & 0x80) if (s->B(i) & 0x80)
stb(A0 + i, d->B(i)); stb(a0 + i, d->B(i));
} }
FORCE_RET(); FORCE_RET();
} }

View File

@ -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_pmaddwd, SUFFIX) (Reg *d, Reg *s);
void glue(helper_psadbw, 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); void glue(helper_movl_mm_T0, SUFFIX) (Reg *d, uint32_t val);
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
void glue(helper_movq_mm_T0, SUFFIX) (Reg *d, uint64_t val); void glue(helper_movq_mm_T0, SUFFIX) (Reg *d, uint64_t val);

View File

@ -554,39 +554,6 @@ void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void)
T0 = DF << SHIFT; 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 DATA_BITS
#undef SHIFT_MASK #undef SHIFT_MASK
#undef SHIFT1_MASK #undef SHIFT1_MASK

View File

@ -71,8 +71,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
uint32_t int_vector; uint32_t int_vector;
uint32_t int_state; uint32_t int_state;
uint8_t reserved_3[4]; uint8_t reserved_3[4];
uint32_t exit_code; uint64_t exit_code;
uint32_t exit_code_hi;
uint64_t exit_info_1; uint64_t exit_info_1;
uint64_t exit_info_2; uint64_t exit_info_2;
uint32_t exit_int_info; uint32_t exit_int_info;
@ -323,14 +322,6 @@ struct __attribute__ ((__packed__)) vmcb {
/* function references */ /* 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 INTERCEPTED(mask) (env->intercept & mask)
#define INTERCEPTEDw(var, mask) (env->intercept ## var & mask) #define INTERCEPTEDw(var, mask) (env->intercept ## var & mask)
#define INTERCEPTEDl(var, mask) (env->intercept ## var & mask) #define INTERCEPTEDl(var, mask) (env->intercept ## var & mask)

View File

@ -60,7 +60,7 @@
/* global register indexes */ /* global register indexes */
static TCGv cpu_env, cpu_T[2], cpu_A0; static TCGv cpu_env, cpu_T[2], cpu_A0;
/* local register indexes (only used inside old micro ops) */ /* 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 #ifdef TARGET_X86_64
static int x86_64_hregs; 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] = { static void *helper_in_func[3] = {
gen_op_inb_DX_T0, helper_inb,
gen_op_inw_DX_T0, helper_inw,
gen_op_inl_DX_T0, helper_inl,
}; };
static GenOpFunc *gen_op_out_DX_T0[3] = { static void *helper_out_func[3] = {
gen_op_outb_DX_T0, helper_outb,
gen_op_outw_DX_T0, helper_outw,
gen_op_outl_DX_T0, helper_outl,
}; };
static GenOpFunc *gen_op_in[3] = { static void *gen_check_io_func[3] = {
gen_op_inb_T0_T1, helper_check_iob,
gen_op_inw_T0_T1, helper_check_iow,
gen_op_inl_T0_T1, helper_check_iol,
}; };
static GenOpFunc *gen_op_out[3] = { static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip,
gen_op_outb_T0_T1, uint32_t svm_flags)
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)
{ {
int state_saved;
target_ulong next_eip;
state_saved = 0;
if (s->pe && (s->cpl > s->iopl || s->vm86)) { if (s->pe && (s->cpl > s->iopl || s->vm86)) {
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_jmp_im(cur_eip); gen_jmp_im(cur_eip);
if (use_dx) state_saved = 1;
gen_check_io_DX[ot](); tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]);
else tcg_gen_helper_0_1(gen_check_io_func[ot],
gen_check_io_T0[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_string_movl_A0_EDI(s);
gen_op_movl_T0_0(); gen_op_movl_T0_0();
gen_op_st_T0_A0(ot + s->mem_index); 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_st_T0_A0(ot + s->mem_index);
gen_op_movl_T0_Dshift[ot](); gen_op_movl_T0_Dshift[ot]();
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
@ -1099,7 +1104,13 @@ static inline void gen_outs(DisasContext *s, int ot)
{ {
gen_string_movl_A0_ESI(s); gen_string_movl_A0_ESI(s);
gen_op_ld_T0_A0(ot + s->mem_index); 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](); gen_op_movl_T0_Dshift[ot]();
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (s->aflag == 2) { 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) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_jmp_im(cur_eip); 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 /* abort translation because the addseg value may change or
because ss32 may change. For R_SS, translation must always because ss32 may change. For R_SS, translation must always
stop as a special handling must be done to disable hardware 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) static inline int svm_is_rep(int prefixes)
{ {
return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0); return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
@ -2019,7 +2009,7 @@ static inline int svm_is_rep(int prefixes)
static inline int static inline int
gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start, 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))) if(!(s->flags & (INTERCEPT_SVM_MASK)))
/* no SVM activated */ /* 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: case SVM_EXIT_READ_CR0 ... SVM_EXIT_EXCP_BASE - 1:
if (s->cc_op != CC_OP_DYNAMIC) { if (s->cc_op != CC_OP_DYNAMIC) {
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
s->cc_op = CC_OP_DYNAMIC;
} }
gen_jmp_im(pc_start - s->cs_base); gen_jmp_im(pc_start - s->cs_base);
SVM_movq_T1_im(param); tcg_gen_helper_0_2(helper_svm_check_intercept_param,
gen_op_geneflags(); tcg_const_i32(type), tcg_const_i64(param));
gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type);
/* this is a special case as we do not know if the interception occurs /* this is a special case as we do not know if the interception occurs
so we assume there was none */ so we assume there was none */
return 0; 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->flags & (1ULL << INTERCEPT_MSR_PROT)) {
if (s->cc_op != CC_OP_DYNAMIC) { if (s->cc_op != CC_OP_DYNAMIC) {
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
s->cc_op = CC_OP_DYNAMIC;
} }
gen_jmp_im(pc_start - s->cs_base); gen_jmp_im(pc_start - s->cs_base);
SVM_movq_T1_im(param); tcg_gen_helper_0_2(helper_svm_check_intercept_param,
gen_op_geneflags(); tcg_const_i32(type), tcg_const_i64(param));
gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type);
/* this is a special case as we do not know if the interception occurs /* this is a special case as we do not know if the interception occurs
so we assume there was none */ so we assume there was none */
return 0; 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->flags & (1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR))) {
if (s->cc_op != CC_OP_DYNAMIC) { if (s->cc_op != CC_OP_DYNAMIC) {
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
s->cc_op = CC_OP_EFLAGS;
} }
gen_jmp_im(pc_start - s->cs_base); gen_jmp_im(pc_start - s->cs_base);
SVM_movq_T1_im(param); tcg_gen_helper_0_2(helper_vmexit,
gen_op_geneflags(); tcg_const_i32(type), tcg_const_i64(param));
gen_op_svm_vmexit(type >> 32, type);
/* we can optimize this one so TBs don't get longer /* we can optimize this one so TBs don't get longer
than up to vmexit */ than up to vmexit */
gen_eob(s); 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); gen_op_st_T0_A0(ot + s->mem_index);
if (level) { if (level) {
/* XXX: must save state */ /* 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(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_mov_reg_T1(ot, R_EBP);
gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); 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); gen_op_st_T0_A0(ot + s->mem_index);
if (level) { if (level) {
/* XXX: must save state */ /* 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(level),
tcg_const_i32(s->dflag)); tcg_const_i32(s->dflag),
cpu_T[1]);
} }
gen_op_mov_reg_T1(ot, R_EBP); gen_op_mov_reg_T1(ot, R_EBP);
gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); 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 { } else {
/* generic MMX or SSE operation */ /* generic MMX or SSE operation */
switch(b) { 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 0x70: /* pshufx insn */
case 0xc6: /* pshufx insn */ case 0xc6: /* pshufx insn */
case 0xc2: /* compare insns */ 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_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1); tcg_gen_helper_0_2(sse_op2, cpu_ptr0, cpu_ptr1);
break; 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: default:
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_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 */ /* lock generation */
if (prefixes & PREFIX_LOCK) if (prefixes & PREFIX_LOCK)
gen_op_lock(); tcg_gen_helper_0_0(helper_lock);
/* now check op code */ /* now check op code */
reswitch: reswitch:
@ -3783,9 +3773,17 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base); 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 { } 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); gen_eob(s);
break; break;
@ -3804,7 +3802,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base); 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 { } else {
gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
gen_op_movl_T0_T1(); 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); gen_op_mov_TN_reg(ot, 0, reg);
/* for xchg, lock is implicit */ /* for xchg, lock is implicit */
if (!(prefixes & PREFIX_LOCK)) 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_ld_T1_A0(ot + s->mem_index);
gen_op_st_T0_A0(ot + s->mem_index); gen_op_st_T0_A0(ot + s->mem_index);
if (!(prefixes & PREFIX_LOCK)) if (!(prefixes & PREFIX_LOCK))
gen_op_unlock(); tcg_gen_helper_0_0(helper_unlock);
gen_op_mov_reg_T1(ot, reg); gen_op_mov_reg_T1(ot, reg);
} }
break; break;
@ -5117,13 +5119,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE; ot = OT_BYTE;
else else
ot = dflag ? OT_LONG : OT_WORD; 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_mov_TN_reg(OT_WORD, 0, R_EDX);
gen_op_andl_T0_ffff(); gen_op_andl_T0_ffff();
if (gen_svm_check_io(s, pc_start, gen_check_io(s, ot, pc_start - s->cs_base,
SVM_IOIO_TYPE_MASK | (1 << (4+ot)) | SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4);
svm_is_rep(prefixes) | 4 | (1 << (7+s->aflag))))
break;
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else { } else {
@ -5136,13 +5135,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = OT_BYTE; ot = OT_BYTE;
else else
ot = dflag ? OT_LONG : OT_WORD; 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_mov_TN_reg(OT_WORD, 0, R_EDX);
gen_op_andl_T0_ffff(); gen_op_andl_T0_ffff();
if (gen_svm_check_io(s, pc_start, gen_check_io(s, ot, pc_start - s->cs_base,
(1 << (4+ot)) | svm_is_rep(prefixes) | svm_is_rep(prefixes) | 4);
4 | (1 << (7+s->aflag))))
break;
if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
} else { } else {
@ -5161,12 +5157,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
val = ldub_code(s->pc++); val = ldub_code(s->pc++);
gen_op_movl_T0_im(val); gen_op_movl_T0_im(val);
gen_check_io(s, ot, 0, pc_start - s->cs_base); gen_check_io(s, ot, pc_start - s->cs_base,
if (gen_svm_check_io(s, pc_start, SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]);
(1 << (4+ot)))) tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2);
break;
gen_op_in[ot]();
gen_op_mov_reg_T1(ot, R_EAX); gen_op_mov_reg_T1(ot, R_EAX);
break; break;
case 0xe6: case 0xe6:
@ -5177,12 +5171,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
val = ldub_code(s->pc++); val = ldub_code(s->pc++);
gen_op_movl_T0_im(val); gen_op_movl_T0_im(val);
gen_check_io(s, ot, 0, pc_start - s->cs_base); gen_check_io(s, ot, pc_start - s->cs_base,
if (gen_svm_check_io(s, pc_start, svm_is_rep(prefixes) | svm_is_rep(prefixes));
(1 << (4+ot))))
break;
gen_op_mov_TN_reg(ot, 1, R_EAX); 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; break;
case 0xec: case 0xec:
case 0xed: case 0xed:
@ -5192,12 +5188,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
gen_op_andl_T0_ffff(); gen_op_andl_T0_ffff();
gen_check_io(s, ot, 0, pc_start - s->cs_base); gen_check_io(s, ot, pc_start - s->cs_base,
if (gen_svm_check_io(s, pc_start, SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]);
(1 << (4+ot)))) tcg_gen_helper_1_1(helper_in_func[ot], cpu_T[1], cpu_tmp2);
break;
gen_op_in[ot]();
gen_op_mov_reg_T1(ot, R_EAX); gen_op_mov_reg_T1(ot, R_EAX);
break; break;
case 0xee: case 0xee:
@ -5208,12 +5202,14 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
ot = dflag ? OT_LONG : OT_WORD; ot = dflag ? OT_LONG : OT_WORD;
gen_op_mov_TN_reg(OT_WORD, 0, R_EDX); gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
gen_op_andl_T0_ffff(); gen_op_andl_T0_ffff();
gen_check_io(s, ot, 0, pc_start - s->cs_base); gen_check_io(s, ot, pc_start - s->cs_base,
if (gen_svm_check_io(s, pc_start, svm_is_rep(prefixes));
svm_is_rep(prefixes) | (1 << (4+ot))))
break;
gen_op_mov_TN_reg(ot, 1, R_EAX); 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; break;
/************************/ /************************/
@ -5246,7 +5242,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base); 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 { } else {
gen_stack_A0(s); gen_stack_A0(s);
/* pop offset */ /* pop offset */
@ -5273,20 +5271,22 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
break; break;
if (!s->pe) { if (!s->pe) {
/* real mode */ /* 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; s->cc_op = CC_OP_EFLAGS;
} else if (s->vm86) { } else if (s->vm86) {
if (s->iopl != 3) { if (s->iopl != 3) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else { } 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; s->cc_op = CC_OP_EFLAGS;
} }
} else { } else {
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_jmp_im(pc_start - s->cs_base); 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; s->cc_op = CC_OP_EFLAGS;
} }
gen_eob(s); 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_op_mov_TN_reg(ot, 0, reg);
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr); gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_jmp_im(pc_start - s->cs_base); gen_jmp_im(pc_start - s->cs_base);
tcg_gen_trunc_tl_i32(cpu_tmp2, cpu_T[0]);
if (ot == OT_WORD) if (ot == OT_WORD)
tcg_gen_helper_0_0(helper_boundw); tcg_gen_helper_0_2(helper_boundw, cpu_A0, cpu_tmp2);
else else
tcg_gen_helper_0_0(helper_boundl); tcg_gen_helper_0_2(helper_boundl, cpu_A0, cpu_tmp2);
break; break;
case 0x1c8 ... 0x1cf: /* bswap reg */ case 0x1c8 ... 0x1cf: /* bswap reg */
reg = (b & 7) | REX_B(s); 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)) if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0))
break; break;
gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); 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_jmp_im(s->pc - s->cs_base);
gen_eob(s); gen_eob(s);
} }
@ -6223,6 +6224,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} else { } else {
gen_op_mov_TN_reg(ot, 0, rm); gen_op_mov_TN_reg(ot, 0, rm);
} }
gen_op_mov_TN_reg(ot, 1, reg);
if (s->cc_op != CC_OP_DYNAMIC) if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op); gen_op_set_cc_op(s->cc_op);
gen_op_arpl(); gen_op_arpl();
@ -6299,14 +6301,15 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
if (b & 2) { if (b & 2) {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0 + reg); gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0 + reg);
gen_op_mov_TN_reg(ot, 0, rm); 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_jmp_im(s->pc - s->cs_base);
gen_eob(s); gen_eob(s);
} else { } else {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0 + reg); gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0 + reg);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
if (reg == 8) if (reg == 8)
gen_op_movtl_T0_cr8(); tcg_gen_helper_1_0(helper_movtl_T0_cr8, cpu_T[0]);
else else
#endif #endif
gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg])); 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) { if (b & 2) {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg); gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg);
gen_op_mov_TN_reg(ot, 0, rm); 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_jmp_im(s->pc - s->cs_base);
gen_eob(s); gen_eob(s);
} else { } 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); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else { } else {
gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0); 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 */ /* abort block because static cpu state changed */
gen_jmp_im(s->pc - s->cs_base); gen_jmp_im(s->pc - s->cs_base);
gen_eob(s); gen_eob(s);
@ -6485,11 +6489,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
} }
/* lock generation */ /* lock generation */
if (s->prefix & PREFIX_LOCK) if (s->prefix & PREFIX_LOCK)
gen_op_unlock(); tcg_gen_helper_0_0(helper_unlock);
return s->pc; return s->pc;
illegal_op: illegal_op:
if (s->prefix & PREFIX_LOCK) if (s->prefix & PREFIX_LOCK)
gen_op_unlock(); tcg_gen_helper_0_0(helper_unlock);
/* XXX: ensure that no lock was generated */ /* XXX: ensure that no lock was generated */
gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
return s->pc; 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_T[1] = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG2, "T1");
cpu_A0 = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG3, "A0"); cpu_A0 = tcg_global_reg_new(TCG_TYPE_TL, TCG_AREG3, "A0");
#endif #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"); cpu_tmp1 = tcg_global_reg2_new_hack(TCG_TYPE_I64, TCG_AREG1, TCG_AREG2, "tmp1");
#endif #endif
} }
@ -6957,10 +6962,11 @@ static inline int gen_intermediate_code_internal(CPUState *env,
#endif #endif
cpu_tmp0 = tcg_temp_new(TCG_TYPE_TL); 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); cpu_tmp1 = tcg_temp_new(TCG_TYPE_I64);
#endif #endif
cpu_tmp2 = tcg_temp_new(TCG_TYPE_I32); 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_ptr0 = tcg_temp_new(TCG_TYPE_PTR);
cpu_ptr1 = tcg_temp_new(TCG_TYPE_PTR); cpu_ptr1 = tcg_temp_new(TCG_TYPE_PTR);