IA64: fix fp fault/trap handler. This patch is a part of fixes to bug reported as http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1392 When fpswa handler fails to get a bundle in guest, fp fault/trap should be injected into the guest and let a guest to handle it. When the fpswa library return a error, there is no way to pass the value to the guest. In that case, revert the change and inject the fp fault/trap. Signed-off-by: Isaku Yamahata diff --git a/xen/arch/ia64/vmx/vmx_fault.c b/xen/arch/ia64/vmx/vmx_fault.c --- a/xen/arch/ia64/vmx/vmx_fault.c +++ b/xen/arch/ia64/vmx/vmx_fault.c @@ -122,8 +122,7 @@ void vmx_reflect_interruption(u64 ifa, u if (!status) { vcpu_increment_iip(vcpu); return; - } else if (IA64_RETRY == status) - return; + } break; case 33: // IA64_FP_TRAP_VECTOR @@ -133,10 +132,6 @@ void vmx_reflect_interruption(u64 ifa, u status = handle_fpu_swa(0, regs, isr); if (!status) return; - else if (IA64_RETRY == status) { - vcpu_decrement_iip(vcpu); - return; - } break; case 29: // IA64_DEBUG_VECTOR diff --git a/xen/arch/ia64/xen/faults.c b/xen/arch/ia64/xen/faults.c --- a/xen/arch/ia64/xen/faults.c +++ b/xen/arch/ia64/xen/faults.c @@ -314,11 +314,15 @@ unsigned long unsigned long handle_fpu_swa(int fp_fault, struct pt_regs *regs, unsigned long isr) { - struct vcpu *v = current; IA64_BUNDLE bundle; unsigned long fault_ip; fpswa_ret_t ret; unsigned long rc; + + unsigned long ipsr_save; + unsigned long fpsr_save; + unsigned long pr_save; + struct ia64_fpreg fp_save[6]; fault_ip = regs->cr_iip; /* @@ -344,11 +348,22 @@ handle_fpu_swa(int fp_fault, struct pt_r return IA64_RETRY; } + /* If fpswa returns error, fp falut/trap is reflected and + a guest will call fpswa itself. So we have to revert the effect + to avoid calling fpswa twice. */ + ipsr_save = regs->cr_ipsr; + fpsr_save = regs->ar_fpsr; + pr_save = regs->pr; + memcpy(fp_save, ®s->f6, sizeof(fp_save)); + ret = fp_emulate(fp_fault, &bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, ®s->cr_ifs, regs); if (ret.status) { - PSCBX(v, fpswa_ret) = ret; + regs->cr_ipsr = ipsr_save; + regs->ar_fpsr = fpsr_save; + regs->pr = pr_save; + memcpy(®s->f6, fp_save, sizeof(fp_save)); printk("%s(%s): fp_emulate() returned %ld\n", __FUNCTION__, fp_fault ? "fault" : "trap", ret.status); } @@ -688,9 +703,6 @@ ia64_handle_reflection(unsigned long ifa vcpu_increment_iip(v); return; } - // fetch code fail - if (IA64_RETRY == status) - return; printk("ia64_handle_reflection: handling FP fault\n"); vector = IA64_FP_FAULT_VECTOR; break; @@ -698,11 +710,6 @@ ia64_handle_reflection(unsigned long ifa status = handle_fpu_swa(0, regs, isr); if (!status) return; - // fetch code fail - if (IA64_RETRY == status) { - vcpu_decrement_iip(v); - return; - } printk("ia64_handle_reflection: handling FP trap\n"); vector = IA64_FP_TRAP_VECTOR; break; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -288,7 +288,6 @@ struct arch_vcpu { char irq_new_condition; // vpsr.i/vtpr change, check for pending VHPI char hypercall_continuation; - fpswa_ret_t fpswa_ret; /* save return values of FPSWA emulation */ struct timer hlt_timer; struct arch_vmx_struct arch_vmx; /* Virtual Machine Extensions */