# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Node ID a80ad3a0f2ce37c3907820f0f8282dcd5ace76b5 # Parent 2bde9ab4140b0b21ac40533dd319af66d4003841 introduce vcpu_get_domain_bundle() and replace __get_domain_handle call in priv_handle_op with it. priv_handle_op() uses __get_domain_handle to domain's bundle. it directly access guest ip with guest virtual address which may results in data tlb miss which cause some trobles. This patch also cleans up vcpu_translate(). PATCHNAME: vcpu_get_domain_bundle Signed-off-by: Isaku Yamahata diff -r 2bde9ab4140b -r a80ad3a0f2ce xen/arch/ia64/xen/privop.c --- a/xen/arch/ia64/xen/privop.c Tue May 30 11:35:19 2006 +0900 +++ b/xen/arch/ia64/xen/privop.c Tue May 30 11:38:47 2006 +0900 @@ -615,16 +615,11 @@ priv_handle_op(VCPU *vcpu, REGS *regs, i int x6; // make a local copy of the bundle containing the privop -#if 1 - bundle = __get_domain_bundle(iip); - if (!bundle.i64[0] && !bundle.i64[1]) -#else - if (__copy_from_user(&bundle,iip,sizeof(bundle))) -#endif - { -//printf("*** priv_handle_op: privop bundle at 0x%lx not mapped, retrying\n",iip); - return vcpu_force_data_miss(vcpu,regs->cr_iip); - } + if (!vcpu_get_domain_bundle(vcpu, regs, iip, &bundle)) { + //return vcpu_force_data_miss(vcpu, regs->cr_iip); + return vcpu_force_inst_miss(vcpu, regs->cr_iip); + } + #if 0 if (iip==0xa000000100001820) { static int firstpagefault = 1; diff -r 2bde9ab4140b -r a80ad3a0f2ce xen/arch/ia64/xen/vcpu.c --- a/xen/arch/ia64/xen/vcpu.c Tue May 30 11:35:19 2006 +0900 +++ b/xen/arch/ia64/xen/vcpu.c Tue May 30 11:38:47 2006 +0900 @@ -17,6 +17,7 @@ #include #include #include +#include #include /* FIXME: where these declarations should be there ? */ @@ -28,6 +29,7 @@ extern void setfpreg (unsigned long regn extern void panic_domain(struct pt_regs *, const char *, ...); extern unsigned long translate_domain_mpaddr(unsigned long); +extern IA64_BUNDLE __get_domain_bundle(UINT64); typedef union { struct ia64_psr ia64_psr; @@ -1183,14 +1185,25 @@ Privileged operation emulation routines Privileged operation emulation routines **************************************************************************/ +static void +vcpu_force_tlb_miss(VCPU* vcpu, UINT64 ifa) +{ + PSCB(vcpu, ifa) = ifa; + PSCB(vcpu, itir) = vcpu_get_itir_on_fault(vcpu, ifa); + vcpu_thash(current, ifa, &PSCB(current, iha)); +} + +IA64FAULT vcpu_force_inst_miss(VCPU *vcpu, UINT64 ifa) +{ + vcpu_force_tlb_miss(vcpu, ifa); + return (vcpu_get_rr_ve(vcpu, ifa)? IA64_INST_TLB_VECTOR: IA64_ALT_INST_TLB_VECTOR); +} + IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa) { - PSCB(vcpu,ifa) = ifa; - PSCB(vcpu,itir) = vcpu_get_itir_on_fault(vcpu,ifa); - vcpu_thash(current, ifa, &PSCB(current,iha)); - return (vcpu_get_rr_ve(vcpu,ifa) ? IA64_DATA_TLB_VECTOR : IA64_ALT_DATA_TLB_VECTOR); -} - + vcpu_force_tlb_miss(vcpu, ifa); + return (vcpu_get_rr_ve(vcpu, ifa)? IA64_DATA_TLB_VECTOR: IA64_ALT_DATA_TLB_VECTOR); +} IA64FAULT vcpu_rfi(VCPU *vcpu) { @@ -1302,12 +1315,117 @@ static inline int vcpu_match_tr_entry(TR return trp->pte.p && vcpu_match_tr_entry_no_p(trp, ifa, rid); } +static TR_ENTRY* +vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data) +{ + unsigned int* regions; + TR_ENTRY *trp; + int tr_max; + int i; + + if (is_data) { + // data + regions = &vcpu->arch.dtr_regions; + trp = vcpu->arch.dtrs; + tr_max = sizeof(vcpu->arch.dtrs)/sizeof(vcpu->arch.dtrs[0]); + } else { + // instruction + regions = &vcpu->arch.itr_regions; + trp = vcpu->arch.itrs; + tr_max = sizeof(vcpu->arch.itrs)/sizeof(vcpu->arch.itrs[0]); + } + + if (!vcpu_quick_region_check(*regions, va)) { + return NULL; + } + for (i = 0; i < tr_max; i++, trp++) { + if (vcpu_match_tr_entry(trp, va, rid)) { + return trp; + } + } + return NULL; +} + +// return value +// 0: failure +// 1: success +int +vcpu_get_domain_bundle(VCPU* vcpu, REGS* regs, UINT64 gip, IA64_BUNDLE* bundle) +{ + UINT64 gpip;// guest pseudo phyiscal ip + +#if 0 + // Currently xen doesn't track psr.it bits. + // it assumes always psr.it = 1. + if (!(VCPU(vcpu, vpsr) & IA64_PSR_IT)) { + gpip = gip; + } else +#endif + { + unsigned long region = REGION_NUMBER(gip); + unsigned long rr = PSCB(vcpu, rrs)[region]; + unsigned long rid = rr & RR_RID_MASK; + BOOLEAN swap_rr0; + TR_ENTRY* trp; + + // vcpu->arch.{i, d}tlb are volatile, + // copy its value to the variable, tr, before use. + TR_ENTRY tr; + + trp = vcpu_tr_lookup(vcpu, gip, rid, 0); + if (trp != NULL) { + tr = *trp; + goto found; + } + // When it failed to get a bundle, itlb miss is reflected. + // Last itc.i value is cached to PSCBX(vcpu, itlb). + tr = PSCBX(vcpu, itlb); + if (vcpu_match_tr_entry(&tr, gip, rid)) { + //DPRINTK("%s gip 0x%lx gpip 0x%lx\n", __func__, gip, gpip); + goto found; + } + trp = vcpu_tr_lookup(vcpu, gip, rid, 1); + if (trp != NULL) { + 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_one_rr(0x0, PSCB(vcpu, rrs[0])); + } + *bundle = __get_domain_bundle(gip); + if (swap_rr0) { + set_metaphysical_rr0(); + } + if (bundle->i64[0] == 0 && bundle->i64[1] == 0) { + DPRINTK("%s gip 0x%lx\n", __func__, gip); + return 0; + } + return 1; + + found: + gpip = ((tr.pte.ppn >> (tr.ps - 12)) << tr.ps) | + (gip & ((1 << tr.ps) - 1)); + } + + *bundle = *((IA64_BUNDLE*)__va(__gpa_to_mpa(vcpu->domain, gpip))); + return 1; +} + IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir, UINT64 *iha) { unsigned long region = address >> 61; unsigned long pta, rid, rr; union pte_flags pte; - int i; TR_ENTRY *trp; if (PSCB(vcpu,metaphysical_mode) && !(!is_data && region)) { @@ -1348,28 +1466,22 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UIN rr = PSCB(vcpu,rrs)[region]; rid = rr & RR_RID_MASK; if (is_data) { - if (vcpu_quick_region_check(vcpu->arch.dtr_regions,address)) { - for (trp = vcpu->arch.dtrs, i = NDTRS; i; i--, trp++) { - if (vcpu_match_tr_entry(trp,address,rid)) { - *pteval = trp->pte.val; - *itir = trp->itir; - tr_translate_count++; - return IA64_NO_FAULT; - } - } + trp = vcpu_tr_lookup(vcpu, address, rid, 1); + if (trp != NULL) { + *pteval = trp->pte.val; + *itir = trp->itir; + tr_translate_count++; + return IA64_NO_FAULT; } } // FIXME?: check itr's for data accesses too, else bad things happen? /* else */ { - if (vcpu_quick_region_check(vcpu->arch.itr_regions,address)) { - for (trp = vcpu->arch.itrs, i = NITRS; i; i--, trp++) { - if (vcpu_match_tr_entry(trp,address,rid)) { - *pteval = trp->pte.val; - *itir = trp->itir; - tr_translate_count++; - return IA64_NO_FAULT; - } - } + trp = vcpu_tr_lookup(vcpu, address, rid, 0); + if (trp != NULL) { + *pteval = trp->pte.val; + *itir = trp->itir; + tr_translate_count++; + return IA64_NO_FAULT; } } diff -r 2bde9ab4140b -r a80ad3a0f2ce xen/include/asm-ia64/vcpu.h --- a/xen/include/asm-ia64/vcpu.h Tue May 30 11:35:19 2006 +0900 +++ b/xen/include/asm-ia64/vcpu.h Tue May 30 11:38:47 2006 +0900 @@ -151,9 +151,12 @@ extern IA64FAULT vcpu_ptc_ga(VCPU *vcpu, extern IA64FAULT vcpu_ptc_ga(VCPU *vcpu, UINT64 vadr, UINT64 addr_range); extern IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr, UINT64 addr_range); extern IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr, UINT64 addr_range); +union U_IA64_BUNDLE; +extern int vcpu_get_domain_bundle(VCPU *vcpu, REGS *regs, UINT64 gip, union U_IA64_BUNDLE *bundle); extern IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir, UINT64 *iha); extern IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr); +extern IA64FAULT vcpu_force_inst_miss(VCPU *vcpu, UINT64 ifa); extern IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa); extern IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr); /* misc */