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(). Signed-off-by: Isaku Yamahata 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 @@ -318,6 +318,7 @@ handle_fpu_swa(int fp_fault, struct pt_r IA64_BUNDLE bundle; unsigned long fault_ip; fpswa_ret_t ret; + unsigned long rc; fault_ip = regs->cr_iip; /* @@ -329,15 +330,18 @@ handle_fpu_swa(int fp_fault, struct pt_r 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, @@ -689,8 +693,10 @@ ia64_handle_reflection(unsigned long ifa 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/xen/arch/ia64/xen/vcpu.c b/xen/arch/ia64/xen/vcpu.c --- a/xen/arch/ia64/xen/vcpu.c +++ b/xen/arch/ia64/xen/vcpu.c @@ -1355,6 +1355,26 @@ vcpu_get_domain_bundle(VCPU * vcpu, REGS // 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; @@ -1374,28 +1394,13 @@ vcpu_get_domain_bundle(VCPU * vcpu, REGS 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) |