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

@ -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
}
/* XXX: do more */
void helper_movl_drN_T0(int reg)
void helper_lmsw(target_ulong t0)
{
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)
@ -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();
}