# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1198814687 -32400 # Node ID 3fa9bfb63a947099e0202c25437eb785507d6025 # Parent b02e17ab2adf8b5b7199fd24a7408ce6e5a921f3 allocate privregs from domain heap for VTi domain. - pin privregs down with both dtr/itr so that privregs can be allocated from the domain heap - introduce vmx_vpd_pin()/vmx_vpd_unpin(). the vpd area is pinned down when current. But two functions, update_vhpi() and alloc_vpd() are exceptions. We have to pin down the area before PAL call. - minor twist context switch not to use unpinned vpd area. vmx_load_state() needs the vpd area pinned down. call it after vmx_load_all_rr() - fix vmx_load_all_rr() vmx_switch_rr7() sets psr.ic = 0 so that clearing psr.ic before calling vmx_switch_rr7() doesn't make sense. - improve vmx_switch_rr7() it sets psr.ic = 0 after switching to physical mode. But it can be done at the switching time. PATCHNAME: vti_privregs_from_domheap Signed-off-by: Isaku Yamahata diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/arch/ia64/vmx/vlsapic.c --- a/xen/arch/ia64/vmx/vlsapic.c Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/arch/ia64/vmx/vlsapic.c Fri Dec 28 13:04:47 2007 +0900 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -91,9 +92,12 @@ static void update_vhpi(VCPU *vcpu, int VCPU(vcpu,vhpi) = vhpi; // TODO: Add support for XENO - if (VCPU(vcpu,vac).a_int) + if (VCPU(vcpu,vac).a_int) { + vmx_vpd_pin(vcpu); ia64_call_vsa(PAL_VPS_SET_PENDING_INTERRUPT, (uint64_t)vcpu->arch.privregs, 0, 0, 0, 0, 0, 0); + vmx_vpd_unpin(vcpu); + } } diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/arch/ia64/vmx/vmx_entry.S --- a/xen/arch/ia64/vmx/vmx_entry.S Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/arch/ia64/vmx/vmx_entry.S Fri Dec 28 13:04:47 2007 +0900 @@ -616,14 +616,14 @@ END(ia64_leave_hypercall) #define PSR_BITS_TO_CLEAR \ (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | \ IA64_PSR_RT | IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | \ - IA64_PSR_ED | IA64_PSR_DFL | IA64_PSR_DFH) + IA64_PSR_ED | IA64_PSR_DFL | IA64_PSR_DFH | IA64_PSR_IC) #define PSR_BITS_TO_SET IA64_PSR_BN -//extern void vmx_switch_rr7(unsigned long rid, void *guest_vhpt, void * pal_vaddr ); +//extern void vmx_switch_rr7(unsigned long rid, void *guest_vhpt, void * pal_vaddr, void * shared_arch_info ); GLOBAL_ENTRY(vmx_switch_rr7) // not sure this unwind statement is correct... .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1) - alloc loc1 = ar.pfs, 3, 7, 0, 0 + alloc loc1 = ar.pfs, 4, 8, 0, 0 1:{ mov r28 = in0 // copy procedure index mov r8 = ip // save ip to compute branch @@ -636,7 +636,12 @@ 1:{ tpa r3 = r8 // get physical address of ip dep loc5 = 0,in1,60,4 // get physical address of guest_vhpt dep loc6 = 0,in2,60,4 // get physical address of pal code - ;; + dep loc7 = 0,in3,60,4 // get physical address of privregs + ;; + dep loc6 = 0,loc6,0,IA64_GRANULE_SHIFT + // mask granule shift + dep loc7 = 0,loc7,0,IA64_GRANULE_SHIFT + // mask granule shift mov loc4 = psr // save psr ;; mov loc3 = ar.rsc // save RSE configuration @@ -654,11 +659,9 @@ 1: dep r16=-1,r0,61,3 ;; mov rr[r16]=in0 + ;; srlz.d ;; - rsm 0x6000 - ;; - srlz.d // re-pin mappings for kernel text and data mov r18=KERNEL_TR_PAGE_SHIFT<<2 @@ -672,6 +675,7 @@ 1: mov r16=IA64_TR_KERNEL movl r25 = PAGE_KERNEL // r2=KERNEL_TR_PAGE_SHIFT truncated physicall address of ip + // = ia64_tpa(ip) & (KERNEL_TR_PAGE_SIZE - 1) dep r2=0,r3,0,KERNEL_TR_PAGE_SHIFT ;; or r24=r2,r25 @@ -730,7 +734,9 @@ 1: // re-pin mappings for guest_vhpt // unless overlaps with IA64_TR_XEN_HEAP_REGS or IA64_TR_CURRENT_STACK dep r18=0,loc5,0,KERNEL_TR_PAGE_SHIFT + // r21 = (current physical addr) & (IA64_GRANULE_SIZE - 1) dep r21=0,r21,0,IA64_GRANULE_SHIFT + // r17 = (guest_vhpt physical addr) & (IA64_GRANULE_SIZE - 1) dep r17=0,loc5,0,IA64_GRANULE_SHIFT ;; cmp.eq p6,p0=r18,r2 // check overlap with xen heap @@ -764,6 +770,43 @@ 1: itr.i itr[r24]=loc6 // wire in new mapping... ;; + // r16, r19, r20 are used by + // ia64_switch_mode_phys()/ia64_switch_mode_virt() + // re-pin mappings for privregs + // r2 = ia64_tpa(ip) & (KERNEL_TR_PAGE_SIZE - 1) + // r21 = (current physical addr) & (IA64_GRANULE_SIZE - 1) + // r17 = (guest_vhpt physical addr) & (IA64_GRANULE_SIZE - 1) + + // r24 = (privregs physical addr) & (KERNEL_TR_PAGE_SIZE - 1) + // loc6 = (((pal phys addr) & (IA64_GRANULE_SIZE - 1) << 2)) | PAGE_KERNEL + // loc7 = (privregs physical addr) & (IA64_GRANULE_SIZE - 1) + dep r24 = 0,loc7,0,KERNEL_TR_PAGE_SHIFT + ;; + cmp.ne p6,p0=r24,r2 // check overlap with xen heap + ;; +(p6) cmp.ne.unc p7,p0=r21,loc7 // check overlap with current stack + ;; +(p7) cmp.ne.unc p8,p0=r17,loc7 // check overlap with guest_vhpt + ;; + // loc7 = (((privregs phys) & (IA64_GRANULE_SIZE - 1)) << 2) | PAGE_KERNEL + or loc7 = r25,loc7 // construct PA | page properties + ;; + cmp.ne p9,p0=loc6,loc7 + mov r22=IA64_TR_VPD + mov r24=IA64_TR_MAPPED_REGS + mov r23 = IA64_GRANULE_SHIFT <<2 + ;; +(p9) ptr.i in3,r23 +(p8) ptr.d in3,r23 + mov cr.itir=r23 + mov cr.ifa=in3 + ;; +(p9) itr.i itr[r22]=loc7 // wire in new mapping... + ;; +(p8) itr.d dtr[r24]=loc7 // wire in new mapping... + ;; +.privregs_overlaps: + // done, switch back to virtual and return mov r16=loc4 // r16= original psr br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/arch/ia64/vmx/vmx_init.c --- a/xen/arch/ia64/vmx/vmx_init.c Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/arch/ia64/vmx/vmx_init.c Fri Dec 28 13:04:47 2007 +0900 @@ -51,6 +51,7 @@ #include #include #include +#include #include "entry.h" /* Global flag to identify whether Intel vmx feature is on */ @@ -150,20 +151,21 @@ typedef union { }; } cpuid3_t; -/* Allocate vpd from xenheap */ +/* Allocate vpd from domheap */ static vpd_t *alloc_vpd(void) { int i; cpuid3_t cpuid3; + struct page_info *page; vpd_t *vpd; mapped_regs_t *mregs; - vpd = alloc_xenheap_pages(get_order(VPD_SIZE)); - if (!vpd) { + page = alloc_domheap_pages(NULL, get_order(VPD_SIZE), 0); + if (page == NULL) { printk("VPD allocation failed.\n"); return NULL; } - vpd = (vpd_t *)virt_to_xenva(vpd); + vpd = page_to_virt(page); printk(XENLOG_DEBUG "vpd base: 0x%p, vpd size:%ld\n", vpd, sizeof(vpd_t)); @@ -191,12 +193,79 @@ static vpd_t *alloc_vpd(void) return vpd; } -/* Free vpd to xenheap */ +/* Free vpd to domheap */ static void free_vpd(struct vcpu *v) { if ( v->arch.privregs ) - free_xenheap_pages(v->arch.privregs, get_order(VPD_SIZE)); + free_domheap_pages(virt_to_page(v->arch.privregs), + get_order(VPD_SIZE)); +} + +// This is used for PAL_VP_CREATE and PAL_VPS_SET_PENDING_INTERRUPT +// so that we don't have to pin the vpd down with itr[]. +void +__vmx_vpd_pin(struct vcpu* v) +{ + unsigned long privregs = (unsigned long)v->arch.privregs; + u64 psr; + + // check overlapping with xenheap + if ((privregs & + ~(KERNEL_TR_PAGE_SIZE - 1)) == + ((unsigned long)__va(ia64_tpa(current_text_addr())) & + ~(KERNEL_TR_PAGE_SIZE - 1))) + return; + + privregs &= ~(IA64_GRANULE_SIZE - 1); + + // check overlapping with current stack + if (privregs == + ((unsigned long)current & ~(IA64_GRANULE_SIZE - 1))) + return; + + if (!VMX_DOMAIN(current)) { + // check overlapping with vhpt + if (privregs == + (vcpu_vhpt_maddr(current) & ~(IA64_GRANULE_SHIFT - 1))) + return; + } else { + // check overlapping with vhpt + if (privregs == + ((unsigned long)current->arch.vhpt.hash & + ~(IA64_GRANULE_SHIFT - 1))) + return; + + // check overlapping with privregs + if (privregs == + ((unsigned long)current->arch.privregs & + ~(IA64_GRANULE_SHIFT - 1))) + return; + } + + psr = ia64_clear_ic(); + ia64_ptr(0x2 /*D*/, privregs, IA64_GRANULE_SIZE); + ia64_srlz_d(); + ia64_itr(0x2 /*D*/, IA64_TR_MAPPED_REGS, privregs, + pte_val(pfn_pte(__pa(privregs) >> PAGE_SHIFT, PAGE_KERNEL)), + IA64_GRANULE_SHIFT); + ia64_set_psr(psr); + ia64_srlz_d(); +} + +void +__vmx_vpd_unpin(struct vcpu* v) +{ + if (!VMX_DOMAIN(current)) { + int rc; + rc = !set_one_rr(VRN7 << VRN_SHIFT, VCPU(current, rrs[VRN7])); + BUG_ON(rc); + } else { + IA64FAULT fault; + fault = vmx_vcpu_set_rr(current, VRN7 << VRN_SHIFT, + VMX(current, vrr[VRN7])); + BUG_ON(fault != IA64_NO_FAULT); + } } /* @@ -212,7 +281,11 @@ vmx_create_vp(struct vcpu *v) /* ia64_ivt is function pointer, so need this tranlation */ ivt_base = (u64) &vmx_ia64_ivt; printk(XENLOG_DEBUG "ivt_base: 0x%lx\n", ivt_base); + + vmx_vpd_pin(v); ret = ia64_pal_vp_create((u64 *)vpd, (u64 *)ivt_base, 0); + vmx_vpd_unpin(v); + if (ret != PAL_STATUS_SUCCESS){ panic_domain(vcpu_regs(v),"ia64_pal_vp_create failed. \n"); } @@ -224,6 +297,7 @@ vmx_save_state(struct vcpu *v) { u64 status; + BUG_ON(v != current); /* FIXME: about setting of pal_proc_vector... time consuming */ status = ia64_pal_vp_save((u64 *)v->arch.privregs, 0); if (status != PAL_STATUS_SUCCESS){ @@ -250,6 +324,7 @@ vmx_load_state(struct vcpu *v) { u64 status; + BUG_ON(v != current); status = ia64_pal_vp_restore((u64 *)v->arch.privregs, 0); if (status != PAL_STATUS_SUCCESS){ panic_domain(vcpu_regs(v),"Restore vp status failed\n"); @@ -518,6 +593,7 @@ void vmx_do_resume(struct vcpu *v) ioreq_t *p; vmx_load_all_rr(v); + vmx_load_state(v); migrate_timer(&v->arch.arch_vmx.vtm.vtm_timer, v->processor); /* stolen from hvm_do_resume() in arch/x86/hvm/hvm.c */ diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/arch/ia64/vmx/vmx_phy_mode.c --- a/xen/arch/ia64/vmx/vmx_phy_mode.c Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/arch/ia64/vmx/vmx_phy_mode.c Fri Dec 28 13:04:47 2007 +0900 @@ -138,7 +138,6 @@ void void vmx_load_all_rr(VCPU *vcpu) { - unsigned long psr; unsigned long rr0, rr4; switch (vcpu->arch.arch_vmx.mmu_mode) { @@ -158,8 +157,6 @@ vmx_load_all_rr(VCPU *vcpu) panic_domain(NULL, "bad mmu mode value"); } - psr = ia64_clear_ic(); - ia64_set_rr((VRN0 << VRN_SHIFT), rr0); ia64_dv_serialize_data(); ia64_set_rr((VRN4 << VRN_SHIFT), rr4); @@ -175,13 +172,11 @@ vmx_load_all_rr(VCPU *vcpu) ia64_set_rr((VRN6 << VRN_SHIFT), vrrtomrr(vcpu, VMX(vcpu, vrr[VRN6]))); ia64_dv_serialize_data(); vmx_switch_rr7(vrrtomrr(vcpu,VMX(vcpu, vrr[VRN7])), - (void *)vcpu->arch.vhpt.hash, pal_vaddr); + (void *)vcpu->arch.vhpt.hash, pal_vaddr, vcpu->arch.privregs); ia64_set_pta(VMX(vcpu, mpta)); vmx_ia64_set_dcr(vcpu); ia64_srlz_d(); - ia64_set_psr(psr); - ia64_srlz_i(); } void diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/arch/ia64/vmx/vmx_vcpu.c --- a/xen/arch/ia64/vmx/vmx_vcpu.c Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/arch/ia64/vmx/vmx_vcpu.c Fri Dec 28 13:04:47 2007 +0900 @@ -184,8 +184,8 @@ IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, u6 switch((u64)(reg>>VRN_SHIFT)) { case VRN7: if (likely(vcpu == current)) - vmx_switch_rr7(vrrtomrr(vcpu,val), - (void *)vcpu->arch.vhpt.hash, pal_vaddr ); + vmx_switch_rr7(vrrtomrr(vcpu,val), (void *)vcpu->arch.vhpt.hash, + pal_vaddr, vcpu->arch.privregs); break; case VRN4: rrval = vrrtomrr(vcpu,val); diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/arch/ia64/xen/domain.c --- a/xen/arch/ia64/xen/domain.c Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/arch/ia64/xen/domain.c Fri Dec 28 13:04:47 2007 +0900 @@ -241,8 +241,6 @@ void context_switch(struct vcpu *prev, s ia64_setreg(_IA64_REG_CR_DCR, dcr); } } - if (VMX_DOMAIN(next)) - vmx_load_state(next); ia64_disable_vhpt_walker(); lazy_fp_switch(prev, current); @@ -261,6 +259,7 @@ void context_switch(struct vcpu *prev, s if (VMX_DOMAIN(current)) { vmx_load_all_rr(current); + vmx_load_state(current); migrate_timer(¤t->arch.arch_vmx.vtm.vtm_timer, current->processor); } else { diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/include/asm-ia64/vmx_vcpu.h --- a/xen/include/asm-ia64/vmx_vcpu.h Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/include/asm-ia64/vmx_vcpu.h Fri Dec 28 13:04:47 2007 +0900 @@ -114,7 +114,7 @@ extern void memwrite_v(VCPU * vcpu, thas size_t s); extern void memwrite_p(VCPU * vcpu, u64 * src, u64 * dest, size_t s); extern void vcpu_load_kernel_regs(VCPU * vcpu); -extern void vmx_switch_rr7(unsigned long, void *, void *); +extern void vmx_switch_rr7(unsigned long, void *, void *, void *); extern void dtlb_fault(VCPU * vcpu, u64 vadr); extern void nested_dtlb(VCPU * vcpu); diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/include/asm-ia64/vmx_vpd.h --- a/xen/include/asm-ia64/vmx_vpd.h Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/include/asm-ia64/vmx_vpd.h Fri Dec 28 13:04:47 2007 +0900 @@ -70,6 +70,24 @@ struct arch_vmx_struct { #define ARCH_VMX_DOMAIN 0 /* Need it to indicate VTi domain */ +/* pin/unpin vpd area for PAL call with DTR[] */ +void __vmx_vpd_pin(struct vcpu* v); +void __vmx_vpd_unpin(struct vcpu* v); + +static inline void vmx_vpd_pin(struct vcpu* v) +{ + if (likely(v == current)) + return; + __vmx_vpd_pin(v); +} + +static inline void vmx_vpd_unpin(struct vcpu* v) +{ + if (likely(v == current)) + return; + __vmx_vpd_unpin(v); +} + #endif //__ASSEMBLY__ // VPD field offset diff -r b02e17ab2adf -r 3fa9bfb63a94 xen/include/asm-ia64/xenkregs.h --- a/xen/include/asm-ia64/xenkregs.h Tue Dec 25 17:29:11 2007 +0900 +++ b/xen/include/asm-ia64/xenkregs.h Fri Dec 28 13:04:47 2007 +0900 @@ -8,6 +8,8 @@ #define IA64_TR_SHARED_INFO 4 /* dtr4: page shared with domain */ #define IA64_TR_MAPPED_REGS 5 /* dtr5: vcpu mapped regs */ #define IA64_TR_VHPT 6 /* dtr6: vhpt */ + +#define IA64_TR_VPD 2 /* itr2: vpd */ #define IA64_DTR_GUEST_KERNEL 7 #define IA64_ITR_GUEST_KERNEL 2