From: Chris Lalancette <clalance@redhat.com> Date: Fri, 13 Mar 2009 09:55:10 +0100 Subject: [xen] improve handle_fpu_swa Message-id: 49BA1F6E.1070600@redhat.com O-Subject: [RHEL5.4 PATCH 1/3]: Improve handle_fpu_swa Bugzilla: 477098 RH-Acked-by: Don Dutile <ddutile@redhat.com> IA64: improve handle_fpu_swa() It tries to get a bundle in guest. Make it more robust using vmx_get_domain_bundle() instead of __get_domain_bundle(). xen-unstable c/s 18980 Fixes BZ 477098 diff --git a/arch/ia64/xen/faults.c b/arch/ia64/xen/faults.c index a127c9f..2737c3a 100644 --- a/arch/ia64/xen/faults.c +++ b/arch/ia64/xen/faults.c @@ -344,6 +344,7 @@ handle_fpu_swa(int fp_fault, struct pt_regs *regs, unsigned long isr) IA64_BUNDLE bundle; unsigned long fault_ip; fpswa_ret_t ret; + unsigned long rc; fault_ip = regs->cr_iip; /* @@ -355,15 +356,18 @@ handle_fpu_swa(int fp_fault, struct pt_regs *regs, unsigned long isr) fault_ip -= 16; if (VMX_DOMAIN(current)) { - if (IA64_RETRY == __vmx_get_domain_bundle(fault_ip, &bundle)) - return IA64_RETRY; - } else - bundle = __get_domain_bundle(fault_ip); - - if (!bundle.i64[0] && !bundle.i64[1]) { - printk("%s: floating-point bundle at 0x%lx not mapped\n", - __FUNCTION__, fault_ip); - return -1; + rc = __vmx_get_domain_bundle(fault_ip, &bundle); + } else { + rc = 0; + if (vcpu_get_domain_bundle(current, regs, fault_ip, + &bundle) == 0) + rc = IA64_RETRY; + } + if (rc == IA64_RETRY) { + gdprintk(XENLOG_DEBUG, + "%s(%s): floating-point bundle at 0x%lx not mapped\n", + __FUNCTION__, fp_fault ? "fault" : "trap", fault_ip); + return IA64_RETRY; } ret = fp_emulate(fp_fault, &bundle, ®s->cr_ipsr, ®s->ar_fpsr, @@ -698,8 +702,10 @@ ia64_handle_reflection(unsigned long ifa, struct pt_regs *regs, if (!status) return; // fetch code fail - if (IA64_RETRY == status) + 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/arch/ia64/xen/vcpu.c b/arch/ia64/xen/vcpu.c index 4394bc9..b7fdc2d 100644 --- a/arch/ia64/xen/vcpu.c +++ b/arch/ia64/xen/vcpu.c @@ -1512,6 +1512,26 @@ vcpu_get_domain_bundle(VCPU * vcpu, REGS * regs, u64 gip, // copy its value to the variable, tr, before use. TR_ENTRY tr; + // fast path: + // try to access gip with guest virtual address directly. + // This may cause tlb miss. see vcpu_translate(). Be careful! + swap_rr0 = (!region && PSCB(vcpu, metaphysical_mode)); + if (swap_rr0) { + set_virtual_rr0(); + } + *bundle = __get_domain_bundle(gip); + if (swap_rr0) { + set_metaphysical_rr0(); + } + + if (!bundle->i64[0] && !bundle->i64[1]) { + dprintk(XENLOG_INFO, "%s gip 0x%lx\n", __func__, gip); + } else { + // Okay, mDTC successed + return 1; + } + // mDTC failed, so try vTLB. + trp = vcpu_tr_lookup(vcpu, gip, rid, 0); if (trp != NULL) { tr = *trp; @@ -1531,28 +1551,13 @@ vcpu_get_domain_bundle(VCPU * vcpu, REGS * regs, u64 gip, tr = *trp; goto found; } -#if 0 tr = PSCBX(vcpu, dtlb); if (vcpu_match_tr_entry(&tr, gip, rid)) { goto found; } -#endif - // try to access gip with guest virtual address - // This may cause tlb miss. see vcpu_translate(). Be careful! - swap_rr0 = (!region && PSCB(vcpu, metaphysical_mode)); - if (swap_rr0) { - set_virtual_rr0(); - } - *bundle = __get_domain_bundle(gip); - if (swap_rr0) { - set_metaphysical_rr0(); - } - if (bundle->i64[0] == 0 && bundle->i64[1] == 0) { - dprintk(XENLOG_INFO, "%s gip 0x%lx\n", __func__, gip); - return 0; - } - return 1; + // mDTC and vTLB failed. so reflect tlb miss into the guest. + return 0; found: gpip = ((tr.pte.ppn >> (tr.ps - 12)) << tr.ps) |