You can subscribe to this list here.
2008 |
Jan
(41) |
Feb
(101) |
Mar
(164) |
Apr
(94) |
May
(27) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
---|
From: Zhang, X. <xia...@in...> - 2008-03-31 01:44:06
|
Avi Kivity wrote: > Zhang, Xiantao wrote: >> >> diff --git a/include/linux/smp.h b/include/linux/smp.h >> index 55232cc..b71820b 100644 >> --- a/include/linux/smp.h >> +++ b/include/linux/smp.h >> @@ -56,6 +56,9 @@ int smp_call_function(void(*func)(void *info), >> void *info, int retry, int wait); >> >> int smp_call_function_single(int cpuid, void (*func) (void *info), >> void *info, int retry, int wait); >> +int smp_call_function_mask(cpumask_t mask, >> + void (*func)(void *), void *info, >> + int wait); >> >> > > For all other archs, smp_call_function_mask() is declared in > <asm/smp.h> so please define it there. A separate patch can move the > declarations to <linux/smp.h>, since it makes sense to have just one > declaration (and the uniprocessor version is declared there anyway). OK, moved it to asm-ia64/smp.h first, although only x86 arch defined the interface in current code. :) Xiantao |
From: <tgi...@fr...> - 2008-03-30 14:34:33
|
Hi, Selon "Zhang, Xiantao" <xia...@in...>: > >From 5f82ea88c095cf89cbae920944c05e578f35365f Mon Sep 17 00:00:00 2001 > From: Xiantao Zhang <xia...@in...> > Date: Wed, 12 Mar 2008 14:48:09 +0800 > Subject: [PATCH] kvm/ia64: Add mmio decoder for kvm/ia64. [...] > + post_update = (inst.M5.i << 7) + inst.M5.imm7; > + if (inst.M5.s) > + temp -= post_update; > + else > + temp += post_update; The sign extension is not done correctly here. (This has been fixed in Xen code). > + post_update = (inst.M3.i << 7) + inst.M3.imm7; > + if (inst.M3.s) > + temp -= post_update; > + else > + temp += post_update; Ditto. > + post_update = (inst.M10.i << 7) + inst.M10.imm7; > + if (inst.M10.s) > + temp -= post_update; > + else > + temp += post_update; Ditto. > + post_update = (inst.M10.i << 7) + inst.M10.imm7; > + if (inst.M10.s) > + temp -= post_update; > + else > + temp += post_update; Ditto. > + post_update = (inst.M15.i << 7) + inst.M15.imm7; > + if (inst.M15.s) > + temp -= post_update; > + else > + temp += post_update; Ditto. Tristan. |
From: Avi K. <av...@qu...> - 2008-03-30 11:42:05
|
Zhang, Xiantao wrote: > > diff --git a/include/linux/smp.h b/include/linux/smp.h > index 55232cc..b71820b 100644 > --- a/include/linux/smp.h > +++ b/include/linux/smp.h > @@ -56,6 +56,9 @@ int smp_call_function(void(*func)(void *info), void > *info, int retry, int wait); > > int smp_call_function_single(int cpuid, void (*func) (void *info), void > *info, > int retry, int wait); > +int smp_call_function_mask(cpumask_t mask, > + void (*func)(void *), void *info, > + int wait); > > For all other archs, smp_call_function_mask() is declared in <asm/smp.h> so please define it there. A separate patch can move the declarations to <linux/smp.h>, since it makes sense to have just one declaration (and the uniprocessor version is declared there anyway). -- error compiling committee.c: too many arguments to function |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:50:30
|
>From 851ad380c7aace2b1a1409e91722660b1df43aa1 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:50:49 +0800 Subject: [PATCH] kvm/ia64: Add guest interruption injection support. process.c mainly handle interruption injection, and some faults handling. Signed-off-by: Anthony Xu <ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/process.c | 981 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 982 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/process.c diff --git a/arch/ia64/kvm/process.c b/arch/ia64/kvm/process.c new file mode 100644 index 0000000..e4c32c4 --- /dev/null +++ b/arch/ia64/kvm/process.c @@ -0,0 +1,981 @@ +/* + * process.c: handle interruption inject for guests. + * Copyright (c) 2005, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Shaofan Li (Susue Li) <sus...@in...> + * Xiaoyan Feng (Fleming Feng) <fle...@in...> + * Xuefei Xu (Anthony Xu) (Ant...@in...) + * Xiantao Zhang (xia...@in...) + */ +#include "vcpu.h" + +#include <asm/pal.h> +#include <asm/sal.h> +#include <asm/fpswa.h> +#include <asm/kregs.h> + +fpswa_interface_t *vmm_fpswa_interface; + +#define IA64_VHPT_TRANS_VECTOR 0x0000 +#define IA64_INST_TLB_VECTOR 0x0400 +#define IA64_DATA_TLB_VECTOR 0x0800 +#define IA64_ALT_INST_TLB_VECTOR 0x0c00 +#define IA64_ALT_DATA_TLB_VECTOR 0x1000 +#define IA64_DATA_NESTED_TLB_VECTOR 0x1400 +#define IA64_INST_KEY_MISS_VECTOR 0x1800 +#define IA64_DATA_KEY_MISS_VECTOR 0x1c00 +#define IA64_DIRTY_BIT_VECTOR 0x2000 +#define IA64_INST_ACCESS_BIT_VECTOR 0x2400 +#define IA64_DATA_ACCESS_BIT_VECTOR 0x2800 +#define IA64_BREAK_VECTOR 0x2c00 +#define IA64_EXTINT_VECTOR 0x3000 +#define IA64_PAGE_NOT_PRESENT_VECTOR 0x5000 +#define IA64_KEY_PERMISSION_VECTOR 0x5100 +#define IA64_INST_ACCESS_RIGHTS_VECTOR 0x5200 +#define IA64_DATA_ACCESS_RIGHTS_VECTOR 0x5300 +#define IA64_GENEX_VECTOR 0x5400 +#define IA64_DISABLED_FPREG_VECTOR 0x5500 +#define IA64_NAT_CONSUMPTION_VECTOR 0x5600 +#define IA64_SPECULATION_VECTOR 0x5700 /* UNUSED */ +#define IA64_DEBUG_VECTOR 0x5900 +#define IA64_UNALIGNED_REF_VECTOR 0x5a00 +#define IA64_UNSUPPORTED_DATA_REF_VECTOR 0x5b00 +#define IA64_FP_FAULT_VECTOR 0x5c00 +#define IA64_FP_TRAP_VECTOR 0x5d00 +#define IA64_LOWERPRIV_TRANSFER_TRAP_VECTOR 0x5e00 +#define IA64_TAKEN_BRANCH_TRAP_VECTOR 0x5f00 +#define IA64_SINGLE_STEP_TRAP_VECTOR 0x6000 + +/* SDM vol2 5.5 - IVA based interruption handling */ +#define INITIAL_PSR_VALUE_AT_INTERRUPTION IA64_PSR_UP_BIT| IA64_PSR_MFL_BIT|\ + IA64_PSR_MFH_BIT|IA64_PSR_PK_BIT|IA64_PSR_DT_BIT| \ + IA64_PSR_RT_BIT|IA64_PSR_MC_BIT|IA64_PSR_IT_BIT + +#define DOMN_PAL_REQUEST 0x110000 +#define DOMN_SAL_REQUEST 0x110001 + +static u64 vec2off[68] = {0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800, + 0x1c00, 0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, + 0x4000, 0x4400, 0x4800, 0x4c00, 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, + 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5a00, 0x5b00, 0x5c00, 0x5d00, + 0x5e00, 0x5f00, 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, + 0x6700, 0x6800, 0x6900, 0x6a00, 0x6b00, 0x6c00, 0x6d00, 0x6e00, 0x6f00, + 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, 0x7800, + 0x7900, 0x7a00, 0x7b00, 0x7c00, 0x7d00, 0x7e00, 0x7f00 +}; + +static void collect_interruption(VCPU *vcpu) +{ + u64 ipsr; + u64 vdcr; + u64 vifs; + ia64_psr vpsr; + REGS *regs = vcpu_regs(vcpu); + + vpsr.val = vcpu_get_psr(vcpu); + vcpu_bsw0(vcpu); + if (vpsr.ic) { + + /* Sync mpsr id/da/dd/ss/ed bits to vipsr + * since after guest do rfi, we still want these bits on in + * mpsr + */ + + ipsr = regs->cr_ipsr; + vpsr.val = vpsr.val | (ipsr & (IA64_PSR_ID | IA64_PSR_DA + | IA64_PSR_DD | IA64_PSR_SS + | IA64_PSR_ED)); + vcpu_set_ipsr(vcpu, vpsr.val); + + /* Currently, for trap, we do not advance IIP to next + * instruction. That's because we assume caller already + * set up IIP correctly + */ + + vcpu_set_iip(vcpu , regs->cr_iip); + + /* set vifs.v to zero */ + vifs = VCPU(vcpu, ifs); + vifs &= ~IA64_IFS_V; + vcpu_set_ifs(vcpu, vifs); + + vcpu_set_iipa(vcpu, VMX(vcpu, cr_iipa)); + } + + vdcr = VCPU(vcpu, dcr); + + /* Set guest psr + * up/mfl/mfh/pk/dt/rt/mc/it keeps unchanged + * be: set to the value of dcr.be + * pp: set to the value of dcr.pp + */ + vpsr.val &= INITIAL_PSR_VALUE_AT_INTERRUPTION; + vpsr.val |= (vdcr & IA64_DCR_BE); + + /* VDCR pp bit position is different from VPSR pp bit */ + if (vdcr & IA64_DCR_PP) { + vpsr.val |= IA64_PSR_PP; + } else { + vpsr.val &= ~IA64_PSR_PP;; + } + + vcpu_set_psr(vcpu, vpsr.val); + +} + +void inject_guest_interruption(VCPU *vcpu, u64 vec) +{ + u64 viva; + REGS *regs; + ia64_isr pt_isr; + + regs = vcpu_regs(vcpu); + + /* clear cr.isr.ir (incomplete register frame)*/ + pt_isr.val = VMX(vcpu, cr_isr); + pt_isr.ir = 0; + VMX(vcpu, cr_isr) = pt_isr.val; + + collect_interruption(vcpu); + + viva = vcpu_get_iva(vcpu); + regs->cr_iip = viva + vec; +} + +static u64 vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa) +{ + ia64_rr rr, rr1; + + rr.val = vcpu_get_rr(vcpu, ifa); + rr1.val = 0; + rr1.ps = rr.ps; + rr1.rid = rr.rid; + return (rr1.val); +} + + +/* + * Set vIFA & vITIR & vIHA, when vPSR.ic =1 + * Parameter: + * set_ifa: if true, set vIFA + * set_itir: if true, set vITIR + * set_iha: if true, set vIHA + */ +void set_ifa_itir_iha(VCPU *vcpu, u64 vadr, + int set_ifa, int set_itir, int set_iha) +{ + ia64_psr vpsr; + u64 value; + + vpsr.val = VCPU(vcpu, vpsr); + /* Vol2, Table 8-1 */ + if (vpsr.ic) { + if (set_ifa) { + vcpu_set_ifa(vcpu, vadr); + } + if (set_itir) { + value = vcpu_get_itir_on_fault(vcpu, vadr); + vcpu_set_itir(vcpu, value); + } + + if (set_iha) { + value = vcpu_thash(vcpu, vadr); + vcpu_set_iha(vcpu, value); + } + } +} + +/* + * Data TLB Fault + * @ Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void dtlb_fault(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu, IA64_DATA_TLB_VECTOR); +} + +/* + * Instruction TLB Fault + * @ Instruction TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void itlb_fault (VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu, IA64_INST_TLB_VECTOR); +} + + + +/* + * Data Nested TLB Fault + * @ Data Nested TLB Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void nested_dtlb(VCPU *vcpu) +{ + inject_guest_interruption(vcpu, IA64_DATA_NESTED_TLB_VECTOR); +} + +/* + * Alternate Data TLB Fault + * @ Alternate Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void alt_dtlb(VCPU *vcpu, u64 vadr) +{ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_ALT_DATA_TLB_VECTOR); +} + + +/* + * Data TLB Fault + * @ Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void alt_itlb(VCPU *vcpu, u64 vadr) +{ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_ALT_INST_TLB_VECTOR); +} + +/* Deal with: + * VHPT Translation Vector + */ +static void _vhpt_fault(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA*/ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu, IA64_VHPT_TRANS_VECTOR); + + +} + +/* + * VHPT Instruction Fault + * @ VHPT Translation vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void ivhpt_fault(VCPU *vcpu, u64 vadr) +{ + _vhpt_fault(vcpu, vadr); +} + + +/* + * VHPT Data Fault + * @ VHPT Translation vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void dvhpt_fault(VCPU *vcpu, u64 vadr) +{ + _vhpt_fault(vcpu, vadr); +} + + + +/* + * Deal with: + * General Exception vector + */ +void _general_exception(VCPU *vcpu) +{ + inject_guest_interruption(vcpu, IA64_GENEX_VECTOR); +} + + +/* + * Illegal Operation Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void illegal_op(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Illegal Dependency Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void illegal_dep(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Reserved Register/Field Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void rsv_reg_field(VCPU *vcpu) +{ + _general_exception(vcpu); +} +/* + * Privileged Operation Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ + +void privilege_op(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Unimplement Data Address Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void unimpl_daddr(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Privileged Register Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void privilege_reg(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* Deal with + * Nat consumption vector + * Parameter: + * vaddr: Optional, if t == REGISTER + */ +static void _nat_consumption_fault(VCPU *vcpu, u64 vadr, miss_type t) +{ + /* If vPSR.ic && t == DATA/INST, IFA */ + if (t == DATA || t == INSTRUCTION) { + /* IFA */ + set_ifa_itir_iha(vcpu, vadr, 1, 0, 0); + } + + inject_guest_interruption(vcpu, IA64_NAT_CONSUMPTION_VECTOR); +} + +/* + * IR Data Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +#if 0 + static void +ir_nat_page_consumption(VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, DATA); +} +#endif /*shadow it due to no use currently*/ + +/* + * Instruction Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void inat_page_consumption(VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, INSTRUCTION); +} + +/* + * Register Nat Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void rnat_consumption(VCPU *vcpu) +{ + _nat_consumption_fault(vcpu, 0, REGISTER); +} + +/* + * Data Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void dnat_page_consumption(VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, DATA); +} + +/* Deal with + * Page not present vector + */ +static void __page_not_present(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_PAGE_NOT_PRESENT_VECTOR); +} + + +void data_page_not_present(VCPU *vcpu, u64 vadr) +{ + __page_not_present(vcpu, vadr); +} + + +void inst_page_not_present(VCPU *vcpu, u64 vadr) +{ + __page_not_present(vcpu, vadr); +} + + +/* Deal with + * Data access rights vector + */ +void data_access_rights(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_DATA_ACCESS_RIGHTS_VECTOR); +} + +fpswa_ret_t vmm_fp_emulate(int fp_fault, void *bundle, unsigned long *ipsr, + unsigned long *fpsr, unsigned long *isr, unsigned long *pr, + unsigned long *ifs, REGS *regs) +{ + fp_state_t fp_state; + fpswa_ret_t ret; + struct kvm_vcpu *vcpu = current_vcpu; + + uint64_t old_rr7 = ia64_get_rr(7UL<<61); + + if (!vmm_fpswa_interface) + return (fpswa_ret_t) {-1, 0, 0, 0}; + + /* + * Just let fpswa driver to use hardware fp registers. + * No fp register is valid in memory. + */ + memset(&fp_state, 0, sizeof(fp_state_t)); + + /* + * unsigned long (*EFI_FPSWA) ( + * unsigned long trap_type, + * void *Bundle, + * unsigned long *pipsr, + * unsigned long *pfsr, + * unsigned long *pisr, + * unsigned long *ppreds, + * unsigned long *pifs, + * void *fp_state); + */ + /*Call host fpswa interface directly to virtualize + *guest fpswa request! + */ + ia64_set_rr(7UL << 61, vcpu->arch.host.rr[7]); + ia64_srlz_d(); + + ret = (*vmm_fpswa_interface->fpswa) (fp_fault, bundle, + ipsr, fpsr, isr, pr, ifs, &fp_state); + ia64_set_rr(7UL << 61, old_rr7); + ia64_srlz_d(); + return ret; +} + +/* + * Handle floating-point assist faults and traps for domain. + */ +unsigned long vmm_handle_fpu_swa(int fp_fault, REGS *regs, unsigned long isr) +{ + struct kvm_vcpu *v = current_vcpu; + IA64_BUNDLE bundle; + unsigned long fault_ip; + fpswa_ret_t ret; + + fault_ip = regs->cr_iip; + /* + * When the FP trap occurs, the trapping instruction is completed. + * If ipsr.ri == 0, there is the trapping instruction in previous + * bundle. + */ + if (!fp_fault && (ia64_psr(regs)->ri == 0)) + fault_ip -= 16; + + if (fetch_code(v, fault_ip, &bundle)) + return -EAGAIN; + + if (!bundle.i64[0] && !bundle.i64[1]) { + return -EACCES; + } + + ret = vmm_fp_emulate(fp_fault, &bundle, ®s->cr_ipsr, ®s->ar_fpsr, + &isr, ®s->pr, ®s->cr_ifs, regs); + return ret.status; +} + +void reflect_interruption(u64 ifa, u64 isr, u64 iim, + u64 vec, REGS *regs) +{ + u64 vector; + int status ; + VCPU *vcpu = current_vcpu; + u64 vpsr = VCPU(vcpu, vpsr); + + vector = vec2off[vec]; + + if (!(vpsr & IA64_PSR_IC) && (vector != IA64_DATA_NESTED_TLB_VECTOR)) { + panic_vm(vcpu); + return; + } + + switch (vec) { + case 32: /*IA64_FP_FAULT_VECTOR*/ + status = vmm_handle_fpu_swa(1, regs, isr); + if (!status) { + vcpu_increment_iip(vcpu); + return; + } else if (-EAGAIN == status) + return; + break; + case 33: /*IA64_FP_TRAP_VECTOR*/ + status = vmm_handle_fpu_swa(0, regs, isr); + if (!status) + return ; + else if (-EAGAIN == status) { + vcpu_decrement_iip(vcpu); + return ; + } + break; + } + + VCPU(vcpu, isr) = isr; + VCPU(vcpu, iipa) = regs->cr_iip; + if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR) + VCPU(vcpu, iim) = iim; + else { + set_ifa_itir_iha(vcpu, ifa, 1, 1, 1); + } + inject_guest_interruption(vcpu, vector); +} + +static void set_pal_call_data(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + /*FIXME:For static and stacked convention, firmware + * has put the parameters in gr28-gr31 before + * break to vmm !!*/ + + p->u.pal_data.gr28 = vcpu_get_gr(vcpu, 28); + p->u.pal_data.gr29 = vcpu_get_gr(vcpu, 29); + p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30); + p->u.pal_data.gr31 = vcpu_get_gr(vcpu, 31); + p->exit_reason = EXIT_REASON_PAL_CALL; +} + +static void set_pal_call_result(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + if (p->exit_reason == EXIT_REASON_PAL_CALL) { + vcpu_set_gr(vcpu, 8, p->u.pal_data.ret.status, 0); + vcpu_set_gr(vcpu, 9, p->u.pal_data.ret.v0, 0); + vcpu_set_gr(vcpu, 10, p->u.pal_data.ret.v1, 0); + vcpu_set_gr(vcpu, 11, p->u.pal_data.ret.v2, 0); + } else + panic_vm(vcpu); +} + +static void set_sal_call_data(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + p->u.sal_data.in0 = vcpu_get_gr(vcpu, 32); + p->u.sal_data.in1 = vcpu_get_gr(vcpu, 33); + p->u.sal_data.in2 = vcpu_get_gr(vcpu, 34); + p->u.sal_data.in3 = vcpu_get_gr(vcpu, 35); + p->u.sal_data.in4 = vcpu_get_gr(vcpu, 36); + p->u.sal_data.in5 = vcpu_get_gr(vcpu, 37); + p->u.sal_data.in6 = vcpu_get_gr(vcpu, 38); + p->u.sal_data.in7 = vcpu_get_gr(vcpu, 39); + p->exit_reason = EXIT_REASON_SAL_CALL; +} + +static void set_sal_call_result(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + if (p->exit_reason == EXIT_REASON_SAL_CALL) { + vcpu_set_gr(vcpu, 8, p->u.sal_data.ret.r8, 0); + vcpu_set_gr(vcpu, 9, p->u.sal_data.ret.r9, 0); + vcpu_set_gr(vcpu, 10, p->u.sal_data.ret.r10, 0); + vcpu_set_gr(vcpu, 11, p->u.sal_data.ret.r11, 0); + } else + panic_vm(vcpu); +} + +void kvm_ia64_handle_break(unsigned long ifa, struct kvm_pt_regs *regs, + unsigned long isr, unsigned long iim) +{ + VCPU *v = current_vcpu; + + if (ia64_psr(regs)->cpl == 0) { + /* Allow hypercalls only when cpl = 0. */ + if (iim == DOMN_PAL_REQUEST) { + set_pal_call_data(v); + vmm_transition(v); + set_pal_call_result(v); + vcpu_increment_iip(v); + return; + } else if (iim == DOMN_SAL_REQUEST) { + set_sal_call_data(v); + vmm_transition(v); + set_sal_call_result(v); + vcpu_increment_iip(v); + return; + } + } + reflect_interruption(ifa, isr, iim, 11, regs); +} + +void check_pending_irq(VCPU *vcpu) +{ + int mask, h_pending, h_inservice; + u64 isr; + ia64_psr vpsr; + REGS *regs = vcpu_regs(vcpu); + + h_pending = highest_pending_irq(vcpu); + if (h_pending == NULL_VECTOR) { + update_vhpi(vcpu, NULL_VECTOR); + return; + } + h_inservice = highest_inservice_irq(vcpu); + + vpsr.val = VCPU(vcpu, vpsr); + mask = irq_masked(vcpu, h_pending, h_inservice); + if (vpsr.i && IRQ_NO_MASKED == mask) { + isr = vpsr.val & IA64_PSR_RI; + update_vhpi(vcpu, h_pending); + reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */ + } else if (mask == IRQ_MASKED_BY_INSVC) { + if (VCPU(vcpu, vhpi)) + update_vhpi(vcpu, NULL_VECTOR); + } else { + /* masked by vpsr.i or vtpr.*/ + update_vhpi(vcpu, h_pending); + } +} + +static void generate_exirq(VCPU *vcpu) +{ + ia64_psr vpsr; + uint64_t isr; + + REGS *regs = vcpu_regs(vcpu); + + vpsr.val = VCPU(vcpu, vpsr); + isr = vpsr.val & IA64_PSR_RI; + if (!vpsr.ic) + panic_vm(vcpu); + reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */ +} + +void vhpi_detection(VCPU *vcpu) +{ + uint64_t threshold, vhpi; + tpr_t vtpr; + ia64_psr vpsr; + + vpsr.val = VCPU(vcpu, vpsr); + vtpr.val = VCPU(vcpu, tpr); + + threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic; + vhpi = VCPU(vcpu, vhpi); + if (vhpi > threshold) { + /* interrupt actived*/ + generate_exirq(vcpu); + } +} + + +void leave_hypervisor_tail(void) +{ + VCPU *v = current_vcpu; + + if (VMX(v, timer_check)) { + VMX(v, timer_check) = 0; + if (VMX(v, itc_check)) { + if (vcpu_get_itc(v) > VCPU(v, itm)) { + if (!(VCPU(v, itv) & (1 << 16))) { + vcpu_pend_interrupt(v, VCPU(v, itv) + & 0xff); + VMX(v, itc_check) = 0; + } else { + v->arch.timer_pending = 1; + } + VMX(v, last_itc) = VCPU(v, itm) + 1; + } + } + } + + rmb(); + if (v->arch.irq_new_pending) { + v->arch.irq_new_pending = 0; + VMX(v, irq_check) = 0; + check_pending_irq(v); + return; + } + if (VMX(v, irq_check)) { + VMX(v, irq_check) = 0; + vhpi_detection(v); + } +} + + +static inline void handle_lds(REGS *regs) +{ + regs->cr_ipsr |= IA64_PSR_ED; +} + +void physical_tlb_miss(VCPU *vcpu, unsigned long vadr, int type) +{ + unsigned long pte; + ia64_rr rr; + + rr.val = ia64_get_rr(vadr); + pte = vadr & _PAGE_PPN_MASK; + pte = pte | PHY_PAGE_WB; + thash_vhpt_insert(vcpu, pte, (u64)(rr.ps << 2), vadr, type); + return; +} + +void kvm_page_fault(u64 vadr , u64 vec, REGS *regs) +{ + ia64_psr vpsr; + int type; + + u64 vhpt_adr, gppa, pteval, rr, itir; + ia64_isr misr; + ia64_pta vpta; + thash_data_t *data; + VCPU *v = current_vcpu; + + vpsr.val = VCPU(v, vpsr); + misr.val = VMX(v, cr_isr); + + type = vec; + + if (is_physical_mode(v) && (!(vadr << 1 >> 62))) { + if (vec == 2) { + if (__gpfn_is_io((vadr << 1) >> (PAGE_SHIFT + 1))) { + emulate_io_inst(v, ((vadr << 1) >> 1), 4); + return; + } + } + physical_tlb_miss(v, vadr, type); + return; + } + data = vtlb_lookup(v, vadr, type); + if (data != 0) { + if (type == D_TLB) { + gppa = (vadr & ((1UL << data->ps) - 1)) + + (data->ppn >> (data->ps - 12) << data->ps); + if (__gpfn_is_io(gppa >> PAGE_SHIFT)) { + if (data->pl >= ((regs->cr_ipsr >> + IA64_PSR_CPL0_BIT) & 3)) + emulate_io_inst(v, gppa, data->ma); + else { + vcpu_set_isr(v, misr.val); + data_access_rights(v, vadr); + } + return ; + } + } + thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type); + + } else if (type == D_TLB) { + if (misr.sp) { + handle_lds(regs); + return; + } + + rr = vcpu_get_rr(v, vadr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + + if (!vhpt_enabled(v, vadr, misr.rs ? RSE_REF : DATA_REF)) { + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + alt_dtlb(v, vadr); + } else { + nested_dtlb(v); + } + return ; + } + + vpta.val = vcpu_get_pta(v); + /* avoid recursively walking (short format) VHPT */ + + vhpt_adr = vcpu_thash(v, vadr); + if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { + /* VHPT successfully read. */ + if (!(pteval & _PAGE_P)) { + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + } else { + nested_dtlb(v); + } + } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) { + thash_purge_and_insert(v, pteval, itir, + vadr, D_TLB); + } else if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + } else { + nested_dtlb(v); + } + } else { + /* Can't read VHPT. */ + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dvhpt_fault(v, vadr); + } else { + nested_dtlb(v); + } + } + } else if (type == I_TLB) { + if (!vpsr.ic) + misr.ni = 1; + if (!vhpt_enabled(v, vadr, INST_REF)) { + vcpu_set_isr(v, misr.val); + alt_itlb(v, vadr); + return; + } + + vpta.val = vcpu_get_pta(v); + + vhpt_adr = vcpu_thash(v, vadr); + if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { + /* VHPT successfully read. */ + if (pteval & _PAGE_P) { + if ((pteval & _PAGE_MA_MASK) == _PAGE_MA_ST) { + vcpu_set_isr(v, misr.val); + itlb_fault(v, vadr); + return ; + } + rr = vcpu_get_rr(v, vadr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + thash_purge_and_insert(v, pteval, itir, + vadr, I_TLB); + } else { + vcpu_set_isr(v, misr.val); + inst_page_not_present(v, vadr); + } + } else { + vcpu_set_isr(v, misr.val); + ivhpt_fault(v, vadr); + } + } +} + +void kvm_vexirq(VCPU *vcpu) +{ + u64 vpsr, isr; + REGS *regs; + + regs = vcpu_regs(vcpu); + vpsr = VCPU(vcpu, vpsr); + isr = vpsr & IA64_PSR_RI; + reflect_interruption(0, isr, 0, 12, regs); /*EXT IRQ*/ +} + +void kvm_ia64_handle_irq(VCPU *v) +{ + struct exit_ctl_data *p = &v->arch.exit_data; + long psr; + + local_irq_save(psr); + p->exit_reason = EXIT_REASON_EXTERNAL_INTERRUPT; + vmm_transition(v); + local_irq_restore(psr); + + VMX(v, timer_check) = 1; + +} + +static void ptc_ga_remote_func(struct kvm_vcpu *v, int pos) +{ + u64 oldrid, moldrid, oldpsbits, vaddr; + struct kvm_ptc_g *p = &v->arch.ptc_g_data[pos]; + vaddr = p->vaddr; + + oldrid = VMX(v, vrr[0]); + VMX(v, vrr[0]) = p->rr; + oldpsbits = VMX(v, psbits[0]); + VMX(v, psbits[0]) = VMX(v, psbits[REGION_NUMBER(vaddr)]); + moldrid = ia64_get_rr(0x0); + ia64_set_rr(0x0, vrrtomrr(p->rr)); + ia64_srlz_d(); + + vaddr = PAGEALIGN(vaddr, p->ps); + thash_purge_entries_remote(v, vaddr, p->ps); + + VMX(v, vrr[0]) = oldrid; + VMX(v, psbits[0]) = oldpsbits; + ia64_set_rr(0x0, moldrid); + ia64_dv_serialize_data(); +} + +static void vcpu_do_resume(struct kvm_vcpu *vcpu) +{ + /*Re-init VHPT and VTLB once from resume*/ + vcpu->arch.vhpt.num = VHPT_NUM_ENTRIES; + thash_init(&vcpu->arch.vhpt, VHPT_SHIFT); + vcpu->arch.vtlb.num = VTLB_NUM_ENTRIES; + thash_init(&vcpu->arch.vtlb, VTLB_SHIFT); + + ia64_set_pta(vcpu->arch.vhpt.pta.val); +} + +static void kvm_do_resume_op(struct kvm_vcpu *vcpu) +{ + if (test_and_clear_bit(KVM_REQ_RESUME, &vcpu->requests)) { + vcpu_do_resume(vcpu); + return; + } + + if (unlikely(test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))) { + thash_purge_all(vcpu); + return; + } + + if (test_and_clear_bit(KVM_REQ_PTC_G, &vcpu->requests)) { + while (vcpu->arch.ptc_g_count > 0) + ptc_ga_remote_func(vcpu, --vcpu->arch.ptc_g_count); + } +} + +void vmm_transition(struct kvm_vcpu *vcpu) +{ + ia64_call_vsa(PAL_VPS_SAVE, (unsigned long)vcpu->arch.vpd, + 0, 0, 0, 0, 0, 0); + vmm_trampoline(&vcpu->arch.guest, &vcpu->arch.host); + ia64_call_vsa(PAL_VPS_RESTORE, (unsigned long)vcpu->arch.vpd, + 0, 0, 0, 0, 0, 0); + kvm_do_resume_op(vcpu); +} -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:48:31
|
From 1028321e00b0f3a60fc414484754f489a70f2400 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Sat, 29 Mar 2008 09:23:37 +0800 Subject: [PATCH] Add API for allocating Dynamic TR resouce. Dynamic TR resouce should be managed in an uniform way. Signed-off-by: Xiantao Zhang <xia...@in...> Signed-off-by: Anthony Xu<ant...@in...> --- arch/ia64/kernel/mca.c | 49 +++++++++++ arch/ia64/kernel/mca_asm.S | 5 + arch/ia64/mm/tlb.c | 196 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-ia64/kregs.h | 3 + include/asm-ia64/tlb.h | 14 +++ 5 files changed, 267 insertions(+), 0 deletions(-) diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 6c18221..ee6924b 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -97,6 +97,7 @@ #include <asm/irq.h> #include <asm/hw_irq.h> +#include <asm/tlb.h> #include "mca_drv.h" #include "entry.h" @@ -112,6 +113,7 @@ DEFINE_PER_CPU(u64, ia64_mca_data); /* == __per_cpu_mca[smp_processor_id()] */ DEFINE_PER_CPU(u64, ia64_mca_per_cpu_pte); /* PTE to map per-CPU area */ DEFINE_PER_CPU(u64, ia64_mca_pal_pte); /* PTE to map PAL code */ DEFINE_PER_CPU(u64, ia64_mca_pal_base); /* vaddr PAL code granule */ +DEFINE_PER_CPU(u64, ia64_mca_tr_reload); /* Flag for TR reload */ unsigned long __per_cpu_mca[NR_CPUS]; @@ -1182,6 +1184,49 @@ all_in: return; } +/* mca_insert_tr + * + * Switch rid when TR reload and needed! + * iord: 1: itr, 2: itr; + * +*/ +static void mca_insert_tr(u64 iord) +{ + + int i; + u64 old_rr; + struct ia64_tr_entry *p; + unsigned long psr; + int cpu = smp_processor_id(); + + psr = ia64_clear_ic(); + for (i = IA64_TR_ALLOC_BASE; i < IA64_TR_ALLOC_MAX; i++) { + p = &__per_cpu_idtrs[cpu][iord-1][i]; + if (p->pte&0x1) { + old_rr = ia64_get_rr(p->ifa); + if (old_rr != p->rr) { + ia64_set_rr(p->ifa, p->rr); + ia64_srlz_d(); + } + ia64_ptr(iord, p->ifa, p->itir >> 2); + ia64_srlz_i(); + if (iord & 0x1) { + ia64_itr(0x1, i, p->ifa, p->pte, p->itir >> 2); + ia64_srlz_i(); + } + if (iord & 0x2) { + ia64_itr(0x2, i, p->ifa, p->pte, p->itir >> 2); + ia64_srlz_i(); + } + if (old_rr != p->rr) { + ia64_set_rr(p->ifa, old_rr); + ia64_srlz_d(); + } + } + } + ia64_set_psr(psr); +} + /* * ia64_mca_handler * @@ -1271,6 +1316,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, monarch_cpu = -1; #endif } + if (__get_cpu_var(ia64_mca_tr_reload)) { + mca_insert_tr(0x1); /*Reload dynamic itrs*/ + mca_insert_tr(0x2); /*Reload dynamic itrs*/ + } if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover) == NOTIFY_STOP) ia64_mca_spin(__func__); diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index 8bc7d25..a06d465 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -219,8 +219,13 @@ ia64_reload_tr: mov r20=IA64_TR_CURRENT_STACK ;; itr.d dtr[r20]=r16 + GET_THIS_PADDR(r2, ia64_mca_tr_reload) + mov r18 = 1 ;; srlz.d + ;; + st8 [r2] =r18 + ;; done_tlb_purge_and_reload: diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index 655da24..0b418cc 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -26,6 +26,8 @@ #include <asm/pal.h> #include <asm/tlbflush.h> #include <asm/dma.h> +#include <asm/processor.h> +#include <asm/tlb.h> static struct { unsigned long mask; /* mask of supported purge page-sizes */ @@ -39,6 +41,10 @@ struct ia64_ctx ia64_ctx = { }; DEFINE_PER_CPU(u8, ia64_need_tlb_flush); +DEFINE_PER_CPU(u8, ia64_tr_num); /*Number of TR slots in current processor*/ +DEFINE_PER_CPU(u8, ia64_tr_used); /*Max Slot number used by kernel*/ + +struct ia64_tr_entry __per_cpu_idtrs[NR_CPUS][2][IA64_TR_ALLOC_MAX]; /* * Initializes the ia64_ctx.bitmap array based on max_ctx+1. @@ -190,6 +196,9 @@ ia64_tlb_init (void) ia64_ptce_info_t uninitialized_var(ptce_info); /* GCC be quiet */ unsigned long tr_pgbits; long status; + pal_vm_info_1_u_t vm_info_1; + pal_vm_info_2_u_t vm_info_2; + int cpu = smp_processor_id(); if ((status = ia64_pal_vm_page_size(&tr_pgbits, &purge.mask)) != 0) { printk(KERN_ERR "PAL_VM_PAGE_SIZE failed with status=%ld; " @@ -206,4 +215,191 @@ ia64_tlb_init (void) local_cpu_data->ptce_stride[1] = ptce_info.stride[1]; local_flush_tlb_all(); /* nuke left overs from bootstrapping... */ + status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2); + + if (status) { + printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status); + per_cpu(ia64_tr_num, cpu) = 8; + return; + } + per_cpu(ia64_tr_num, cpu) = vm_info_1.pal_vm_info_1_s.max_itr_entry+1; + if (per_cpu(ia64_tr_num, cpu) > + (vm_info_1.pal_vm_info_1_s.max_dtr_entry+1)) + per_cpu(ia64_tr_num, cpu) = + vm_info_1.pal_vm_info_1_s.max_dtr_entry+1; + if (per_cpu(ia64_tr_num, cpu) > IA64_TR_ALLOC_MAX) { + per_cpu(ia64_tr_num, cpu) = IA64_TR_ALLOC_MAX; + printk(KERN_DEBUG"TR register number exceeds IA64_TR_ALLOC_MAX!" + "IA64_TR_ALLOC_MAX should be extended\n"); + } +} + +/* + * is_tr_overlap + * + * Check overlap with inserted TRs. + */ +static int is_tr_overlap(struct ia64_tr_entry *p, u64 va, u64 log_size) +{ + u64 tr_log_size; + u64 tr_end; + u64 va_rr = ia64_get_rr(va); + u64 va_rid = RR_TO_RID(va_rr); + u64 va_end = va + (1<<log_size) - 1; + + if (va_rid != RR_TO_RID(p->rr)) + return 0; + tr_log_size = (p->itir & 0xff) >> 2; + tr_end = p->ifa + (1<<tr_log_size) - 1; + + if (va > tr_end || p->ifa > va_end) + return 0; + return 1; + +} + +/* + * ia64_insert_tr in virtual mode. Allocate a TR slot + * + * target_mask : 0x1 : itr, 0x2 : dtr, 0x3 : idtr + * + * va : virtual address. + * pte : pte entries inserted. + * log_size: range to be covered. + * + * Return value: <0 : error No. + * + * >=0 : slot number allocated for TR. + */ +int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64 log_size) +{ + int i, r; + unsigned long psr; + struct ia64_tr_entry *p; + int cpu = smp_processor_id(); + + r = -EINVAL; + /*Check overlap with existing TR entries*/ + if (target_mask&0x1) { + p = &__per_cpu_idtrs[cpu][0][0]; + for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_used, cpu); + i++, p++) { + if (p->pte&0x1) + if (is_tr_overlap(p, va, log_size)) { + printk(KERN_DEBUG"Overlapped Entry" + "Inserted for TR Reigster!!"); + goto out; + } + } + } + if (target_mask&0x2) { + p = &__per_cpu_idtrs[cpu][1][0]; + for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_used, cpu); + i++, p++) { + if (p->pte&0x1) + if (is_tr_overlap(p, va, log_size)) { + printk(KERN_DEBUG"Overlapped Entry" + "Inserted for TR Reigster!!"); + goto out; + } + } + } + + for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_num, cpu); i++) { + switch (target_mask & 0x3) { + case 1: + if (!(__per_cpu_idtrs[cpu][0][i].pte&0x1)) + goto found; + continue; + case 2: + if (!(__per_cpu_idtrs[cpu][1][i].pte&0x1)) + goto found; + continue; + case 3: + if (!(__per_cpu_idtrs[cpu][0][i].pte&0x1) && + !(__per_cpu_idtrs[cpu][1][i].pte&0x1)) + goto found; + continue; + default: + r = -EINVAL; + goto out; + } + } +found: + if (i >= per_cpu(ia64_tr_num, cpu)) { + r = -EBUSY; + goto out; + } + + /*Record tr info for mca hander use!*/ + if (i > per_cpu(ia64_tr_used, cpu)) + per_cpu(ia64_tr_used, cpu) = i; + + psr = ia64_clear_ic(); + if (target_mask & 0x1) { + ia64_itr(0x1, i, va, pte, log_size); + ia64_srlz_i(); + p = &__per_cpu_idtrs[cpu][0][i]; + p->ifa = va; + p->pte = pte; + p->itir = log_size << 2; + p->rr = ia64_get_rr(va); + } + if (target_mask & 0x2) { + ia64_itr(0x2, i, va, pte, log_size); + ia64_srlz_i(); + p = &__per_cpu_idtrs[cpu][1][i]; + p->ifa = va; + p->pte = pte; + p->itir = log_size << 2; + p->rr = ia64_get_rr(va); + } + ia64_set_psr(psr); + r = i; +out: + return r; +} +EXPORT_SYMBOL_GPL(ia64_itr_entry); + +/* + * ia64_purge_tr + * + * target_mask: 0x1: purge itr, 0x2 : purge dtr, 0x3 purge idtr. + * + * slot: slot number to be freed. + */ +void ia64_ptr_entry(u64 target_mask, int slot) +{ + int cpu = smp_processor_id(); + int i; + struct ia64_tr_entry *p; + + if (slot < IA64_TR_ALLOC_BASE || slot >= per_cpu(ia64_tr_num, cpu)) + return; + + if (target_mask&0x1) { + p = &__per_cpu_idtrs[cpu][0][slot]; + if ((p->pte&0x1) && is_tr_overlap(p, p->ifa, p->itir>>2)) { + p->pte = 0; + ia64_ptr(0x1, p->ifa, p->itir>>2); + ia64_srlz_i(); + } + } + + if (target_mask&0x2) { + p = &__per_cpu_idtrs[cpu][1][slot]; + if ((p->pte&0x1) && is_tr_overlap(p, p->ifa, p->itir>>2)) { + p->pte = 0; + ia64_ptr(0x2, p->ifa, p->itir>>2); + ia64_srlz_i(); + } + } + + for (i = per_cpu(ia64_tr_used, cpu) - 1; i >= IA64_TR_ALLOC_BASE; i--) { + if ((__per_cpu_idtrs[cpu][0][i].pte&0x1) || + (__per_cpu_idtrs[cpu][1][i].pte&0x1)) + break; + } + per_cpu(ia64_tr_used, cpu) = i; } +EXPORT_SYMBOL_GPL(ia64_ptr_entry); diff --git a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h index 7e55a58..aefcdfe 100644 --- a/include/asm-ia64/kregs.h +++ b/include/asm-ia64/kregs.h @@ -31,6 +31,9 @@ #define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */ #define IA64_TR_CURRENT_STACK 1 /* dtr1: maps kernel's memory- & register-stacks */ +#define IA64_TR_ALLOC_BASE 2 /* itr&dtr: Base of dynamic TR resource*/ +#define IA64_TR_ALLOC_MAX 32 /* Max number for dynamic use*/ + /* Processor status register bits: */ #define IA64_PSR_BE_BIT 1 #define IA64_PSR_UP_BIT 2 diff --git a/include/asm-ia64/tlb.h b/include/asm-ia64/tlb.h index 26edcb7..de1f829 100644 --- a/include/asm-ia64/tlb.h +++ b/include/asm-ia64/tlb.h @@ -64,6 +64,20 @@ struct mmu_gather { struct page *pages[FREE_PTE_NR]; }; +struct ia64_tr_entry { + u64 ifa; + u64 itir; + u64 pte; + u64 rr; +}; /*Record for tr entry!*/ + +extern int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64 log_size); +extern void ia64_ptr_entry(u64 target_mask, int slot); + +extern struct ia64_tr_entry __per_cpu_idtrs[NR_CPUS][2][IA64_TR_ALLOC_MAX]; + +#define RR_TO_RID(rr) ((rr)<<32>>40) + /* Users of the generic TLB shootdown code must declare this storage space. */ DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:43:09
|
>From 851ad380c7aace2b1a1409e91722660b1df43aa1 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:50:49 +0800 Subject: [PATCH] kvm/ia64: Add guest interruption injection support. process.c mainly handle interruption injection, and some faults handling. Signed-off-by: Anthony Xu <ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/process.c | 981 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 981 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/process.c diff --git a/arch/ia64/kvm/process.c b/arch/ia64/kvm/process.c new file mode 100644 index 0000000..e4c32c4 --- /dev/null +++ b/arch/ia64/kvm/process.c @@ -0,0 +1,981 @@ +/* + * process.c: handle interruption inject for guests. + * Copyright (c) 2005, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Shaofan Li (Susue Li) <sus...@in...> + * Xiaoyan Feng (Fleming Feng) <fle...@in...> + * Xuefei Xu (Anthony Xu) (Ant...@in...) + * Xiantao Zhang (xia...@in...) + */ +#include "vcpu.h" + +#include <asm/pal.h> +#include <asm/sal.h> +#include <asm/fpswa.h> +#include <asm/kregs.h> + +fpswa_interface_t *vmm_fpswa_interface; + +#define IA64_VHPT_TRANS_VECTOR 0x0000 +#define IA64_INST_TLB_VECTOR 0x0400 +#define IA64_DATA_TLB_VECTOR 0x0800 +#define IA64_ALT_INST_TLB_VECTOR 0x0c00 +#define IA64_ALT_DATA_TLB_VECTOR 0x1000 +#define IA64_DATA_NESTED_TLB_VECTOR 0x1400 +#define IA64_INST_KEY_MISS_VECTOR 0x1800 +#define IA64_DATA_KEY_MISS_VECTOR 0x1c00 +#define IA64_DIRTY_BIT_VECTOR 0x2000 +#define IA64_INST_ACCESS_BIT_VECTOR 0x2400 +#define IA64_DATA_ACCESS_BIT_VECTOR 0x2800 +#define IA64_BREAK_VECTOR 0x2c00 +#define IA64_EXTINT_VECTOR 0x3000 +#define IA64_PAGE_NOT_PRESENT_VECTOR 0x5000 +#define IA64_KEY_PERMISSION_VECTOR 0x5100 +#define IA64_INST_ACCESS_RIGHTS_VECTOR 0x5200 +#define IA64_DATA_ACCESS_RIGHTS_VECTOR 0x5300 +#define IA64_GENEX_VECTOR 0x5400 +#define IA64_DISABLED_FPREG_VECTOR 0x5500 +#define IA64_NAT_CONSUMPTION_VECTOR 0x5600 +#define IA64_SPECULATION_VECTOR 0x5700 /* UNUSED */ +#define IA64_DEBUG_VECTOR 0x5900 +#define IA64_UNALIGNED_REF_VECTOR 0x5a00 +#define IA64_UNSUPPORTED_DATA_REF_VECTOR 0x5b00 +#define IA64_FP_FAULT_VECTOR 0x5c00 +#define IA64_FP_TRAP_VECTOR 0x5d00 +#define IA64_LOWERPRIV_TRANSFER_TRAP_VECTOR 0x5e00 +#define IA64_TAKEN_BRANCH_TRAP_VECTOR 0x5f00 +#define IA64_SINGLE_STEP_TRAP_VECTOR 0x6000 + +/* SDM vol2 5.5 - IVA based interruption handling */ +#define INITIAL_PSR_VALUE_AT_INTERRUPTION IA64_PSR_UP_BIT| IA64_PSR_MFL_BIT|\ + IA64_PSR_MFH_BIT|IA64_PSR_PK_BIT|IA64_PSR_DT_BIT| \ + IA64_PSR_RT_BIT|IA64_PSR_MC_BIT|IA64_PSR_IT_BIT + +#define DOMN_PAL_REQUEST 0x110000 +#define DOMN_SAL_REQUEST 0x110001 + +static u64 vec2off[68] = {0x0, 0x400, 0x800, 0xc00, 0x1000, 0x1400, 0x1800, + 0x1c00, 0x2000, 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, + 0x4000, 0x4400, 0x4800, 0x4c00, 0x5000, 0x5100, 0x5200, 0x5300, 0x5400, + 0x5500, 0x5600, 0x5700, 0x5800, 0x5900, 0x5a00, 0x5b00, 0x5c00, 0x5d00, + 0x5e00, 0x5f00, 0x6000, 0x6100, 0x6200, 0x6300, 0x6400, 0x6500, 0x6600, + 0x6700, 0x6800, 0x6900, 0x6a00, 0x6b00, 0x6c00, 0x6d00, 0x6e00, 0x6f00, + 0x7000, 0x7100, 0x7200, 0x7300, 0x7400, 0x7500, 0x7600, 0x7700, 0x7800, + 0x7900, 0x7a00, 0x7b00, 0x7c00, 0x7d00, 0x7e00, 0x7f00 +}; + +static void collect_interruption(VCPU *vcpu) +{ + u64 ipsr; + u64 vdcr; + u64 vifs; + ia64_psr vpsr; + REGS *regs = vcpu_regs(vcpu); + + vpsr.val = vcpu_get_psr(vcpu); + vcpu_bsw0(vcpu); + if (vpsr.ic) { + + /* Sync mpsr id/da/dd/ss/ed bits to vipsr + * since after guest do rfi, we still want these bits on in + * mpsr + */ + + ipsr = regs->cr_ipsr; + vpsr.val = vpsr.val | (ipsr & (IA64_PSR_ID | IA64_PSR_DA + | IA64_PSR_DD | IA64_PSR_SS + | IA64_PSR_ED)); + vcpu_set_ipsr(vcpu, vpsr.val); + + /* Currently, for trap, we do not advance IIP to next + * instruction. That's because we assume caller already + * set up IIP correctly + */ + + vcpu_set_iip(vcpu , regs->cr_iip); + + /* set vifs.v to zero */ + vifs = VCPU(vcpu, ifs); + vifs &= ~IA64_IFS_V; + vcpu_set_ifs(vcpu, vifs); + + vcpu_set_iipa(vcpu, VMX(vcpu, cr_iipa)); + } + + vdcr = VCPU(vcpu, dcr); + + /* Set guest psr + * up/mfl/mfh/pk/dt/rt/mc/it keeps unchanged + * be: set to the value of dcr.be + * pp: set to the value of dcr.pp + */ + vpsr.val &= INITIAL_PSR_VALUE_AT_INTERRUPTION; + vpsr.val |= (vdcr & IA64_DCR_BE); + + /* VDCR pp bit position is different from VPSR pp bit */ + if (vdcr & IA64_DCR_PP) { + vpsr.val |= IA64_PSR_PP; + } else { + vpsr.val &= ~IA64_PSR_PP;; + } + + vcpu_set_psr(vcpu, vpsr.val); + +} + +void inject_guest_interruption(VCPU *vcpu, u64 vec) +{ + u64 viva; + REGS *regs; + ia64_isr pt_isr; + + regs = vcpu_regs(vcpu); + + /* clear cr.isr.ir (incomplete register frame)*/ + pt_isr.val = VMX(vcpu, cr_isr); + pt_isr.ir = 0; + VMX(vcpu, cr_isr) = pt_isr.val; + + collect_interruption(vcpu); + + viva = vcpu_get_iva(vcpu); + regs->cr_iip = viva + vec; +} + +static u64 vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa) +{ + ia64_rr rr, rr1; + + rr.val = vcpu_get_rr(vcpu, ifa); + rr1.val = 0; + rr1.ps = rr.ps; + rr1.rid = rr.rid; + return (rr1.val); +} + + +/* + * Set vIFA & vITIR & vIHA, when vPSR.ic =1 + * Parameter: + * set_ifa: if true, set vIFA + * set_itir: if true, set vITIR + * set_iha: if true, set vIHA + */ +void set_ifa_itir_iha(VCPU *vcpu, u64 vadr, + int set_ifa, int set_itir, int set_iha) +{ + ia64_psr vpsr; + u64 value; + + vpsr.val = VCPU(vcpu, vpsr); + /* Vol2, Table 8-1 */ + if (vpsr.ic) { + if (set_ifa) { + vcpu_set_ifa(vcpu, vadr); + } + if (set_itir) { + value = vcpu_get_itir_on_fault(vcpu, vadr); + vcpu_set_itir(vcpu, value); + } + + if (set_iha) { + value = vcpu_thash(vcpu, vadr); + vcpu_set_iha(vcpu, value); + } + } +} + +/* + * Data TLB Fault + * @ Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void dtlb_fault(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu, IA64_DATA_TLB_VECTOR); +} + +/* + * Instruction TLB Fault + * @ Instruction TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void itlb_fault (VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu, IA64_INST_TLB_VECTOR); +} + + + +/* + * Data Nested TLB Fault + * @ Data Nested TLB Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void nested_dtlb(VCPU *vcpu) +{ + inject_guest_interruption(vcpu, IA64_DATA_NESTED_TLB_VECTOR); +} + +/* + * Alternate Data TLB Fault + * @ Alternate Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void alt_dtlb(VCPU *vcpu, u64 vadr) +{ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_ALT_DATA_TLB_VECTOR); +} + + +/* + * Data TLB Fault + * @ Data TLB vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void alt_itlb(VCPU *vcpu, u64 vadr) +{ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_ALT_INST_TLB_VECTOR); +} + +/* Deal with: + * VHPT Translation Vector + */ +static void _vhpt_fault(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR, IHA*/ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 1); + inject_guest_interruption(vcpu, IA64_VHPT_TRANS_VECTOR); + + +} + +/* + * VHPT Instruction Fault + * @ VHPT Translation vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void ivhpt_fault(VCPU *vcpu, u64 vadr) +{ + _vhpt_fault(vcpu, vadr); +} + + +/* + * VHPT Data Fault + * @ VHPT Translation vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void dvhpt_fault(VCPU *vcpu, u64 vadr) +{ + _vhpt_fault(vcpu, vadr); +} + + + +/* + * Deal with: + * General Exception vector + */ +void _general_exception(VCPU *vcpu) +{ + inject_guest_interruption(vcpu, IA64_GENEX_VECTOR); +} + + +/* + * Illegal Operation Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void illegal_op(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Illegal Dependency Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void illegal_dep(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Reserved Register/Field Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void rsv_reg_field(VCPU *vcpu) +{ + _general_exception(vcpu); +} +/* + * Privileged Operation Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ + +void privilege_op(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Unimplement Data Address Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void unimpl_daddr(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* + * Privileged Register Fault + * @ General Exception Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void privilege_reg(VCPU *vcpu) +{ + _general_exception(vcpu); +} + +/* Deal with + * Nat consumption vector + * Parameter: + * vaddr: Optional, if t == REGISTER + */ +static void _nat_consumption_fault(VCPU *vcpu, u64 vadr, miss_type t) +{ + /* If vPSR.ic && t == DATA/INST, IFA */ + if (t == DATA || t == INSTRUCTION) { + /* IFA */ + set_ifa_itir_iha(vcpu, vadr, 1, 0, 0); + } + + inject_guest_interruption(vcpu, IA64_NAT_CONSUMPTION_VECTOR); +} + +/* + * IR Data Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +#if 0 + static void +ir_nat_page_consumption(VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, DATA); +} +#endif /*shadow it due to no use currently*/ + +/* + * Instruction Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void inat_page_consumption(VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, INSTRUCTION); +} + +/* + * Register Nat Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void rnat_consumption(VCPU *vcpu) +{ + _nat_consumption_fault(vcpu, 0, REGISTER); +} + +/* + * Data Nat Page Consumption Fault + * @ Nat Consumption Vector + * Refer to SDM Vol2 Table 5-6 & 8-1 + */ +void dnat_page_consumption(VCPU *vcpu, u64 vadr) +{ + _nat_consumption_fault(vcpu, vadr, DATA); +} + +/* Deal with + * Page not present vector + */ +static void __page_not_present(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_PAGE_NOT_PRESENT_VECTOR); +} + + +void data_page_not_present(VCPU *vcpu, u64 vadr) +{ + __page_not_present(vcpu, vadr); +} + + +void inst_page_not_present(VCPU *vcpu, u64 vadr) +{ + __page_not_present(vcpu, vadr); +} + + +/* Deal with + * Data access rights vector + */ +void data_access_rights(VCPU *vcpu, u64 vadr) +{ + /* If vPSR.ic, IFA, ITIR */ + set_ifa_itir_iha(vcpu, vadr, 1, 1, 0); + inject_guest_interruption(vcpu, IA64_DATA_ACCESS_RIGHTS_VECTOR); +} + +fpswa_ret_t vmm_fp_emulate(int fp_fault, void *bundle, unsigned long *ipsr, + unsigned long *fpsr, unsigned long *isr, unsigned long *pr, + unsigned long *ifs, REGS *regs) +{ + fp_state_t fp_state; + fpswa_ret_t ret; + struct kvm_vcpu *vcpu = current_vcpu; + + uint64_t old_rr7 = ia64_get_rr(7UL<<61); + + if (!vmm_fpswa_interface) + return (fpswa_ret_t) {-1, 0, 0, 0}; + + /* + * Just let fpswa driver to use hardware fp registers. + * No fp register is valid in memory. + */ + memset(&fp_state, 0, sizeof(fp_state_t)); + + /* + * unsigned long (*EFI_FPSWA) ( + * unsigned long trap_type, + * void *Bundle, + * unsigned long *pipsr, + * unsigned long *pfsr, + * unsigned long *pisr, + * unsigned long *ppreds, + * unsigned long *pifs, + * void *fp_state); + */ + /*Call host fpswa interface directly to virtualize + *guest fpswa request! + */ + ia64_set_rr(7UL << 61, vcpu->arch.host.rr[7]); + ia64_srlz_d(); + + ret = (*vmm_fpswa_interface->fpswa) (fp_fault, bundle, + ipsr, fpsr, isr, pr, ifs, &fp_state); + ia64_set_rr(7UL << 61, old_rr7); + ia64_srlz_d(); + return ret; +} + +/* + * Handle floating-point assist faults and traps for domain. + */ +unsigned long vmm_handle_fpu_swa(int fp_fault, REGS *regs, unsigned long isr) +{ + struct kvm_vcpu *v = current_vcpu; + IA64_BUNDLE bundle; + unsigned long fault_ip; + fpswa_ret_t ret; + + fault_ip = regs->cr_iip; + /* + * When the FP trap occurs, the trapping instruction is completed. + * If ipsr.ri == 0, there is the trapping instruction in previous + * bundle. + */ + if (!fp_fault && (ia64_psr(regs)->ri == 0)) + fault_ip -= 16; + + if (fetch_code(v, fault_ip, &bundle)) + return -EAGAIN; + + if (!bundle.i64[0] && !bundle.i64[1]) { + return -EACCES; + } + + ret = vmm_fp_emulate(fp_fault, &bundle, ®s->cr_ipsr, ®s->ar_fpsr, + &isr, ®s->pr, ®s->cr_ifs, regs); + return ret.status; +} + +void reflect_interruption(u64 ifa, u64 isr, u64 iim, + u64 vec, REGS *regs) +{ + u64 vector; + int status ; + VCPU *vcpu = current_vcpu; + u64 vpsr = VCPU(vcpu, vpsr); + + vector = vec2off[vec]; + + if (!(vpsr & IA64_PSR_IC) && (vector != IA64_DATA_NESTED_TLB_VECTOR)) { + panic_vm(vcpu); + return; + } + + switch (vec) { + case 32: /*IA64_FP_FAULT_VECTOR*/ + status = vmm_handle_fpu_swa(1, regs, isr); + if (!status) { + vcpu_increment_iip(vcpu); + return; + } else if (-EAGAIN == status) + return; + break; + case 33: /*IA64_FP_TRAP_VECTOR*/ + status = vmm_handle_fpu_swa(0, regs, isr); + if (!status) + return ; + else if (-EAGAIN == status) { + vcpu_decrement_iip(vcpu); + return ; + } + break; + } + + VCPU(vcpu, isr) = isr; + VCPU(vcpu, iipa) = regs->cr_iip; + if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR) + VCPU(vcpu, iim) = iim; + else { + set_ifa_itir_iha(vcpu, ifa, 1, 1, 1); + } + inject_guest_interruption(vcpu, vector); +} + +static void set_pal_call_data(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + /*FIXME:For static and stacked convention, firmware + * has put the parameters in gr28-gr31 before + * break to vmm !!*/ + + p->u.pal_data.gr28 = vcpu_get_gr(vcpu, 28); + p->u.pal_data.gr29 = vcpu_get_gr(vcpu, 29); + p->u.pal_data.gr30 = vcpu_get_gr(vcpu, 30); + p->u.pal_data.gr31 = vcpu_get_gr(vcpu, 31); + p->exit_reason = EXIT_REASON_PAL_CALL; +} + +static void set_pal_call_result(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + if (p->exit_reason == EXIT_REASON_PAL_CALL) { + vcpu_set_gr(vcpu, 8, p->u.pal_data.ret.status, 0); + vcpu_set_gr(vcpu, 9, p->u.pal_data.ret.v0, 0); + vcpu_set_gr(vcpu, 10, p->u.pal_data.ret.v1, 0); + vcpu_set_gr(vcpu, 11, p->u.pal_data.ret.v2, 0); + } else + panic_vm(vcpu); +} + +static void set_sal_call_data(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + p->u.sal_data.in0 = vcpu_get_gr(vcpu, 32); + p->u.sal_data.in1 = vcpu_get_gr(vcpu, 33); + p->u.sal_data.in2 = vcpu_get_gr(vcpu, 34); + p->u.sal_data.in3 = vcpu_get_gr(vcpu, 35); + p->u.sal_data.in4 = vcpu_get_gr(vcpu, 36); + p->u.sal_data.in5 = vcpu_get_gr(vcpu, 37); + p->u.sal_data.in6 = vcpu_get_gr(vcpu, 38); + p->u.sal_data.in7 = vcpu_get_gr(vcpu, 39); + p->exit_reason = EXIT_REASON_SAL_CALL; +} + +static void set_sal_call_result(VCPU *vcpu) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + + if (p->exit_reason == EXIT_REASON_SAL_CALL) { + vcpu_set_gr(vcpu, 8, p->u.sal_data.ret.r8, 0); + vcpu_set_gr(vcpu, 9, p->u.sal_data.ret.r9, 0); + vcpu_set_gr(vcpu, 10, p->u.sal_data.ret.r10, 0); + vcpu_set_gr(vcpu, 11, p->u.sal_data.ret.r11, 0); + } else + panic_vm(vcpu); +} + +void kvm_ia64_handle_break(unsigned long ifa, struct kvm_pt_regs *regs, + unsigned long isr, unsigned long iim) +{ + VCPU *v = current_vcpu; + + if (ia64_psr(regs)->cpl == 0) { + /* Allow hypercalls only when cpl = 0. */ + if (iim == DOMN_PAL_REQUEST) { + set_pal_call_data(v); + vmm_transition(v); + set_pal_call_result(v); + vcpu_increment_iip(v); + return; + } else if (iim == DOMN_SAL_REQUEST) { + set_sal_call_data(v); + vmm_transition(v); + set_sal_call_result(v); + vcpu_increment_iip(v); + return; + } + } + reflect_interruption(ifa, isr, iim, 11, regs); +} + +void check_pending_irq(VCPU *vcpu) +{ + int mask, h_pending, h_inservice; + u64 isr; + ia64_psr vpsr; + REGS *regs = vcpu_regs(vcpu); + + h_pending = highest_pending_irq(vcpu); + if (h_pending == NULL_VECTOR) { + update_vhpi(vcpu, NULL_VECTOR); + return; + } + h_inservice = highest_inservice_irq(vcpu); + + vpsr.val = VCPU(vcpu, vpsr); + mask = irq_masked(vcpu, h_pending, h_inservice); + if (vpsr.i && IRQ_NO_MASKED == mask) { + isr = vpsr.val & IA64_PSR_RI; + update_vhpi(vcpu, h_pending); + reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */ + } else if (mask == IRQ_MASKED_BY_INSVC) { + if (VCPU(vcpu, vhpi)) + update_vhpi(vcpu, NULL_VECTOR); + } else { + /* masked by vpsr.i or vtpr.*/ + update_vhpi(vcpu, h_pending); + } +} + +static void generate_exirq(VCPU *vcpu) +{ + ia64_psr vpsr; + uint64_t isr; + + REGS *regs = vcpu_regs(vcpu); + + vpsr.val = VCPU(vcpu, vpsr); + isr = vpsr.val & IA64_PSR_RI; + if (!vpsr.ic) + panic_vm(vcpu); + reflect_interruption(0, isr, 0, 12, regs); /* EXT IRQ */ +} + +void vhpi_detection(VCPU *vcpu) +{ + uint64_t threshold, vhpi; + tpr_t vtpr; + ia64_psr vpsr; + + vpsr.val = VCPU(vcpu, vpsr); + vtpr.val = VCPU(vcpu, tpr); + + threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic; + vhpi = VCPU(vcpu, vhpi); + if (vhpi > threshold) { + /* interrupt actived*/ + generate_exirq(vcpu); + } +} + + +void leave_hypervisor_tail(void) +{ + VCPU *v = current_vcpu; + + if (VMX(v, timer_check)) { + VMX(v, timer_check) = 0; + if (VMX(v, itc_check)) { + if (vcpu_get_itc(v) > VCPU(v, itm)) { + if (!(VCPU(v, itv) & (1 << 16))) { + vcpu_pend_interrupt(v, VCPU(v, itv) + & 0xff); + VMX(v, itc_check) = 0; + } else { + v->arch.timer_pending = 1; + } + VMX(v, last_itc) = VCPU(v, itm) + 1; + } + } + } + + rmb(); + if (v->arch.irq_new_pending) { + v->arch.irq_new_pending = 0; + VMX(v, irq_check) = 0; + check_pending_irq(v); + return; + } + if (VMX(v, irq_check)) { + VMX(v, irq_check) = 0; + vhpi_detection(v); + } +} + + +static inline void handle_lds(REGS *regs) +{ + regs->cr_ipsr |= IA64_PSR_ED; +} + +void physical_tlb_miss(VCPU *vcpu, unsigned long vadr, int type) +{ + unsigned long pte; + ia64_rr rr; + + rr.val = ia64_get_rr(vadr); + pte = vadr & _PAGE_PPN_MASK; + pte = pte | PHY_PAGE_WB; + thash_vhpt_insert(vcpu, pte, (u64)(rr.ps << 2), vadr, type); + return; +} + +void kvm_page_fault(u64 vadr , u64 vec, REGS *regs) +{ + ia64_psr vpsr; + int type; + + u64 vhpt_adr, gppa, pteval, rr, itir; + ia64_isr misr; + ia64_pta vpta; + thash_data_t *data; + VCPU *v = current_vcpu; + + vpsr.val = VCPU(v, vpsr); + misr.val = VMX(v, cr_isr); + + type = vec; + + if (is_physical_mode(v) && (!(vadr << 1 >> 62))) { + if (vec == 2) { + if (__gpfn_is_io((vadr << 1) >> (PAGE_SHIFT + 1))) { + emulate_io_inst(v, ((vadr << 1) >> 1), 4); + return; + } + } + physical_tlb_miss(v, vadr, type); + return; + } + data = vtlb_lookup(v, vadr, type); + if (data != 0) { + if (type == D_TLB) { + gppa = (vadr & ((1UL << data->ps) - 1)) + + (data->ppn >> (data->ps - 12) << data->ps); + if (__gpfn_is_io(gppa >> PAGE_SHIFT)) { + if (data->pl >= ((regs->cr_ipsr >> + IA64_PSR_CPL0_BIT) & 3)) + emulate_io_inst(v, gppa, data->ma); + else { + vcpu_set_isr(v, misr.val); + data_access_rights(v, vadr); + } + return ; + } + } + thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type); + + } else if (type == D_TLB) { + if (misr.sp) { + handle_lds(regs); + return; + } + + rr = vcpu_get_rr(v, vadr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + + if (!vhpt_enabled(v, vadr, misr.rs ? RSE_REF : DATA_REF)) { + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + alt_dtlb(v, vadr); + } else { + nested_dtlb(v); + } + return ; + } + + vpta.val = vcpu_get_pta(v); + /* avoid recursively walking (short format) VHPT */ + + vhpt_adr = vcpu_thash(v, vadr); + if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { + /* VHPT successfully read. */ + if (!(pteval & _PAGE_P)) { + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + } else { + nested_dtlb(v); + } + } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) { + thash_purge_and_insert(v, pteval, itir, + vadr, D_TLB); + } else if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + } else { + nested_dtlb(v); + } + } else { + /* Can't read VHPT. */ + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dvhpt_fault(v, vadr); + } else { + nested_dtlb(v); + } + } + } else if (type == I_TLB) { + if (!vpsr.ic) + misr.ni = 1; + if (!vhpt_enabled(v, vadr, INST_REF)) { + vcpu_set_isr(v, misr.val); + alt_itlb(v, vadr); + return; + } + + vpta.val = vcpu_get_pta(v); + + vhpt_adr = vcpu_thash(v, vadr); + if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { + /* VHPT successfully read. */ + if (pteval & _PAGE_P) { + if ((pteval & _PAGE_MA_MASK) == _PAGE_MA_ST) { + vcpu_set_isr(v, misr.val); + itlb_fault(v, vadr); + return ; + } + rr = vcpu_get_rr(v, vadr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + thash_purge_and_insert(v, pteval, itir, + vadr, I_TLB); + } else { + vcpu_set_isr(v, misr.val); + inst_page_not_present(v, vadr); + } + } else { + vcpu_set_isr(v, misr.val); + ivhpt_fault(v, vadr); + } + } +} + +void kvm_vexirq(VCPU *vcpu) +{ + u64 vpsr, isr; + REGS *regs; + + regs = vcpu_regs(vcpu); + vpsr = VCPU(vcpu, vpsr); + isr = vpsr & IA64_PSR_RI; + reflect_interruption(0, isr, 0, 12, regs); /*EXT IRQ*/ +} + +void kvm_ia64_handle_irq(VCPU *v) +{ + struct exit_ctl_data *p = &v->arch.exit_data; + long psr; + + local_irq_save(psr); + p->exit_reason = EXIT_REASON_EXTERNAL_INTERRUPT; + vmm_transition(v); + local_irq_restore(psr); + + VMX(v, timer_check) = 1; + +} + +static void ptc_ga_remote_func(struct kvm_vcpu *v, int pos) +{ + u64 oldrid, moldrid, oldpsbits, vaddr; + struct kvm_ptc_g *p = &v->arch.ptc_g_data[pos]; + vaddr = p->vaddr; + + oldrid = VMX(v, vrr[0]); + VMX(v, vrr[0]) = p->rr; + oldpsbits = VMX(v, psbits[0]); + VMX(v, psbits[0]) = VMX(v, psbits[REGION_NUMBER(vaddr)]); + moldrid = ia64_get_rr(0x0); + ia64_set_rr(0x0, vrrtomrr(p->rr)); + ia64_srlz_d(); + + vaddr = PAGEALIGN(vaddr, p->ps); + thash_purge_entries_remote(v, vaddr, p->ps); + + VMX(v, vrr[0]) = oldrid; + VMX(v, psbits[0]) = oldpsbits; + ia64_set_rr(0x0, moldrid); + ia64_dv_serialize_data(); +} + +static void vcpu_do_resume(struct kvm_vcpu *vcpu) +{ + /*Re-init VHPT and VTLB once from resume*/ + vcpu->arch.vhpt.num = VHPT_NUM_ENTRIES; + thash_init(&vcpu->arch.vhpt, VHPT_SHIFT); + vcpu->arch.vtlb.num = VTLB_NUM_ENTRIES; + thash_init(&vcpu->arch.vtlb, VTLB_SHIFT); + + ia64_set_pta(vcpu->arch.vhpt.pta.val); +} + +static void kvm_do_resume_op(struct kvm_vcpu *vcpu) +{ + if (test_and_clear_bit(KVM_REQ_RESUME, &vcpu->requests)) { + vcpu_do_resume(vcpu); + return; + } + + if (unlikely(test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests))) { + thash_purge_all(vcpu); + return; + } + + if (test_and_clear_bit(KVM_REQ_PTC_G, &vcpu->requests)) { + while (vcpu->arch.ptc_g_count > 0) + ptc_ga_remote_func(vcpu, --vcpu->arch.ptc_g_count); + } +} + +void vmm_transition(struct kvm_vcpu *vcpu) +{ + ia64_call_vsa(PAL_VPS_SAVE, (unsigned long)vcpu->arch.vpd, + 0, 0, 0, 0, 0, 0); + vmm_trampoline(&vcpu->arch.guest, &vcpu->arch.host); + ia64_call_vsa(PAL_VPS_RESTORE, (unsigned long)vcpu->arch.vpd, + 0, 0, 0, 0, 0, 0); + kvm_do_resume_op(vcpu); -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:42:12
|
>From 454e8a4473ed13ce313b2ba3b654feb926a891b7 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:57:33 +0800 Subject: [PATCH] kvm/ia64: How to boot up guests on kvm/ia64 Signed-off-by: Xiantao Zhang <xia...@in...> --- Documentation/ia64/kvm-howto.txt | 74 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 74 insertions(+), 0 deletions(-) create mode 100644 Documentation/ia64/kvm-howto.txt diff --git a/Documentation/ia64/kvm-howto.txt b/Documentation/ia64/kvm-howto.txt new file mode 100644 index 0000000..5a8049c --- /dev/null +++ b/Documentation/ia64/kvm-howto.txt @@ -0,0 +1,74 @@ + Guide: How to boot up guests on kvm/ia64 + +1. Get the kvm source from git.kernel.org. + Userspace source: + git clone git://git.kernel.org/pub/scm/virt/kvm/kvm-userspace.git + Kernel Source: + git clone git://git.kernel.org/pub/scm/linux/kernel/git/xiantao/kvm-ia64.git + +2. Compile the source code. + 2.1 Compile userspace code: + (1)cd ./kvm-userspace + (2)./configure + (3)cd kernel + (4)make sync LINUX= $kernel_dir (kernel_dir is the directory of kernel source.) + (5)cd .. + (6)make qemu + (7)cd qemu; make install + + 2.2 Compile kernel source code: + (1) cd ./$kernel_dir + (2) Make menuconfig + (3) Enter into virtualization option, and choose kvm. + (4) make + (5) Once (4) done, make modules_install + (6) Make initrd, and use new kernel to reboot up host machine. + (7) Once (6) done, cd $kernel_dir/arch/ia64/kvm + (8) insmod kvm.ko; insmod kvm-intel.ko + +Note: For step 2, please make sure that host page size == TARGET_PAGE_SIZE of qemu, otherwise, may fail. + +3. Get Guest Firmware named as Flash.fd, and put it under right place: + (1) If you have the guest firmware (binary)released by Intel Corp for Xen, you can use it directly. + (2) If you want to build a guest firmware form source code. Please download the source from + hg clone http://xenbits.xensource.com/ext/efi-vfirmware.hg + Use the Guide of the source to build open Guest Firmware. + (3) Rename it to Flash.fd, and copy it to /usr/local/share/qemu +Note: For step 3, kvm use the guest firmware which complies with the one Xen uses. + +4. Boot up Linux or Windows guests: + 4.1 Create or install a image for guest boot. If you have xen experience, it should be easy. + + 4.2 Boot up guests use the following command. + /usr/local/bin/qemu-system-ia64 -smp xx -m 512 -hda $your_image + (xx is the number of virtual processors for the guest, now the maximum value is 4) + +5. Known possibile issue on some platforms with old Firmware + +If meet strange host crashes, you may try to solve it through either of the following methods. +(1): Upgrade your Firmware to the latest one. + +(2): Applying the below patch to kernel source. +diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S +index 0b53344..f02b0f7 100644 +--- a/arch/ia64/kernel/pal.S ++++ b/arch/ia64/kernel/pal.S +@@ -84,7 +84,8 @@ GLOBAL_ENTRY(ia64_pal_call_static) + mov ar.pfs = loc1 + mov rp = loc0 + ;; +- srlz.d // serialize restoration of psr.l ++ srlz.i // serialize restoration of psr.l ++ ;; + br.ret.sptk.many b0 + END(ia64_pal_call_static) + +6. Bug report: + If you found any issues when use kvm/ia64, Please post the bug info to kvm-ia64-devel mailing list. + https://lists.sourceforge.net/lists/listinfo/kvm-ia64-devel/ + +Thanks for your interest! Let's work together, and make kvm/ia64 stronger and stronger! + + + Xiantao Zhang <xia...@in...> + 2008.3.10 -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:39:16
|
Compared with V6, 1. Updated the PATCH 01 according to Tony's comments. 2. Updated the PATCH 14 according to Akio's comments. 3. Updated the PATCH 17 according to Akio's comments. The latest patchset is located at git://git.kernel.org/pub/scm/linux/kernel/git/xiantao/kvm-ia64.git kvm-ia64-mc7. Pelase have a review! Xiantao |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:22:24
|
Akio Takebe wrote: > Hi, > > I found 3 typos. > >> +3. Get Guest Firmware named as Flash.fd, and put it under right >> place: + (1) If you have the guest firmware (binary)released by Intel >> Corp for Xen, you can use it directly. >> + (2) If you want to build a guest firmware form souce code. souce >> ---> source > >> +5. Known possbile issue on some platforms with old Firmware >> + > possbile ---> possible > >> +(2): Applying the below patch to kernel source. >> +diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S >> +index 0b53344..f02b0f7 100644 >> +--- a/arch/ia64/kernel/pal.S >> ++++ b/arch/ia64/kernel/pal.S >> +@@ -84,7 +84,8 @@ GLOBAL_ENTRY(ia64_pal_call_static) + mov ar.pfs >> = loc1 + mov rp = loc0 >> + ;; >> +- srlz.d // seralize restoration of psr.l >> ++ srlz.i // seralize restoration of psr.l seralize ---> serialize Good finding. The last one is copied from kernel, maybe need a patch to fix it :) Xiantao |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:20:52
|
Akio Takebe wrote: > Hi, Xiantao and Anthony > >> +void getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, >> + struct kvm_pt_regs *regs) >> +{ >> + /* Take floating register rotation into consideration*/ >> + if (regnum >= IA64_FIRST_ROTATING_FR) >> + regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, >> regnum); >> +#define CASE_FIXED_FP(reg) \ >> + case (reg) : \ >> + ia64_stf_spill(fpval, reg); \ >> + break >> + >> + switch (regnum) { >> + CASE_FIXED_FP(0); >> + CASE_FIXED_FP(1); >> + CASE_FIXED_FP(2); >> + CASE_FIXED_FP(3); >> + CASE_FIXED_FP(4); >> + CASE_FIXED_FP(5); >> + >> + CASE_FIXED_FP(6); >> + CASE_FIXED_FP(7); >> + CASE_FIXED_FP(8); >> + CASE_FIXED_FP(9); >> + CASE_FIXED_FP(10); >> + CASE_FIXED_FP(11); >> + > Is this correct ? Though I don't know why xen do so. > In the case of Xen, the above parts are; > > #define CASE_SAVED_FP(reg) \ > case reg: \ > fpval->u.bits[0] = regs->f##reg.u.bits[0]; \ > fpval->u.bits[1] = regs->f##reg.u.bits[1]; \ > break > > CASE_SAVED_FP(6); > CASE_SAVED_FP(7); > CASE_SAVED_FP(8); > Hi, Akio Current should be correct, because for every host<-> guest switch, we switched FPU accordingly. So the fpu register file is dedicated for current vm, getting it from physical register should be right. But for xen's code, due to lazy fpu save/restore, current fpu register file maybe not belong to current vcpu, so need to load it from stack. Thanks Xiantao |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:18:33
|
INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 >> + > Xen also use this value, you had better use macros of PSR bits. > Or you can add the same comments as Xen. Hi, Akio. The comment is where it is used. Anyway, using macro is better. Changed. |
From: Zhang, X. <xia...@in...> - 2008-03-29 02:05:12
|
Akio Takebe wrote: > Hi, Xiantao > > a comments is below. > > >> +// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) >> +ENTRY(kvm_interrupt) + mov r31=pr // prepare to save predicates >> + mov r19=12 >> + mov r29=cr.ipsr >> + ;; >> + tbit.z p6,p7=r29,IA64_PSR_VM_BIT >> + tbit.z p0,p15=r29,IA64_PSR_I_BIT >> + ;; >> +(p7) br.sptk kvm_dispatch_interrupt >> + ;; >> + mov r27=ar.rsc /* M */ >> + mov r20=r1 /* A */ >> + mov r25=ar.unat /* M */ >> + mov r26=ar.pfs /* I */ >> + mov r28=cr.iip /* M */ >> + cover /* B (or nothing) */ >> + ;; >> + mov r1=sp >> + ;; >> + invala /* M */ >> + mov r30=cr.ifs >> + ;; >> + addl r1=-VMM_PT_REGS_SIZE,r1 >> + ;; >> + adds r17=2*L1_CACHE_BYTES,r1 /* really: biggest cache-line size >> */ + adds r16=PT(CR_IPSR),r1 >> + ;; >> + lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES >> + st8 [r16]=r29 /* save cr.ipsr */ >> + ;; >> + lfetch.fault.excl.nt1 [r17] >> + mov r29=b0 >> + ;; >> + adds r16=PT(R8),r1 /* initialize first base pointer */ >> + adds r17=PT(R9),r1 /* initialize second base pointer */ >> + mov r18=r0 /* make sure r18 isn't NaT */ + ;; >> +.mem.offset 0,0; st8.spill [r16]=r8,16 >> +.mem.offset 8,0; st8.spill [r17]=r9,16 >> + ;; >> +.mem.offset 0,0; st8.spill [r16]=r10,24 >> +.mem.offset 8,0; st8.spill [r17]=r11,24 >> + ;; >> + st8 [r16]=r28,16 /* save cr.iip */ >> + st8 [r17]=r30,16 /* save cr.ifs */ >> + mov r8=ar.fpsr /* M */ >> + mov r9=ar.csd >> + mov r10=ar.ssd >> + movl r11=FPSR_DEFAULT /* L-unit */ >> + ;; >> + st8 [r16]=r25,16 /* save ar.unat */ >> + st8 [r17]=r26,16 /* save ar.pfs */ >> + shl r18=r18,16 /* compute ar.rsc to be used for "loadrs" */ >> + ;; >> + st8 [r16]=r27,16 /* save ar.rsc */ >> + adds r17=16,r17 /* skip over ar_rnat field */ + ;; >> + st8 [r17]=r31,16 /* save predicates */ >> + adds r16=16,r16 /* skip over ar_bspstore field */ + ;; >> + st8 [r16]=r29,16 /* save b0 */ >> + st8 [r17]=r18,16 /* save ar.rsc value for "loadrs" */ + ;; >> +.mem.offset 0,0; st8.spill [r16]=r20,16 /* save original r1 */ >> +.mem.offset 8,0; st8.spill [r17]=r12,16 >> + adds r12=-16,r1 >> + /* switch to kernel memory stack (with 16 bytes of scratch) */ >> + ;; +.mem.offset 0,0; st8.spill [r16]=r13,16 >> +.mem.offset 8,0; st8.spill [r17]=r8,16 /* save ar.fpsr */ + ;; >> +.mem.offset 0,0; st8.spill [r16]=r15,16 >> +.mem.offset 8,0; st8.spill [r17]=r14,16 >> + dep r14=-1,r0,60,4 >> + ;; >> +.mem.offset 0,0; st8.spill [r16]=r2,16 >> +.mem.offset 8,0; st8.spill [r17]=r3,16 >> + adds r2=VMM_PT_REGS_R16_OFFSET,r1 >> + adds r14 = VMM_VCPU_GP_OFFSET,r13 >> + ;; >> + mov r8=ar.ccv >> + ld8 r14 = [r14] >> + ;; >> + mov r1=r14 /* establish kernel global pointer */ >> + ;; \ >> + bsw.1 >> + ;; >> + alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group + >> mov out0=r13 + ;; >> + ssm psr.ic >> + ;; >> + srlz.i >> + ;; >> + //(p15) ssm psr.i > Why do you comments out some ssm psr.i? >> + adds r3=8,r2 // set up second base pointer for >> SAVE_REST >> + srlz.i // ensure everybody knows psr.ic is back >> on > Hmm, if the above ssm is not necessary, this srlz.i is also necessary. Currently, we didn't enable psr.i in GVMM, since all external interrupts should back to host. But for next step, we want to add the psr.i = 1 support in GVMM. The final decision should be based on performance evaluation, and to see whether it has impact on the performance of host and guest side. Now I want to keep it there as a tag. Xiantao |
From: Jes S. <je...@sg...> - 2008-03-28 17:07:48
|
Zhang, Xiantao wrote: > Hi, Jes > Seems it is caused by network support. Due to one bug not addressed > in slirp support, I disabled it in configure, but it could cause issues > once enable networking support. > I remembed one patch from Scott is targeted to address slirp issue on > some 64 bit platform, but don't know why it doesn't get pickup. > Attached the patch. Hi Xiantao, I haven't had a chance to try your patch yet, but it seems that it's crashing while trying to copy the firmware image. It's basically dying in ipf_init1() in this memcpy, around line 487: { fw_start = kvm_create_phys_mem(kvm_context, (uint32_t)(-image_size), image_size, 0, 1); if (!fw_start) exit(1); fw_image_start = fw_start + GFW_SIZE - image_size; memcpy(fw_image_start, image, image_size); <=== Cheers, Jes |
From: Akio T. <tak...@jp...> - 2008-03-28 14:39:37
|
Hi, I found 3 typos. >+3. Get Guest Firmware named as Flash.fd, and put it under right place: >+ (1) If you have the guest firmware (binary)released by Intel >Corp for Xen, you can use it directly. >+ (2) If you want to build a guest firmware form souce code. souce ---> source >+5. Known possbile issue on some platforms with old Firmware >+ possbile ---> possible >+(2): Applying the below patch to kernel source. >+diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S >+index 0b53344..f02b0f7 100644 >+--- a/arch/ia64/kernel/pal.S >++++ b/arch/ia64/kernel/pal.S >+@@ -84,7 +84,8 @@ GLOBAL_ENTRY(ia64_pal_call_static) >+ mov ar.pfs = loc1 >+ mov rp = loc0 >+ ;; >+- srlz.d // seralize restoration of psr.l >++ srlz.i // seralize restoration of psr.l seralize ---> serialize Best Regards, Akio Takebe |
From: Akio T. <tak...@jp...> - 2008-03-28 14:34:42
|
Hi, >>From 2dbf7c93ff5e36a221761c690ff12e7be48a6bb2 Mon Sep 17 00:00:00 2001 >From: Xiantao Zhang <xia...@in...> >Date: Wed, 12 Mar 2008 13:49:38 +0800 >Subject: [PATCH] kvm/ia64: add optimization for some virtulization >faults > >optvfault.S adds optimization for some performance-critical >virtualization >faults. >Signed-off-by: Anthony Xu <ant...@in...> >Signed-off-by: Xiantao Zhang <xia...@in...> It looks good. Best Regards, Akio Takebe |
From: Akio T. <tak...@jp...> - 2008-03-28 14:06:59
|
Hi, Xiantao and Anthony >+void getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, >+ struct kvm_pt_regs *regs) >+{ >+ /* Take floating register rotation into consideration*/ >+ if (regnum >= IA64_FIRST_ROTATING_FR) >+ regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, >regnum); >+#define CASE_FIXED_FP(reg) \ >+ case (reg) : \ >+ ia64_stf_spill(fpval, reg); \ >+ break >+ >+ switch (regnum) { >+ CASE_FIXED_FP(0); >+ CASE_FIXED_FP(1); >+ CASE_FIXED_FP(2); >+ CASE_FIXED_FP(3); >+ CASE_FIXED_FP(4); >+ CASE_FIXED_FP(5); >+ >+ CASE_FIXED_FP(6); >+ CASE_FIXED_FP(7); >+ CASE_FIXED_FP(8); >+ CASE_FIXED_FP(9); >+ CASE_FIXED_FP(10); >+ CASE_FIXED_FP(11); >+ Is this correct ? Though I don't know why xen do so. In the case of Xen, the above parts are; #define CASE_SAVED_FP(reg) \ case reg: \ fpval->u.bits[0] = regs->f##reg.u.bits[0]; \ fpval->u.bits[1] = regs->f##reg.u.bits[1]; \ break CASE_SAVED_FP(6); CASE_SAVED_FP(7); CASE_SAVED_FP(8); CASE_SAVED_FP(9); CASE_SAVED_FP(10); CASE_SAVED_FP(11); >+void setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, >+ struct kvm_pt_regs *regs) >+{ >+ /* Take floating register rotation into consideration*/ >+ if (regnum >= IA64_FIRST_ROTATING_FR) >+ regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, >regnum); >+ >+#define CASE_FIXED_FP(reg) \ >+ case (reg) : \ >+ ia64_ldf_fill(reg, fpval); \ >+ break >+ >+ switch (regnum) { >+ CASE_FIXED_FP(2); >+ CASE_FIXED_FP(3); >+ CASE_FIXED_FP(4); >+ CASE_FIXED_FP(5); >+ >+ CASE_FIXED_FP(6); >+ CASE_FIXED_FP(7); >+ CASE_FIXED_FP(8); >+ CASE_FIXED_FP(9); >+ CASE_FIXED_FP(10); >+ CASE_FIXED_FP(11); >+ ditto. #define CASE_RESTORED_FP(reg) \ case reg: \ regs->f##reg.u.bits[0] = fpval->u.bits[0]; \ regs->f##reg.u.bits[1] = fpval->u.bits[1] ; \ break CASE_RESTORED_FP(6); CASE_RESTORED_FP(7); CASE_RESTORED_FP(8); CASE_RESTORED_FP(9); CASE_RESTORED_FP(10); CASE_RESTORED_FP(11); Best Regards, Akio Takebe |
From: Akio T. <tak...@jp...> - 2008-03-28 13:01:15
|
Hi, Xiantao a comments is below. >+// 0x3000 Entry 12 (size 64 bundles) External Interrupt (4) >+ENTRY(kvm_interrupt) >+ mov r31=pr // prepare to save predicates >+ mov r19=12 >+ mov r29=cr.ipsr >+ ;; >+ tbit.z p6,p7=r29,IA64_PSR_VM_BIT >+ tbit.z p0,p15=r29,IA64_PSR_I_BIT >+ ;; >+(p7) br.sptk kvm_dispatch_interrupt >+ ;; >+ mov r27=ar.rsc /* M */ >+ mov r20=r1 /* A */ >+ mov r25=ar.unat /* M */ >+ mov r26=ar.pfs /* I */ >+ mov r28=cr.iip /* M */ >+ cover /* B (or nothing) */ >+ ;; >+ mov r1=sp >+ ;; >+ invala /* M */ >+ mov r30=cr.ifs >+ ;; >+ addl r1=-VMM_PT_REGS_SIZE,r1 >+ ;; >+ adds r17=2*L1_CACHE_BYTES,r1 /* really: biggest cache-line >size */ >+ adds r16=PT(CR_IPSR),r1 >+ ;; >+ lfetch.fault.excl.nt1 [r17],L1_CACHE_BYTES >+ st8 [r16]=r29 /* save cr.ipsr */ >+ ;; >+ lfetch.fault.excl.nt1 [r17] >+ mov r29=b0 >+ ;; >+ adds r16=PT(R8),r1 /* initialize first base pointer */ >+ adds r17=PT(R9),r1 /* initialize second base pointer */ >+ mov r18=r0 /* make sure r18 isn't NaT */ >+ ;; >+.mem.offset 0,0; st8.spill [r16]=r8,16 >+.mem.offset 8,0; st8.spill [r17]=r9,16 >+ ;; >+.mem.offset 0,0; st8.spill [r16]=r10,24 >+.mem.offset 8,0; st8.spill [r17]=r11,24 >+ ;; >+ st8 [r16]=r28,16 /* save cr.iip */ >+ st8 [r17]=r30,16 /* save cr.ifs */ >+ mov r8=ar.fpsr /* M */ >+ mov r9=ar.csd >+ mov r10=ar.ssd >+ movl r11=FPSR_DEFAULT /* L-unit */ >+ ;; >+ st8 [r16]=r25,16 /* save ar.unat */ >+ st8 [r17]=r26,16 /* save ar.pfs */ >+ shl r18=r18,16 /* compute ar.rsc to be used for >"loadrs" */ >+ ;; >+ st8 [r16]=r27,16 /* save ar.rsc */ >+ adds r17=16,r17 /* skip over ar_rnat field */ >+ ;; >+ st8 [r17]=r31,16 /* save predicates */ >+ adds r16=16,r16 /* skip over ar_bspstore field */ >+ ;; >+ st8 [r16]=r29,16 /* save b0 */ >+ st8 [r17]=r18,16 /* save ar.rsc value for "loadrs" */ >+ ;; >+.mem.offset 0,0; st8.spill [r16]=r20,16 /* save original r1 */ >+.mem.offset 8,0; st8.spill [r17]=r12,16 >+ adds r12=-16,r1 >+ /* switch to kernel memory stack (with 16 bytes of scratch) */ >+ ;; >+.mem.offset 0,0; st8.spill [r16]=r13,16 >+.mem.offset 8,0; st8.spill [r17]=r8,16 /* save ar.fpsr */ >+ ;; >+.mem.offset 0,0; st8.spill [r16]=r15,16 >+.mem.offset 8,0; st8.spill [r17]=r14,16 >+ dep r14=-1,r0,60,4 >+ ;; >+.mem.offset 0,0; st8.spill [r16]=r2,16 >+.mem.offset 8,0; st8.spill [r17]=r3,16 >+ adds r2=VMM_PT_REGS_R16_OFFSET,r1 >+ adds r14 = VMM_VCPU_GP_OFFSET,r13 >+ ;; >+ mov r8=ar.ccv >+ ld8 r14 = [r14] >+ ;; >+ mov r1=r14 /* establish kernel global pointer */ >+ ;; \ >+ bsw.1 >+ ;; >+ alloc r14=ar.pfs,0,0,1,0 // must be first in an insn group >+ mov out0=r13 >+ ;; >+ ssm psr.ic >+ ;; >+ srlz.i >+ ;; >+ //(p15) ssm psr.i Why do you comments out some ssm psr.i? >+ adds r3=8,r2 // set up second base pointer for >SAVE_REST >+ srlz.i // ensure everybody knows psr.ic is back >on Hmm, if the above ssm is not necessary, this srlz.i is also necessary. Best Regards, Akio Takebe |
From: Akio T. <tak...@jp...> - 2008-03-28 12:36:03
|
Hi, Xiantao It's good, I have some small comments. >+ >+/* SDM vol2 5.5 - IVA based interruption handling */ >+#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 >+ Xen also use this value, you had better use macros of PSR bits. Or you can add the same comments as Xen. >+ >+/* >+ * Handle floating-point assist faults and traps for domain. >+ */ >+unsigned long vmm_handle_fpu_swa(int fp_fault, REGS *regs, unsigned >long isr) >+{ >+ struct kvm_vcpu *v = current_vcpu; >+ IA64_BUNDLE bundle; >+ unsigned long fault_ip; >+ fpswa_ret_t ret; >+ >+ fault_ip = regs->cr_iip; >+ /* >+ * When the FP trap occurs, the trapping instruction is >completed. >+ * If ipsr.ri == 0, there is the trapping instruction in >previous >+ * bundle. >+ */ >+ if (!fp_fault && (ia64_psr(regs)->ri == 0)) >+ fault_ip -= 16; >+ >+ if (fetch_code(v, fault_ip, &bundle)) >+ return -EAGAIN; >+ >+ if (!bundle.i64[0] && !bundle.i64[1]) { >+ return -EACCES; >+ } >+ >+ ret = vmm_fp_emulate(fp_fault, &bundle, ®s->cr_ipsr, >®s->ar_fpsr, >+ &isr, ®s->pr, ®s->cr_ifs, regs); >+ return ret.status; >+} >+ >+void reflect_interruption(u64 ifa, u64 isr, u64 iim, >+ u64 vec, REGS *regs) >+{ >+ u64 vector; >+ int status ; >+ VCPU *vcpu = current_vcpu; >+ u64 vpsr = VCPU(vcpu, vpsr); >+ >+ vector = vec2off[vec]; >+ >+ if (!(vpsr & IA64_PSR_IC) && (vector != >IA64_DATA_NESTED_TLB_VECTOR)) { >+ panic_vm(vcpu); >+ return; >+ } >+ >+ switch (vec) { >+ case 32: I want to add a comment of IA64_FP_FAULT_VECTOR. >+ status = vmm_handle_fpu_swa(1, regs, isr); >+ if (!status) { >+ vcpu_increment_iip(vcpu); >+ return; >+ } else if (-EAGAIN == status) >+ return; >+ break; >+ case 33: ditto, I want to add a comments of IA64_FP_TRAP_VECTOR. >+ status = vmm_handle_fpu_swa(0, regs, isr); >+ if (!status) >+ return ; >+ else if (-EAGAIN == status) { >+ vcpu_decrement_iip(vcpu); >+ return ; >+ } >+ break; >+ } >+ >+ VCPU(vcpu, isr) = isr; >+ VCPU(vcpu, iipa) = regs->cr_iip; >+ if (vector == IA64_BREAK_VECTOR || vector == >IA64_SPECULATION_VECTOR) >+ VCPU(vcpu, iim) = iim; >+ else { >+ set_ifa_itir_iha(vcpu, ifa, 1, 1, 1); >+ } >+ inject_guest_interruption(vcpu, vector); >+} >+ > Best Regards, Akio Takebe |
From: Zhang, X. <xia...@in...> - 2008-03-28 10:28:36
|
Jes Sorensen wrote: > Zhang, Xiantao wrote: >> Hi, Jes >> Could you check your build step by step? :) >> 1. Checkout latest source, and apply the attached patch. >> 2. ./configure --disable-cpu-emulation >> 3. cd kernel >> 4. make sync Linux=$kvm_kernel_dir >> kvm_kernel_dir = the kernel directory of kvm-ia64.git >> 5. cd .. >> 6. make qemu > > Hi Xiantao, > > Thanks for the instructions, with this I finally managed to build > qemu. However, it gets more fun, I am not getting this when I try to > run :( At least there's something I can start debugging. Hi, Jes Seems it is caused by network support. Due to one bug not addressed in slirp support, I disabled it in configure, but it could cause issues once enable networking support. I remembed one patch from Scott is targeted to address slirp issue on some 64 bit platform, but don't know why it doesn't get pickup. Attached the patch. If you want to apply it, please set slirp=''yes" in qemu's configuration first. Xiantao |
From: Zhang, X. <xia...@in...> - 2008-03-28 10:07:17
|
>From cd6d41cd4c8b86e84455ef90514c0e9226f37979 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:48:59 +0800 Subject: [PATCH] kvm/ia64: add processor virtulization support. vcpu.c provides processor virtualization logic. Signed-off-by: Anthony Xu <ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/vcpu.c | 2145 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 2145 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/vcpu.c diff --git a/arch/ia64/kvm/vcpu.c b/arch/ia64/kvm/vcpu.c new file mode 100644 index 0000000..729647b --- /dev/null +++ b/arch/ia64/kvm/vcpu.c @@ -0,0 +1,2145 @@ +/* + * kvm_vcpu.c: handling all virtual cpu related thing. + * Copyright (c) 2005, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Shaofan Li (Susue Li) <sus...@in...> + * Yaozu Dong (Eddie Dong) (Edd...@in...) + * Xuefei Xu (Anthony Xu) (Ant...@in...) + * Xiantao Zhang <xia...@in...> + */ + +#include <linux/kvm_host.h> + +#include <asm/types.h> +#include <asm/processor.h> +#include <asm/ia64regs.h> +#include <asm/gcc_intrin.h> +#include <asm/kregs.h> +#include <asm/pgtable.h> + + +#include "asm-offsets.h" +#include "vcpu.h" + +/* + * Special notes: + * - Index by it/dt/rt sequence + * - Only existing mode transitions are allowed in this table + * - RSE is placed at lazy mode when emulating guest partial mode + * - If gva happens to be rr0 and rr4, only allowed case is identity + * mapping (gva=gpa), or panic! (How?) + */ +int mm_switch_table[8][8] = { + /* 2004/09/12(Kevin): Allow switch to self */ + /* + * (it,dt,rt): (0,0,0) -> (1,1,1) + * This kind of transition usually occurs in the very early + * stage of Linux boot up procedure. Another case is in efi + * and pal calls. (see "arch/ia64/kernel/head.S") + * + * (it,dt,rt): (0,0,0) -> (0,1,1) + * This kind of transition is found when OSYa exits efi boot + * service. Due to gva = gpa in this case (Same region), + * data access can be satisfied though itlb entry for physical + * emulation is hit. + */ + {SW_SELF, 0, 0, SW_NOP, 0, 0, 0, SW_P2V}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + /* + * (it,dt,rt): (0,1,1) -> (1,1,1) + * This kind of transition is found in OSYa. + * + * (it,dt,rt): (0,1,1) -> (0,0,0) + * This kind of transition is found in OSYa + */ + {SW_NOP, 0, 0, SW_SELF, 0, 0, 0, SW_P2V}, + /* (1,0,0)->(1,1,1) */ + {0, 0, 0, 0, 0, 0, 0, SW_P2V}, + /* + * (it,dt,rt): (1,0,1) -> (1,1,1) + * This kind of transition usually occurs when Linux returns + * from the low level TLB miss handlers. + * (see "arch/ia64/kernel/ivt.S") + */ + {0, 0, 0, 0, 0, SW_SELF, 0, SW_P2V}, + {0, 0, 0, 0, 0, 0, 0, 0}, + /* + * (it,dt,rt): (1,1,1) -> (1,0,1) + * This kind of transition usually occurs in Linux low level + * TLB miss handler. (see "arch/ia64/kernel/ivt.S") + * + * (it,dt,rt): (1,1,1) -> (0,0,0) + * This kind of transition usually occurs in pal and efi calls, + * which requires running in physical mode. + * (see "arch/ia64/kernel/head.S") + * (1,1,1)->(1,0,0) + */ + + {SW_V2P, 0, 0, 0, SW_V2P, SW_V2P, 0, SW_SELF}, +}; + +void physical_mode_init(VCPU *vcpu) +{ + vcpu->arch.mode_flags = GUEST_IN_PHY; +} + +extern void kvm_switch_rr6(unsigned long, void *, void *, void *); + + +void switch_to_physical_rid(VCPU *vcpu) +{ + unsigned long psr; + + /* Save original virtual mode rr[0] and rr[4] */ + psr = ia64_clear_ic(); + ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_rr0); + ia64_srlz_d(); + ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_rr4); + ia64_srlz_d(); + + ia64_set_psr(psr); + return; +} + + +void switch_to_virtual_rid(VCPU *vcpu) +{ + unsigned long psr; + + psr = ia64_clear_ic(); + ia64_set_rr(VRN0 << VRN_SHIFT, vcpu->arch.metaphysical_saved_rr0); + ia64_srlz_d(); + ia64_set_rr(VRN4 << VRN_SHIFT, vcpu->arch.metaphysical_saved_rr4); + ia64_srlz_d(); + ia64_set_psr(psr); + return; +} + +static int mm_switch_action(ia64_psr opsr, ia64_psr npsr) +{ + return mm_switch_table[MODE_IND(opsr)][MODE_IND(npsr)]; +} + +void switch_mm_mode(VCPU *vcpu, ia64_psr old_psr, ia64_psr new_psr) +{ + int act; + act = mm_switch_action(old_psr, new_psr); + switch (act) { + case SW_V2P: + /*printk("V -> P mode transition: (0x%lx -> 0x%lx)\n", + old_psr.val, new_psr.val);*/ + switch_to_physical_rid(vcpu); + /* + * Set rse to enforced lazy, to prevent active rse + *save/restor when guest physical mode. + */ + vcpu->arch.mode_flags |= GUEST_IN_PHY; + break; + case SW_P2V: + switch_to_virtual_rid(vcpu); + /* + * recover old mode which is saved when entering + * guest physical mode + */ + vcpu->arch.mode_flags &= ~GUEST_IN_PHY; + break; + case SW_SELF: + break; + case SW_NOP: + break; + default: + /* Sanity check */ + break; + } + return; +} + + + +/* + * In physical mode, insert tc/tr for region 0 and 4 uses + * RID[0] and RID[4] which is for physical mode emulation. + * However what those inserted tc/tr wants is rid for + * virtual mode. So original virtual rid needs to be restored + * before insert. + * + * Operations which required such switch include: + * - insertions (itc.*, itr.*) + * - purges (ptc.* and ptr.*) + * - tpa + * - tak + * - thash?, ttag? + * All above needs actual virtual rid for destination entry. + */ + +void check_mm_mode_switch(VCPU *vcpu, ia64_psr old_psr, ia64_psr new_psr) +{ + + if ((old_psr.dt != new_psr.dt) + || (old_psr.it != new_psr.it) + || (old_psr.rt != new_psr.rt)) + switch_mm_mode(vcpu, old_psr, new_psr); + + return; +} + + +/* + * In physical mode, insert tc/tr for region 0 and 4 uses + * RID[0] and RID[4] which is for physical mode emulation. + * However what those inserted tc/tr wants is rid for + * virtual mode. So original virtual rid needs to be restored + * before insert. + * + * Operations which required such switch include: + * - insertions (itc.*, itr.*) + * - purges (ptc.* and ptr.*) + * - tpa + * - tak + * - thash?, ttag? + * All above needs actual virtual rid for destination entry. + */ + +void prepare_if_physical_mode(VCPU *vcpu) +{ + if (is_physical_mode(vcpu)) { + vcpu->arch.mode_flags |= GUEST_PHY_EMUL; + switch_to_virtual_rid(vcpu); + } + return; +} + +/* Recover always follows prepare */ +void recover_if_physical_mode(VCPU *vcpu) +{ + if (is_physical_mode(vcpu)) + switch_to_physical_rid(vcpu); + vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL; + return; +} + +#define RPT(x) ((u16) &((struct kvm_pt_regs *)0)->x) + +static u16 gr_info[32] = { + 0, /* r0 is read-only : WE SHOULD NEVER GET THIS */ + RPT(r1), RPT(r2), RPT(r3), + RPT(r4), RPT(r5), RPT(r6), RPT(r7), + RPT(r8), RPT(r9), RPT(r10), RPT(r11), + RPT(r12), RPT(r13), RPT(r14), RPT(r15), + RPT(r16), RPT(r17), RPT(r18), RPT(r19), + RPT(r20), RPT(r21), RPT(r22), RPT(r23), + RPT(r24), RPT(r25), RPT(r26), RPT(r27), + RPT(r28), RPT(r29), RPT(r30), RPT(r31) +}; + +/* + * Return the (rotated) index for floating point register + * be in the REGNUM (REGNUM must range from 32-127, + * result is in the range from 0-95. + */ +static inline unsigned long fph_index(struct kvm_pt_regs *regs, + long regnum) +{ + unsigned long rrb_fr = (regs->cr_ifs >> 25) & 0x7f; + return rotate_reg(96, rrb_fr, (regnum - IA64_FIRST_ROTATING_FR)); +} + + +/* + * The inverse of the above: given bspstore and the number of + * registers, calculate ar.bsp. + */ +static inline unsigned long *kvm_rse_skip_regs(unsigned long *addr, + long num_regs) +{ + long delta = ia64_rse_slot_num(addr) + num_regs; + int i = 0; + + if (num_regs < 0) + delta -= 0x3e; + if (delta < 0) { + while (delta <= -0x3f) { + i--; + delta += 0x3f; + } + } else { + while (delta >= 0x3f) { + i++; + delta -= 0x3f; + } + } + + return addr + num_regs + i; +} + +static void get_rse_reg (struct kvm_pt_regs *regs, unsigned long r1, + unsigned long *val, int *nat) +{ + unsigned long *bsp, *addr, *rnat_addr, *bspstore; + unsigned long *kbs = (void *) current_vcpu + VMM_RBS_OFFSET; + unsigned long nat_mask; + unsigned long old_rsc, new_rsc; + long sof = (regs->cr_ifs) & 0x7f; + long sor = (((regs->cr_ifs >> 14) & 0xf) << 3); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx = r1 - 32; + + if (ridx < sor) + ridx = rotate_reg(sor, rrb_gr, ridx); + + old_rsc = ia64_get_rsc(); + new_rsc = old_rsc&(~(0x3)); + ia64_set_rsc(new_rsc); + + bspstore = (unsigned long *)ia64_get_bspstore(); + bsp = kbs + (regs->loadrs >> 19); + + addr = kvm_rse_skip_regs(bsp, -sof + ridx); + nat_mask = 1UL << ia64_rse_slot_num(addr); + rnat_addr = ia64_rse_rnat_addr(addr); + + if (addr >= bspstore) { + ia64_flushrs(); + ia64_mf(); + bspstore = (unsigned long *)ia64_get_bspstore(); + } + *val = *addr; + if (nat) { + if (bspstore < rnat_addr) { + *nat = (int)!!(ia64_get_rnat() & nat_mask); + } else { + *nat = (int)!!((*rnat_addr) & nat_mask); + } + ia64_set_rsc(old_rsc); + } +} + +void set_rse_reg(struct kvm_pt_regs *regs, unsigned long r1, + unsigned long val, unsigned long nat) +{ + unsigned long *bsp, *bspstore, *addr, *rnat_addr; + unsigned long *kbs = (void *) current_vcpu + VMM_RBS_OFFSET; + unsigned long nat_mask; + unsigned long old_rsc, new_rsc, psr; + unsigned long rnat; + long sof = (regs->cr_ifs) & 0x7f; + long sor = (((regs->cr_ifs >> 14) & 0xf) << 3); + long rrb_gr = (regs->cr_ifs >> 18) & 0x7f; + long ridx = r1 - 32; + + if (ridx < sor) + ridx = rotate_reg(sor, rrb_gr, ridx); + + old_rsc = ia64_get_rsc(); + /* put RSC to lazy mode, and set loadrs 0 */ + new_rsc = old_rsc & (~0x3fff0003); + ia64_set_rsc(new_rsc); + bsp = kbs + (regs->loadrs >> 19); /* 16 + 3 */ + + addr = kvm_rse_skip_regs(bsp, -sof + ridx); + nat_mask = 1UL << ia64_rse_slot_num(addr); + rnat_addr = ia64_rse_rnat_addr(addr); + + local_irq_save(psr); + bspstore = (unsigned long *)ia64_get_bspstore(); + if (addr >= bspstore) { + + ia64_flushrs(); + ia64_mf(); + *addr = val; + bspstore = (unsigned long *)ia64_get_bspstore(); + rnat = ia64_get_rnat(); + if (bspstore < rnat_addr) { + rnat = rnat & (~nat_mask); + } else{ + *rnat_addr = (*rnat_addr)&(~nat_mask); + } + ia64_mf(); + ia64_loadrs(); + ia64_set_rnat(rnat); + } else { + rnat = ia64_get_rnat(); + *addr = val; + if (bspstore < rnat_addr) { + rnat = rnat&(~nat_mask); + } else { + *rnat_addr = (*rnat_addr) & (~nat_mask); + } + ia64_set_bspstore(bspstore); + ia64_set_rnat(rnat); + } + local_irq_restore(psr); + ia64_set_rsc(old_rsc); +} + +void getreg(unsigned long regnum, unsigned long *val, + int *nat, struct kvm_pt_regs *regs) +{ + unsigned long addr, *unat; + if (regnum >= IA64_FIRST_STACKED_GR) { + get_rse_reg(regs, regnum, val, nat); + return; + } + + /* + * Now look at registers in [0-31] range and init correct UNAT + */ + addr = (unsigned long)regs; + unat = ®s->eml_unat;; + + addr += gr_info[regnum]; + + *val = *(unsigned long *)addr; + /* + * do it only when requested + */ + if (nat) + *nat = (*unat >> ((addr >> 3) & 0x3f)) & 0x1UL; +} + +void setreg(unsigned long regnum, unsigned long val, + int nat, struct kvm_pt_regs *regs) +{ + unsigned long addr; + unsigned long bitmask; + unsigned long *unat; + + /* + * First takes care of stacked registers + */ + if (regnum >= IA64_FIRST_STACKED_GR) { + set_rse_reg(regs, regnum, val, nat); + return; + } + + /* + * Now look at registers in [0-31] range and init correct UNAT + */ + addr = (unsigned long)regs; + unat = ®s->eml_unat; + /* + * add offset from base of struct + * and do it ! + */ + addr += gr_info[regnum]; + + *(unsigned long *)addr = val; + + /* + * We need to clear the corresponding UNAT bit to fully emulate the load + * UNAT bit_pos = GR[r3]{8:3} form EAS-2.4 + */ + bitmask = 1UL << ((addr >> 3) & 0x3f); + if (nat) { + *unat |= bitmask; + } else { + *unat &= ~bitmask; + } +} + +u64 vcpu_get_gr(VCPU *vcpu, unsigned long reg) +{ + REGS *regs = vcpu_regs(vcpu); + u64 val; + + if (!reg) + return 0; + getreg(reg, &val, 0, regs); + return val; +} + +void vcpu_set_gr(VCPU *vcpu, u64 reg, u64 value, int nat) +{ + REGS *regs = vcpu_regs(vcpu); + long sof = (regs->cr_ifs) & 0x7f; + + if (!reg) + return; + if (reg >= sof + 32) + return; + setreg(reg, value, nat, regs); /* FIXME: handle NATs later*/ +} + +void getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, + struct kvm_pt_regs *regs) +{ + /* Take floating register rotation into consideration*/ + if (regnum >= IA64_FIRST_ROTATING_FR) + regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, regnum); +#define CASE_FIXED_FP(reg) \ + case (reg) : \ + ia64_stf_spill(fpval, reg); \ + break + + switch (regnum) { + CASE_FIXED_FP(0); + CASE_FIXED_FP(1); + CASE_FIXED_FP(2); + CASE_FIXED_FP(3); + CASE_FIXED_FP(4); + CASE_FIXED_FP(5); + + CASE_FIXED_FP(6); + CASE_FIXED_FP(7); + CASE_FIXED_FP(8); + CASE_FIXED_FP(9); + CASE_FIXED_FP(10); + CASE_FIXED_FP(11); + + CASE_FIXED_FP(12); + CASE_FIXED_FP(13); + CASE_FIXED_FP(14); + CASE_FIXED_FP(15); + CASE_FIXED_FP(16); + CASE_FIXED_FP(17); + CASE_FIXED_FP(18); + CASE_FIXED_FP(19); + CASE_FIXED_FP(20); + CASE_FIXED_FP(21); + CASE_FIXED_FP(22); + CASE_FIXED_FP(23); + CASE_FIXED_FP(24); + CASE_FIXED_FP(25); + CASE_FIXED_FP(26); + CASE_FIXED_FP(27); + CASE_FIXED_FP(28); + CASE_FIXED_FP(29); + CASE_FIXED_FP(30); + CASE_FIXED_FP(31); + CASE_FIXED_FP(32); + CASE_FIXED_FP(33); + CASE_FIXED_FP(34); + CASE_FIXED_FP(35); + CASE_FIXED_FP(36); + CASE_FIXED_FP(37); + CASE_FIXED_FP(38); + CASE_FIXED_FP(39); + CASE_FIXED_FP(40); + CASE_FIXED_FP(41); + CASE_FIXED_FP(42); + CASE_FIXED_FP(43); + CASE_FIXED_FP(44); + CASE_FIXED_FP(45); + CASE_FIXED_FP(46); + CASE_FIXED_FP(47); + CASE_FIXED_FP(48); + CASE_FIXED_FP(49); + CASE_FIXED_FP(50); + CASE_FIXED_FP(51); + CASE_FIXED_FP(52); + CASE_FIXED_FP(53); + CASE_FIXED_FP(54); + CASE_FIXED_FP(55); + CASE_FIXED_FP(56); + CASE_FIXED_FP(57); + CASE_FIXED_FP(58); + CASE_FIXED_FP(59); + CASE_FIXED_FP(60); + CASE_FIXED_FP(61); + CASE_FIXED_FP(62); + CASE_FIXED_FP(63); + CASE_FIXED_FP(64); + CASE_FIXED_FP(65); + CASE_FIXED_FP(66); + CASE_FIXED_FP(67); + CASE_FIXED_FP(68); + CASE_FIXED_FP(69); + CASE_FIXED_FP(70); + CASE_FIXED_FP(71); + CASE_FIXED_FP(72); + CASE_FIXED_FP(73); + CASE_FIXED_FP(74); + CASE_FIXED_FP(75); + CASE_FIXED_FP(76); + CASE_FIXED_FP(77); + CASE_FIXED_FP(78); + CASE_FIXED_FP(79); + CASE_FIXED_FP(80); + CASE_FIXED_FP(81); + CASE_FIXED_FP(82); + CASE_FIXED_FP(83); + CASE_FIXED_FP(84); + CASE_FIXED_FP(85); + CASE_FIXED_FP(86); + CASE_FIXED_FP(87); + CASE_FIXED_FP(88); + CASE_FIXED_FP(89); + CASE_FIXED_FP(90); + CASE_FIXED_FP(91); + CASE_FIXED_FP(92); + CASE_FIXED_FP(93); + CASE_FIXED_FP(94); + CASE_FIXED_FP(95); + CASE_FIXED_FP(96); + CASE_FIXED_FP(97); + CASE_FIXED_FP(98); + CASE_FIXED_FP(99); + CASE_FIXED_FP(100); + CASE_FIXED_FP(101); + CASE_FIXED_FP(102); + CASE_FIXED_FP(103); + CASE_FIXED_FP(104); + CASE_FIXED_FP(105); + CASE_FIXED_FP(106); + CASE_FIXED_FP(107); + CASE_FIXED_FP(108); + CASE_FIXED_FP(109); + CASE_FIXED_FP(110); + CASE_FIXED_FP(111); + CASE_FIXED_FP(112); + CASE_FIXED_FP(113); + CASE_FIXED_FP(114); + CASE_FIXED_FP(115); + CASE_FIXED_FP(116); + CASE_FIXED_FP(117); + CASE_FIXED_FP(118); + CASE_FIXED_FP(119); + CASE_FIXED_FP(120); + CASE_FIXED_FP(121); + CASE_FIXED_FP(122); + CASE_FIXED_FP(123); + CASE_FIXED_FP(124); + CASE_FIXED_FP(125); + CASE_FIXED_FP(126); + CASE_FIXED_FP(127); + } +#undef CASE_FIXED_FP +} + +void setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, + struct kvm_pt_regs *regs) +{ + /* Take floating register rotation into consideration*/ + if (regnum >= IA64_FIRST_ROTATING_FR) + regnum = IA64_FIRST_ROTATING_FR + fph_index(regs, regnum); + +#define CASE_FIXED_FP(reg) \ + case (reg) : \ + ia64_ldf_fill(reg, fpval); \ + break + + switch (regnum) { + CASE_FIXED_FP(2); + CASE_FIXED_FP(3); + CASE_FIXED_FP(4); + CASE_FIXED_FP(5); + + CASE_FIXED_FP(6); + CASE_FIXED_FP(7); + CASE_FIXED_FP(8); + CASE_FIXED_FP(9); + CASE_FIXED_FP(10); + CASE_FIXED_FP(11); + + CASE_FIXED_FP(12); + CASE_FIXED_FP(13); + CASE_FIXED_FP(14); + CASE_FIXED_FP(15); + CASE_FIXED_FP(16); + CASE_FIXED_FP(17); + CASE_FIXED_FP(18); + CASE_FIXED_FP(19); + CASE_FIXED_FP(20); + CASE_FIXED_FP(21); + CASE_FIXED_FP(22); + CASE_FIXED_FP(23); + CASE_FIXED_FP(24); + CASE_FIXED_FP(25); + CASE_FIXED_FP(26); + CASE_FIXED_FP(27); + CASE_FIXED_FP(28); + CASE_FIXED_FP(29); + CASE_FIXED_FP(30); + CASE_FIXED_FP(31); + CASE_FIXED_FP(32); + CASE_FIXED_FP(33); + CASE_FIXED_FP(34); + CASE_FIXED_FP(35); + CASE_FIXED_FP(36); + CASE_FIXED_FP(37); + CASE_FIXED_FP(38); + CASE_FIXED_FP(39); + CASE_FIXED_FP(40); + CASE_FIXED_FP(41); + CASE_FIXED_FP(42); + CASE_FIXED_FP(43); + CASE_FIXED_FP(44); + CASE_FIXED_FP(45); + CASE_FIXED_FP(46); + CASE_FIXED_FP(47); + CASE_FIXED_FP(48); + CASE_FIXED_FP(49); + CASE_FIXED_FP(50); + CASE_FIXED_FP(51); + CASE_FIXED_FP(52); + CASE_FIXED_FP(53); + CASE_FIXED_FP(54); + CASE_FIXED_FP(55); + CASE_FIXED_FP(56); + CASE_FIXED_FP(57); + CASE_FIXED_FP(58); + CASE_FIXED_FP(59); + CASE_FIXED_FP(60); + CASE_FIXED_FP(61); + CASE_FIXED_FP(62); + CASE_FIXED_FP(63); + CASE_FIXED_FP(64); + CASE_FIXED_FP(65); + CASE_FIXED_FP(66); + CASE_FIXED_FP(67); + CASE_FIXED_FP(68); + CASE_FIXED_FP(69); + CASE_FIXED_FP(70); + CASE_FIXED_FP(71); + CASE_FIXED_FP(72); + CASE_FIXED_FP(73); + CASE_FIXED_FP(74); + CASE_FIXED_FP(75); + CASE_FIXED_FP(76); + CASE_FIXED_FP(77); + CASE_FIXED_FP(78); + CASE_FIXED_FP(79); + CASE_FIXED_FP(80); + CASE_FIXED_FP(81); + CASE_FIXED_FP(82); + CASE_FIXED_FP(83); + CASE_FIXED_FP(84); + CASE_FIXED_FP(85); + CASE_FIXED_FP(86); + CASE_FIXED_FP(87); + CASE_FIXED_FP(88); + CASE_FIXED_FP(89); + CASE_FIXED_FP(90); + CASE_FIXED_FP(91); + CASE_FIXED_FP(92); + CASE_FIXED_FP(93); + CASE_FIXED_FP(94); + CASE_FIXED_FP(95); + CASE_FIXED_FP(96); + CASE_FIXED_FP(97); + CASE_FIXED_FP(98); + CASE_FIXED_FP(99); + CASE_FIXED_FP(100); + CASE_FIXED_FP(101); + CASE_FIXED_FP(102); + CASE_FIXED_FP(103); + CASE_FIXED_FP(104); + CASE_FIXED_FP(105); + CASE_FIXED_FP(106); + CASE_FIXED_FP(107); + CASE_FIXED_FP(108); + CASE_FIXED_FP(109); + CASE_FIXED_FP(110); + CASE_FIXED_FP(111); + CASE_FIXED_FP(112); + CASE_FIXED_FP(113); + CASE_FIXED_FP(114); + CASE_FIXED_FP(115); + CASE_FIXED_FP(116); + CASE_FIXED_FP(117); + CASE_FIXED_FP(118); + CASE_FIXED_FP(119); + CASE_FIXED_FP(120); + CASE_FIXED_FP(121); + CASE_FIXED_FP(122); + CASE_FIXED_FP(123); + CASE_FIXED_FP(124); + CASE_FIXED_FP(125); + CASE_FIXED_FP(126); + CASE_FIXED_FP(127); + } +} + +void vcpu_get_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val) +{ + REGS *regs = vcpu_regs(vcpu); + + getfpreg(reg, val, regs); /* FIXME: handle NATs later*/ +} + +void vcpu_set_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val) +{ + REGS *regs = vcpu_regs(vcpu); + + if (reg > 1) + setfpreg(reg, val, regs); /* FIXME: handle NATs later*/ +} + + +/********************************************************************** ** + * lsapic timer + ***********************************************************************/ +u64 vcpu_get_itc(VCPU *vcpu) +{ + unsigned long guest_itc; + guest_itc = VMX(vcpu, itc_offset) + ia64_get_itc(); + + if (guest_itc >= VMX(vcpu, last_itc)) { + VMX(vcpu, last_itc) = guest_itc; + return guest_itc; + } else + return VMX(vcpu, last_itc); +} + +static inline void vcpu_set_itm(VCPU *vcpu, u64 val); +static void vcpu_set_itc(VCPU *vcpu, u64 val) +{ + VCPU *v; + int i; + long itc_offset = val - ia64_get_itc(); + unsigned long vitv = VCPU(vcpu, itv); + + if (vcpu->vcpu_id == 0) { + for (i = 0; i < MAX_VCPU_NUM; i++) { + v = (VCPU *)((char *)vcpu + VCPU_SIZE * i); + VMX(v, itc_offset) = itc_offset; + VMX(v, last_itc) = 0; + } + } + VMX(vcpu, last_itc) = 0; + if (VCPU(vcpu, itm) <= val) { + VMX(vcpu, itc_check) = 0; + vcpu_unpend_interrupt(vcpu, vitv); + } else { + VMX(vcpu, itc_check) = 1; + vcpu_set_itm(vcpu, VCPU(vcpu, itm)); + } + +} + +static inline u64 vcpu_get_itm(VCPU *vcpu) +{ + return ((u64)VCPU(vcpu, itm)); +} + +static inline void vcpu_set_itm(VCPU *vcpu, u64 val) +{ + unsigned long vitv = VCPU(vcpu, itv); + VCPU(vcpu, itm) = val; + + if (val > vcpu_get_itc(vcpu)) { + VMX(vcpu, itc_check) = 1; + vcpu_unpend_interrupt(vcpu, vitv); + VMX(vcpu, timer_pending) = 0; + } else + VMX(vcpu, itc_check) = 0; +} + +#define ITV_VECTOR(itv) (itv&0xff) +#define ITV_IRQ_MASK(itv) (itv&(1<<16)) + +static inline void vcpu_set_itv(VCPU *vcpu, u64 val) +{ + VCPU(vcpu, itv) = val; + if (!ITV_IRQ_MASK(val) && vcpu->arch.timer_pending) { + vcpu_pend_interrupt(vcpu, ITV_VECTOR(val)); + vcpu->arch.timer_pending = 0; + } +} + +static inline void vcpu_set_eoi(VCPU *vcpu, u64 val) +{ + int vec; + + vec = highest_inservice_irq(vcpu); + if (vec == NULL_VECTOR) + return; + VMX(vcpu, insvc[vec >> 6]) &= ~(1UL << (vec & 63)); + VCPU(vcpu, eoi) = 0; + vcpu->arch.irq_new_pending = 1; + +} + +/* See Table 5-8 in SDM vol2 for the definition */ +int irq_masked(VCPU *vcpu, int h_pending, int h_inservice) +{ + ia64_tpr vtpr; + + vtpr.val = VCPU(vcpu, tpr); + + if (h_inservice == NMI_VECTOR) + return IRQ_MASKED_BY_INSVC; + + if (h_pending == NMI_VECTOR) { + /* Non Maskable Interrupt */ + return IRQ_NO_MASKED; + } + + if (h_inservice == ExtINT_VECTOR) + return IRQ_MASKED_BY_INSVC; + + if (h_pending == ExtINT_VECTOR) { + if (vtpr.mmi) { + /* mask all external IRQ */ + return IRQ_MASKED_BY_VTPR; + } else + return IRQ_NO_MASKED; + } + + if (is_higher_irq(h_pending, h_inservice)) { + if (is_higher_class(h_pending, vtpr.mic + (vtpr.mmi << 4))) + return IRQ_NO_MASKED; + else + return IRQ_MASKED_BY_VTPR; + } else { + return IRQ_MASKED_BY_INSVC; + } +} + +void vcpu_pend_interrupt(VCPU *vcpu, u8 vec) +{ + long spsr; + int ret; + + local_irq_save(spsr); + ret = test_and_set_bit(vec, &VCPU(vcpu, irr[0])); + local_irq_restore(spsr); + + vcpu->arch.irq_new_pending = 1; +} + +void vcpu_unpend_interrupt(VCPU *vcpu, u8 vec) +{ + long spsr; + int ret; + + local_irq_save(spsr); + ret = test_and_clear_bit(vec, &VCPU(vcpu, irr[0])); + local_irq_restore(spsr); + if (ret) { + vcpu->arch.irq_new_pending = 1; + wmb(); + } +} + +void update_vhpi(VCPU *vcpu, int vec) +{ + u64 vhpi; + + if (vec == NULL_VECTOR) + vhpi = 0; + else if (vec == NMI_VECTOR) + vhpi = 32; + else if (vec == ExtINT_VECTOR) + vhpi = 16; + else + vhpi = vec >> 4; + + VCPU(vcpu, vhpi) = vhpi; + if (VCPU(vcpu, vac).a_int) + ia64_call_vsa(PAL_VPS_SET_PENDING_INTERRUPT, + (u64)vcpu->arch.vpd, 0, 0, 0, 0, 0, 0); +} + +u64 vcpu_get_ivr(VCPU *vcpu) +{ + int vec, h_inservice, mask; + + vec = highest_pending_irq(vcpu); + h_inservice = highest_inservice_irq(vcpu); + mask = irq_masked(vcpu, vec, h_inservice); + if (vec == NULL_VECTOR || mask == IRQ_MASKED_BY_INSVC) { + if (VCPU(vcpu, vhpi)) + update_vhpi(vcpu, NULL_VECTOR); + return IA64_SPURIOUS_INT_VECTOR; + } + if (mask == IRQ_MASKED_BY_VTPR) { + update_vhpi(vcpu, vec); + return IA64_SPURIOUS_INT_VECTOR; + } + VMX(vcpu, insvc[vec >> 6]) |= (1UL << (vec & 63)); + vcpu_unpend_interrupt(vcpu, vec); + return (u64)vec; +} + +/********************************************************************** **** + Privileged operation emulation routines + ************************************************************************ **/ +u64 vcpu_thash(VCPU *vcpu, u64 vadr) +{ + ia64_pta vpta; + ia64_rr vrr; + u64 pval; + u64 vhpt_offset; + + vpta.val = vcpu_get_pta(vcpu); + vrr.val = vcpu_get_rr(vcpu, vadr); + vhpt_offset = ((vadr >> vrr.ps) << 3) & ((1UL << (vpta.size)) - 1); + if (vpta.vf) { + pval = ia64_call_vsa(PAL_VPS_THASH, vadr, vrr.val, + vpta.val, 0, 0, 0, 0); + } else { + pval = (vadr & VRN_MASK) | vhpt_offset | + (vpta.val << 3 >> (vpta.size + 3) << (vpta.size)); + } + return pval; +} + +u64 vcpu_ttag(VCPU *vcpu, u64 vadr) +{ + ia64_rr vrr; + ia64_pta vpta; + u64 pval; + + vpta.val = vcpu_get_pta(vcpu); + vrr.val = vcpu_get_rr(vcpu, vadr); + if (vpta.vf) { + pval = ia64_call_vsa(PAL_VPS_TTAG, vadr, vrr.val, + 0, 0, 0, 0, 0); + } else + pval = 1; + + return pval; +} + +u64 vcpu_tak(VCPU *vcpu, u64 vadr) +{ + thash_data_t *data; + ia64_pta vpta; + u64 key; + + vpta.val = vcpu_get_pta(vcpu); + if (vpta.vf == 0) { + key = 1; + return key; + } + data = vtlb_lookup(vcpu, vadr, D_TLB); + if (!data || !data->p) { + key = 1; + } else{ + key = data->key; + } + + return key; +} + + + +void kvm_thash(VCPU *vcpu, INST64 inst) +{ + unsigned long thash, vadr; + + vadr = vcpu_get_gr(vcpu, inst.M46.r3); + thash = vcpu_thash(vcpu, vadr); + vcpu_set_gr(vcpu, inst.M46.r1, thash, 0); +} + + +void kvm_ttag(VCPU *vcpu, INST64 inst) +{ + unsigned long tag, vadr; + + vadr = vcpu_get_gr(vcpu, inst.M46.r3); + tag = vcpu_ttag(vcpu, vadr); + vcpu_set_gr(vcpu, inst.M46.r1, tag, 0); +} + +int vcpu_tpa(VCPU *vcpu, u64 vadr, u64 *padr) +{ + thash_data_t *data; + ia64_isr visr, pt_isr; + REGS *regs; + ia64_psr vpsr; + + regs = vcpu_regs(vcpu); + pt_isr.val = VMX(vcpu, cr_isr); + visr.val = 0; + visr.ei = pt_isr.ei; + visr.ir = pt_isr.ir; + vpsr.val = VCPU(vcpu, vpsr); + visr.na = 1; + + data = vhpt_lookup(vadr); + if (data) { + if (data->p == 0) { + vcpu_set_isr(vcpu, visr.val); + data_page_not_present(vcpu, vadr); + return IA64_FAULT; + } else if (data->ma == VA_MATTR_NATPAGE) { + vcpu_set_isr(vcpu, visr.val); + dnat_page_consumption(vcpu, vadr); + return IA64_FAULT; + } else { + *padr = (data->gpaddr >> data->ps << data->ps) | + (vadr & (PSIZE(data->ps) - 1)); + return IA64_NO_FAULT; + } + } + + data = vtlb_lookup(vcpu, vadr, D_TLB); + if (data) { + if (data->p == 0) { + vcpu_set_isr(vcpu, visr.val); + data_page_not_present(vcpu, vadr); + return IA64_FAULT; + } else if (data->ma == VA_MATTR_NATPAGE) { + vcpu_set_isr(vcpu, visr.val); + dnat_page_consumption(vcpu, vadr); + return IA64_FAULT; + } else{ + *padr = ((data->ppn >> (data->ps - 12)) << data->ps) + | (vadr & (PSIZE(data->ps) - 1)); + return IA64_NO_FAULT; + } + } + if (!vhpt_enabled(vcpu, vadr, NA_REF)) { + if (vpsr.ic) { + vcpu_set_isr(vcpu, visr.val); + alt_dtlb(vcpu, vadr); + return IA64_FAULT; + } else { + nested_dtlb(vcpu); + return IA64_FAULT; + } + } else { + if (vpsr.ic) { + vcpu_set_isr(vcpu, visr.val); + dvhpt_fault(vcpu, vadr); + return IA64_FAULT; + } else{ + nested_dtlb(vcpu); + return IA64_FAULT; + } + } + + return IA64_NO_FAULT; +} + + +int kvm_tpa(VCPU *vcpu, INST64 inst) +{ + unsigned long r1, r3; + + r3 = vcpu_get_gr(vcpu, inst.M46.r3); + + if (vcpu_tpa(vcpu, r3, &r1)) + return IA64_FAULT; + + vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); + return(IA64_NO_FAULT); +} + +void kvm_tak(VCPU *vcpu, INST64 inst) +{ + unsigned long r1, r3; + + r3 = vcpu_get_gr(vcpu, inst.M46.r3); + r1 = vcpu_tak(vcpu, r3); + vcpu_set_gr(vcpu, inst.M46.r1, r1, 0); +} + + +/************************************ + * Insert/Purge translation register/cache + ************************************/ +void vcpu_itc_i(VCPU *vcpu, u64 pte, u64 itir, u64 ifa) +{ + thash_purge_and_insert(vcpu, pte, itir, ifa, I_TLB); +} + +void vcpu_itc_d(VCPU *vcpu, u64 pte, u64 itir, u64 ifa) +{ + thash_purge_and_insert(vcpu, pte, itir, ifa, D_TLB); +} + +void vcpu_itr_i(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa) +{ + u64 ps, va, rid; + thash_data_t *p_itr; + + ps = itir_ps(itir); + va = PAGEALIGN(ifa, ps); + pte &= ~PAGE_FLAGS_RV_MASK; + rid = vcpu_get_rr(vcpu, ifa); + rid = rid & RR_RID_MASK; + p_itr = (thash_data_t *)&vcpu->arch.itrs[slot]; + vcpu_set_tr(p_itr, pte, itir, va, rid); + vcpu_quick_region_set(VMX(vcpu, itr_regions), va); +} + + +void vcpu_itr_d(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa) +{ + u64 gpfn; + u64 ps, va, rid; + thash_data_t *p_dtr; + + ps = itir_ps(itir); + va = PAGEALIGN(ifa, ps); + pte &= ~PAGE_FLAGS_RV_MASK; + + /* This is a bad workaround + In Linux, region 7 use 16M pagesize and is identity mapped. + VHPT page size is 16K in XEN. If purge VHPT while guest insert 16M, + it will iteratively purge VHPT 1024 times, which makes XEN/IPF very + slow. XEN doesn't purge VHPT + */ + if (ps != _PAGE_SIZE_16M) + thash_purge_entries(vcpu, va, ps); + gpfn = (pte & _PAGE_PPN_MASK) >> PAGE_SHIFT; + if (__gpfn_is_io(gpfn)) + pte |= VTLB_PTE_IO; + rid = vcpu_get_rr(vcpu, va); + rid = rid & RR_RID_MASK; + p_dtr = (thash_data_t *)&vcpu->arch.dtrs[slot]; + vcpu_set_tr((thash_data_t *)&vcpu->arch.dtrs[slot], pte, itir, va, rid); + vcpu_quick_region_set(VMX(vcpu, dtr_regions), va); +} + +void vcpu_ptr_d(VCPU *vcpu, u64 ifa, u64 ps) +{ + int index; + u64 va; + + va = PAGEALIGN(ifa, ps); + while ((index = vtr_find_overlap(vcpu, va, ps, D_TLB)) >= 0) + vcpu->arch.dtrs[index].page_flags = 0; + + thash_purge_entries(vcpu, va, ps); +} + +void vcpu_ptr_i(VCPU *vcpu, u64 ifa, u64 ps) +{ + int index; + u64 va; + + va = PAGEALIGN(ifa, ps); + while ((index = vtr_find_overlap(vcpu, va, ps, I_TLB)) >= 0) + vcpu->arch.itrs[index].page_flags = 0; + + thash_purge_entries(vcpu, va, ps); +} + +void vcpu_ptc_l(VCPU *vcpu, u64 va, u64 ps) +{ + va = PAGEALIGN(va, ps); + thash_purge_entries(vcpu, va, ps); +} + +void vcpu_ptc_e(VCPU *vcpu, u64 va) +{ + thash_purge_all(vcpu); +} + +void vcpu_ptc_ga(VCPU *vcpu, u64 va, u64 ps) +{ + struct exit_ctl_data *p = &vcpu->arch.exit_data; + long psr; + local_irq_save(psr); + p->exit_reason = EXIT_REASON_PTC_G; + + p->u.ptc_g_data.rr = vcpu_get_rr(vcpu, va); + p->u.ptc_g_data.vaddr = va; + p->u.ptc_g_data.ps = ps; + vmm_transition(vcpu); + /* Do Local Purge Here*/ + vcpu_ptc_l(vcpu, va, ps); + local_irq_restore(psr); +} + + +void vcpu_ptc_g(VCPU *vcpu, u64 va, u64 ps) +{ + vcpu_ptc_ga(vcpu, va, ps); +} + +void kvm_ptc_e(VCPU *vcpu, INST64 inst) +{ + unsigned long ifa; + + ifa = vcpu_get_gr(vcpu, inst.M45.r3); + vcpu_ptc_e(vcpu, ifa); +} + +void kvm_ptc_g(VCPU *vcpu, INST64 inst) +{ + unsigned long ifa, itir; + + ifa = vcpu_get_gr(vcpu, inst.M45.r3); + itir = vcpu_get_gr(vcpu, inst.M45.r2); + vcpu_ptc_g(vcpu, ifa, itir_ps(itir)); +} + +void kvm_ptc_ga(VCPU *vcpu, INST64 inst) +{ + unsigned long ifa, itir; + + ifa = vcpu_get_gr(vcpu, inst.M45.r3); + itir = vcpu_get_gr(vcpu, inst.M45.r2); + vcpu_ptc_ga(vcpu, ifa, itir_ps(itir)); +} + +void kvm_ptc_l(VCPU *vcpu, INST64 inst) +{ + unsigned long ifa, itir; + + ifa = vcpu_get_gr(vcpu, inst.M45.r3); + itir = vcpu_get_gr(vcpu, inst.M45.r2); + vcpu_ptc_l(vcpu, ifa, itir_ps(itir)); +} + +void kvm_ptr_d(VCPU *vcpu, INST64 inst) +{ + unsigned long ifa, itir; + + ifa = vcpu_get_gr(vcpu, inst.M45.r3); + itir = vcpu_get_gr(vcpu, inst.M45.r2); + vcpu_ptr_d(vcpu, ifa, itir_ps(itir)); +} + +void kvm_ptr_i(VCPU *vcpu, INST64 inst) +{ + unsigned long ifa, itir; + + ifa = vcpu_get_gr(vcpu, inst.M45.r3); + itir = vcpu_get_gr(vcpu, inst.M45.r2); + vcpu_ptr_i(vcpu, ifa, itir_ps(itir)); +} + +void kvm_itr_d(VCPU *vcpu, INST64 inst) +{ + unsigned long itir, ifa, pte, slot; + + slot = vcpu_get_gr(vcpu, inst.M45.r3); + pte = vcpu_get_gr(vcpu, inst.M45.r2); + itir = vcpu_get_itir(vcpu); + ifa = vcpu_get_ifa(vcpu); + vcpu_itr_d(vcpu, slot, pte, itir, ifa); +} + + + +void kvm_itr_i(VCPU *vcpu, INST64 inst) +{ + unsigned long itir, ifa, pte, slot; + + slot = vcpu_get_gr(vcpu, inst.M45.r3); + pte = vcpu_get_gr(vcpu, inst.M45.r2); + itir = vcpu_get_itir(vcpu); + ifa = vcpu_get_ifa(vcpu); + vcpu_itr_i(vcpu, slot, pte, itir, ifa); +} + +void kvm_itc_d(VCPU *vcpu, INST64 inst) +{ + unsigned long itir, ifa, pte; + + itir = vcpu_get_itir(vcpu); + ifa = vcpu_get_ifa(vcpu); + pte = vcpu_get_gr(vcpu, inst.M45.r2); + vcpu_itc_d(vcpu, pte, itir, ifa); +} + +void kvm_itc_i(VCPU *vcpu, INST64 inst) +{ + unsigned long itir, ifa, pte; + + itir = vcpu_get_itir(vcpu); + ifa = vcpu_get_ifa(vcpu); + pte = vcpu_get_gr(vcpu, inst.M45.r2); + vcpu_itc_i(vcpu, pte, itir, ifa); +} + +/************************************* + * Moves to semi-privileged registers + *************************************/ + +void kvm_mov_to_ar_imm(VCPU *vcpu, INST64 inst) +{ + unsigned long imm; + + if (inst.M30.s) { + imm = -inst.M30.imm; + } else { + imm = inst.M30.imm; + } + + vcpu_set_itc(vcpu, imm); +} + +void kvm_mov_to_ar_reg(VCPU *vcpu, INST64 inst) +{ + unsigned long r2; + + r2 = vcpu_get_gr(vcpu, inst.M29.r2); + vcpu_set_itc(vcpu, r2); +} + + +void kvm_mov_from_ar_reg(VCPU *vcpu, INST64 inst) +{ + unsigned long r1; + + r1 = vcpu_get_itc(vcpu); + vcpu_set_gr(vcpu, inst.M31.r1, r1, 0); +} +/********************************************************************** **** + VCPU protection key register access routines + ************************************************************************ **/ + +unsigned long vcpu_get_pkr(VCPU *vcpu, unsigned long reg) +{ + return ((unsigned long)ia64_get_pkr(reg)); +} + +void vcpu_set_pkr(VCPU *vcpu, unsigned long reg, unsigned long val) +{ + ia64_set_pkr(reg, val); +} + + +unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, unsigned long ifa) +{ + ia64_rr rr, rr1; + + rr.val = vcpu_get_rr(vcpu, ifa); + rr1.val = 0; + rr1.ps = rr.ps; + rr1.rid = rr.rid; + return (rr1.val); +} + + + +/******************************** + * Moves to privileged registers + ********************************/ +unsigned long vcpu_set_rr(VCPU *vcpu, unsigned long reg, unsigned long val) +{ + ia64_rr oldrr, newrr; + unsigned long rrval; + struct exit_ctl_data *p = &vcpu->arch.exit_data; + unsigned long psr; + + oldrr.val = vcpu_get_rr(vcpu, reg); + newrr.val = val; + vcpu->arch.vrr[reg >> VRN_SHIFT] = val; + + switch ((unsigned long)(reg >> VRN_SHIFT)) { + case VRN6: + vcpu->arch.vmm_rr = vrrtomrr(val); + local_irq_save(psr); + p->exit_reason = EXIT_REASON_SWITCH_RR6; + vmm_transition(vcpu); + local_irq_restore(psr); + break; + case VRN4: + rrval = vrrtomrr(val); + vcpu->arch.metaphysical_saved_rr4 = rrval; + if (!is_physical_mode(vcpu)) + ia64_set_rr(reg, rrval); + break; + case VRN0: + rrval = vrrtomrr(val); + vcpu->arch.metaphysical_saved_rr0 = rrval; + if (!is_physical_mode(vcpu)) + ia64_set_rr(reg, rrval); + break; + default: + ia64_set_rr(reg, vrrtomrr(val)); + break; + } + + return (IA64_NO_FAULT); +} + + + +void kvm_mov_to_rr(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r2; + + r3 = vcpu_get_gr(vcpu, inst.M42.r3); + r2 = vcpu_get_gr(vcpu, inst.M42.r2); + vcpu_set_rr(vcpu, r3, r2); +} + +void kvm_mov_to_dbr(VCPU *vcpu, INST64 inst) +{ +} + +void kvm_mov_to_ibr(VCPU *vcpu, INST64 inst) +{ +} + +void kvm_mov_to_pmc(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r2; + + r3 = vcpu_get_gr(vcpu, inst.M42.r3); + r2 = vcpu_get_gr(vcpu, inst.M42.r2); + vcpu_set_pmc(vcpu, r3, r2); +} + +void kvm_mov_to_pmd(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r2; + + r3 = vcpu_get_gr(vcpu, inst.M42.r3); + r2 = vcpu_get_gr(vcpu, inst.M42.r2); + vcpu_set_pmd(vcpu, r3, r2); +} + +void kvm_mov_to_pkr(VCPU *vcpu, INST64 inst) +{ + u64 r3, r2; + + r3 = vcpu_get_gr(vcpu, inst.M42.r3); + r2 = vcpu_get_gr(vcpu, inst.M42.r2); + vcpu_set_pkr(vcpu, r3, r2); +} + + + +void kvm_mov_from_rr(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r1; + + r3 = vcpu_get_gr(vcpu, inst.M43.r3); + r1 = vcpu_get_rr(vcpu, r3); + vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); +} + +void kvm_mov_from_pkr(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r1; + + r3 = vcpu_get_gr(vcpu, inst.M43.r3); + r1 = vcpu_get_pkr(vcpu, r3); + vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); +} + +void kvm_mov_from_dbr(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r1; + + r3 = vcpu_get_gr(vcpu, inst.M43.r3); + r1 = vcpu_get_dbr(vcpu, r3); + vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); +} + +void kvm_mov_from_ibr(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r1; + + r3 = vcpu_get_gr(vcpu, inst.M43.r3); + r1 = vcpu_get_ibr(vcpu, r3); + vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); +} + +void kvm_mov_from_pmc(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r1; + + r3 = vcpu_get_gr(vcpu, inst.M43.r3); + r1 = vcpu_get_pmc(vcpu, r3); + vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); +} + + +unsigned long vcpu_get_cpuid(VCPU *vcpu, unsigned long reg) +{ + /* FIXME: This could get called as a result of a rsvd-reg fault */ + if (reg > (ia64_get_cpuid(3) & 0xff)) + return 0; + else + return ia64_get_cpuid(reg); +} + +void kvm_mov_from_cpuid(VCPU *vcpu, INST64 inst) +{ + unsigned long r3, r1; + + r3 = vcpu_get_gr(vcpu, inst.M43.r3); + r1 = vcpu_get_cpuid(vcpu, r3); + vcpu_set_gr(vcpu, inst.M43.r1, r1, 0); +} + +void vcpu_set_tpr(VCPU *vcpu, unsigned long val) +{ + VCPU(vcpu, tpr) = val; + vcpu->arch.irq_check = 1; +} + +unsigned long kvm_mov_to_cr(VCPU *vcpu, INST64 inst) +{ + unsigned long r2; + + r2 = vcpu_get_gr(vcpu, inst.M32.r2); + VCPU(vcpu, vcr[inst.M32.cr3]) = r2; + + switch (inst.M32.cr3) { + case 0: + vcpu_set_dcr(vcpu, r2); + break; + case 1: + vcpu_set_itm(vcpu, r2); + break; + case 66: + vcpu_set_tpr(vcpu, r2); + break; + case 67: + vcpu_set_eoi(vcpu, r2); + break; + default: + break; + } + + return 0; +} + + +unsigned long kvm_mov_from_cr(VCPU *vcpu, INST64 inst) +{ + unsigned long tgt = inst.M33.r1; + unsigned long val; + + switch (inst.M33.cr3) { + case 65: + val = vcpu_get_ivr(vcpu); + vcpu_set_gr(vcpu, tgt, val, 0); + break; + + case 67: + vcpu_set_gr(vcpu, tgt, 0L, 0); + break; + default: + val = VCPU(vcpu, vcr[inst.M33.cr3]); + vcpu_set_gr(vcpu, tgt, val, 0); + break; + } + + return 0; +} + + + +void vcpu_set_psr(VCPU *vcpu, unsigned long val) +{ + + unsigned long mask; + REGS *regs; + ia64_psr old_psr, new_psr; + + old_psr = (ia64_psr)VCPU(vcpu, vpsr); + + regs = vcpu_regs(vcpu); + /* We only support guest as: + * vpsr.pk = 0 + * vpsr.is = 0 + * Otherwise panic + */ + if (val & (IA64_PSR_PK | IA64_PSR_IS | IA64_PSR_VM)) + panic_vm(vcpu); + + /* + * For those IA64_PSR bits: id/da/dd/ss/ed/ia + * Since these bits will become 0, after success execution of each + * instruction, we will change set them to mIA64_PSR + */ + VCPU(vcpu, vpsr) = val + & (~(IA64_PSR_ID | IA64_PSR_DA | IA64_PSR_DD | + IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA)); + + if (!old_psr.i && (val & IA64_PSR_I)) { + /* vpsr.i 0->1 */ + vcpu->arch.irq_check = 1; + } + new_psr.val = VCPU(vcpu, vpsr); + + /* + * All vIA64_PSR bits shall go to mPSR (v->tf->tf_special.psr) + * , except for the following bits: + * ic/i/dt/si/rt/mc/it/bn/vm + */ + mask = IA64_PSR_IC + IA64_PSR_I + IA64_PSR_DT + IA64_PSR_SI + + IA64_PSR_RT + IA64_PSR_MC + IA64_PSR_IT + IA64_PSR_BN + + IA64_PSR_VM; + + regs->cr_ipsr = (regs->cr_ipsr & mask) | (val & (~mask)); + + check_mm_mode_switch(vcpu, old_psr, new_psr); + + return ; +} + +unsigned long vcpu_cover(VCPU *vcpu) +{ + ia64_psr vpsr; + + REGS *regs = vcpu_regs(vcpu); + vpsr = (ia64_psr)VCPU(vcpu, vpsr); + + if (!vpsr.ic) + VCPU(vcpu, ifs) = regs->cr_ifs; + regs->cr_ifs = IA64_IFS_V; + return (IA64_NO_FAULT); +} + + + +/********************************************************************** **** + VCPU banked general register access routines + ************************************************************************ **/ +#define vcpu_bsw0_unat(i, b0unat, b1unat, runat, VMM_PT_REGS_R16_SLOT) \ + do { \ + __asm__ __volatile__ ( \ + ";;extr.u %0 = %3,%6,16;;\n" \ + "dep %1 = %0, %1, 0, 16;;\n" \ + "st8 [%4] = %1\n" \ + "extr.u %0 = %2, 16, 16;;\n" \ + "dep %3 = %0, %3, %6, 16;;\n" \ + "st8 [%5] = %3\n" \ + ::"r"(i), "r"(*b1unat), "r"(*b0unat), \ + "r"(*runat), "r"(b1unat), "r"(runat), \ + "i"(VMM_PT_REGS_R16_SLOT) : "memory"); \ + } while (0) + +void vcpu_bsw0(VCPU *vcpu) +{ + unsigned long i; + + REGS *regs = vcpu_regs(vcpu); + unsigned long *r = ®s->r16; + unsigned long *b0 = &VCPU(vcpu, vbgr[0]); + unsigned long *b1 = &VCPU(vcpu, vgr[0]); + unsigned long *runat = ®s->eml_unat; + unsigned long *b0unat = &VCPU(vcpu, vbnat); + unsigned long *b1unat = &VCPU(vcpu, vnat); + + + if (VCPU(vcpu, vpsr) & IA64_PSR_BN) { + for (i = 0; i < 16; i++) { + *b1++ = *r; + *r++ = *b0++; + } + vcpu_bsw0_unat(i, b0unat, b1unat, runat, + VMM_PT_REGS_R16_SLOT); + VCPU(vcpu, vpsr) &= ~IA64_PSR_BN; + } +} + +#define vcpu_bsw1_unat(i, b0unat, b1unat, runat, VMM_PT_REGS_R16_SLOT) \ + do { \ + __asm__ __volatile__ (";;extr.u %0 = %3, %6, 16;;\n" \ + "dep %1 = %0, %1, 16, 16;;\n" \ + "st8 [%4] = %1\n" \ + "extr.u %0 = %2, 0, 16;;\n" \ + "dep %3 = %0, %3, %6, 16;;\n" \ + "st8 [%5] = %3\n" \ + ::"r"(i), "r"(*b0unat), "r"(*b1unat), \ + "r"(*runat), "r"(b0unat), "r"(runat), \ + "i"(VMM_PT_REGS_R16_SLOT) : "memory"); \ + } while (0) + +void vcpu_bsw1(VCPU *vcpu) +{ + /* TODO: Only allowed for current vcpu */ + unsigned long i; + REGS *regs = vcpu_regs(vcpu); + unsigned long *r = ®s->r16; + unsigned long *b0 = &VCPU(vcpu, vbgr[0]); + unsigned long *b1 = &VCPU(vcpu, vgr[0]); + unsigned long *runat = ®s->eml_unat; + unsigned long *b0unat = &VCPU(vcpu, vbnat); + unsigned long *b1unat = &VCPU(vcpu, vnat); + + if (!(VCPU(vcpu, vpsr) & IA64_PSR_BN)) { + for (i = 0; i < 16; i++) { + *b0++ = *r; + *r++ = *b1++; + } + vcpu_bsw1_unat(i, b0unat, b1unat, runat, + VMM_PT_REGS_R16_SLOT); + VCPU(vcpu, vpsr) |= IA64_PSR_BN; + } +} + + + + +void vcpu_rfi(VCPU *vcpu) +{ + /* TODO: Only allowed for current vcpu */ + unsigned long ifs, psr; + REGS *regs = vcpu_regs(vcpu); + + psr = VCPU(vcpu, ipsr); + if (psr & IA64_PSR_BN) + vcpu_bsw1(vcpu); + else + vcpu_bsw0(vcpu); + vcpu_set_psr(vcpu, psr); + ifs = VCPU(vcpu, ifs); + if (ifs >> 63) + regs->cr_ifs = ifs; + regs->cr_iip = VCPU(vcpu, iip); +} + + +/* + VPSR can't keep track of below bits of guest PSR + This function gets guest PSR + */ + +unsigned long vcpu_get_psr(VCPU *vcpu) +{ + unsigned long mask; + REGS *regs = vcpu_regs(vcpu); + + mask = IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | + IA64_PSR_MFH | IA64_PSR_CPL | IA64_PSR_RI; + return (VCPU(vcpu, vpsr) & ~mask) | (regs->cr_ipsr & mask); +} + +void kvm_rsm(VCPU *vcpu, INST64 inst) +{ + unsigned long vpsr; + unsigned long imm24 = (inst.M44.i<<23) | (inst.M44.i2<<21) + | inst.M44.imm; + + vpsr = vcpu_get_psr(vcpu); + vpsr &= (~imm24); + vcpu_set_psr(vcpu, vpsr); +} + +void kvm_ssm(VCPU *vcpu, INST64 inst) +{ + unsigned long vpsr; + unsigned long imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) + | inst.M44.imm; + + vpsr = vcpu_get_psr(vcpu); + vpsr |= imm24; + vcpu_set_psr(vcpu, vpsr); +} + +void vcpu_set_psr_l(VCPU *vcpu, unsigned long val) +{ + val = (val & MASK(0, 32)) | (vcpu_get_psr(vcpu) & MASK(32, 32)); + vcpu_set_psr(vcpu, val); +} + +void kvm_mov_to_psr(VCPU *vcpu, INST64 inst) +{ + unsigned long val; + + val = vcpu_get_gr(vcpu, inst.M35.r2); + vcpu_set_psr_l(vcpu, val); +} + +void kvm_mov_from_psr(VCPU *vcpu, INST64 inst) +{ + unsigned long val; + + val = vcpu_get_psr(vcpu); + val = (val & MASK(0, 32)) | (val & MASK(35, 2)); + vcpu_set_gr(vcpu, inst.M33.r1, val, 0); +} + +void vcpu_increment_iip(VCPU *vcpu) +{ + REGS *regs = vcpu_regs(vcpu); + ia64_psr *ipsr = (ia64_psr *)®s->cr_ipsr; + if (ipsr->ri == 2) { + ipsr->ri = 0; + regs->cr_iip += 16; + } else + ipsr->ri++; +} + +void vcpu_decrement_iip(VCPU *vcpu) +{ + REGS *regs = vcpu_regs(vcpu); + ia64_psr *ipsr = (ia64_psr *)®s->cr_ipsr; + + if (ipsr->ri == 0) { + ipsr->ri = 2; + regs->cr_iip -= 16; + } else + ipsr->ri--; +} + +/** Emulate a privileged operation. + * + * + * @param vcpu virtual cpu + * @cause the reason cause virtualization fault + * @opcode the instruction code which cause virtualization fault + */ + +void kvm_emulate(VCPU *vcpu, REGS *regs) +{ + unsigned long status, cause, opcode ; + INST64 inst; + + status = IA64_NO_FAULT; + cause = VMX(vcpu, cause); + opcode = VMX(vcpu, opcode); + inst.inst = opcode; + /* + * Switch to actual virtual rid in rr0 and rr4, + * which is required by some tlb related instructions. + */ + prepare_if_physical_mode(vcpu); + + switch (cause) { + case EVENT_RSM: + kvm_rsm(vcpu, inst); + break; + case EVENT_SSM: + kvm_ssm(vcpu, inst); + break; + case EVENT_MOV_TO_PSR: + kvm_mov_to_psr(vcpu, inst); + break; + case EVENT_MOV_FROM_PSR: + kvm_mov_from_psr(vcpu, inst); + break; + case EVENT_MOV_FROM_CR: + kvm_mov_from_cr(vcpu, inst); + break; + case EVENT_MOV_TO_CR: + kvm_mov_to_cr(vcpu, inst); + break; + case EVENT_BSW_0: + vcpu_bsw0(vcpu); + break; + case EVENT_BSW_1: + vcpu_bsw1(vcpu); + break; + case EVENT_COVER: + vcpu_cover(vcpu); + break; + case EVENT_RFI: + vcpu_rfi(vcpu); + break; + case EVENT_ITR_D: + kvm_itr_d(vcpu, inst); + break; + case EVENT_ITR_I: + kvm_itr_i(vcpu, inst); + break; + case EVENT_PTR_D: + kvm_ptr_d(vcpu, inst); + break; + case EVENT_PTR_I: + kvm_ptr_i(vcpu, inst); + break; + case EVENT_ITC_D: + kvm_itc_d(vcpu, inst); + break; + case EVENT_ITC_I: + kvm_itc_i(vcpu, inst); + break; + case EVENT_PTC_L: + kvm_ptc_l(vcpu, inst); + break; + case EVENT_PTC_G: + kvm_ptc_g(vcpu, inst); + break; + case EVENT_PTC_GA: + kvm_ptc_ga(vcpu, inst); + break; + case EVENT_PTC_E: + kvm_ptc_e(vcpu, inst); + break; + case EVENT_MOV_TO_RR: + kvm_mov_to_rr(vcpu, inst); + break; + case EVENT_MOV_FROM_RR: + kvm_mov_from_rr(vcpu, inst); + break; + case EVENT_THASH: + kvm_thash(vcpu, inst); + break; + case EVENT_TTAG: + kvm_ttag(vcpu, inst); + break; + case EVENT_TPA: + status = kvm_tpa(vcpu, inst); + break; + case EVENT_TAK: + kvm_tak(vcpu, inst); + break; + case EVENT_MOV_TO_AR_IMM: + kvm_mov_to_ar_imm(vcpu, inst); + break; + case EVENT_MOV_TO_AR: + kvm_mov_to_ar_reg(vcpu, inst); + break; + case EVENT_MOV_FROM_AR: + kvm_mov_from_ar_reg(vcpu, inst); + break; + case EVENT_MOV_TO_DBR: + kvm_mov_to_dbr(vcpu, inst); + break; + case EVENT_MOV_TO_IBR: + kvm_mov_to_ibr(vcpu, inst); + break; + case EVENT_MOV_TO_PMC: + kvm_mov_to_pmc(vcpu, inst); + break; + case EVENT_MOV_TO_PMD: + kvm_mov_to_pmd(vcpu, inst); + break; + case EVENT_MOV_TO_PKR: + kvm_mov_to_pkr(vcpu, inst); + break; + case EVENT_MOV_FROM_DBR: + kvm_mov_from_dbr(vcpu, inst); + break; + case EVENT_MOV_FROM_IBR: + kvm_mov_from_ibr(vcpu, inst); + break; + case EVENT_MOV_FROM_PMC: + kvm_mov_from_pmc(vcpu, inst); + break; + case EVENT_MOV_FROM_PKR: + kvm_mov_from_pkr(vcpu, inst); + break; + case EVENT_MOV_FROM_CPUID: + kvm_mov_from_cpuid(vcpu, inst); + break; + case EVENT_VMSW: + status = IA64_FAULT; + break; + default: + break; + }; + /*Assume all status is NO_FAULT ?*/ + if (status == IA64_NO_FAULT && cause != EVENT_RFI) + vcpu_increment_iip(vcpu); + + recover_if_physical_mode(vcpu); +} + +void init_vcpu(VCPU *vcpu) +{ + int i; + + vcpu->arch.mode_flags = GUEST_IN_PHY; + VMX(vcpu, vrr[0]) = 0x38; + VMX(vcpu, vrr[1]) = 0x38; + VMX(vcpu, vrr[2]) = 0x38; + VMX(vcpu, vrr[3]) = 0x38; + VMX(vcpu, vrr[4]) = 0x38; + VMX(vcpu, vrr[5]) = 0x38; + VMX(vcpu, vrr[6]) = 0x38; + VMX(vcpu, vrr[7]) = 0x38; + VCPU(vcpu, vpsr) = IA64_PSR_BN; + VCPU(vcpu, dcr) = 0; + /* pta.size must not be 0. The minimum is 15 (32k) */ + VCPU(vcpu, pta) = 15 << 2; + VCPU(vcpu, itv) = 0x10000; + VCPU(vcpu, itm) = 0; + VMX(vcpu, last_itc) = 0; + + VCPU(vcpu, lid) = VCPU_LID(vcpu); + VCPU(vcpu, ivr) = 0; + VCPU(vcpu, tpr) = 0x10000; + VCPU(vcpu, eoi) = 0; + VCPU(vcpu, irr[0]) = 0; + VCPU(vcpu, irr[1]) = 0; + VCPU(vcpu, irr[2]) = 0; + VCPU(vcpu, irr[3]) = 0; + VCPU(vcpu, pmv) = 0x10000; + VCPU(vcpu, cmcv) = 0x10000; + VCPU(vcpu, lrr0) = 0x10000; /* default reset value? */ + VCPU(vcpu, lrr1) = 0x10000; /* default reset value? */ + update_vhpi(vcpu, NULL_VECTOR); + VLSAPIC_XTP(vcpu) = 0x80; /* disabled */ + + for (i = 0; i < 4; i++) + VLSAPIC_INSVC(vcpu, i) = 0; +} + +void kvm_init_all_rr(VCPU *vcpu) +{ + unsigned long psr; + + local_irq_save(psr); + + /* WARNING: not allow co-exist of both virtual mode and physical + * mode in same region + */ + + vcpu->arch.metaphysical_saved_rr0 = vrrtomrr(VMX(vcpu, vrr[VRN0])); + vcpu->arch.metaphysical_saved_rr4 = vrrtomrr(VMX(vcpu, vrr[VRN4])); + + if (is_physical_mode(vcpu)) { + if (vcpu->arch.mode_flags & GUEST_PHY_EMUL) + panic_vm(vcpu); + + ia64_set_rr((VRN0 << VRN_SHIFT), vcpu->arch.metaphysical_rr0); + ia64_dv_serialize_data(); + ia64_set_rr((VRN4 << VRN_SHIFT), vcpu->arch.metaphysical_rr4); + ia64_dv_serialize_data(); + } else { + ia64_set_rr((VRN0 << VRN_SHIFT), + vcpu->arch.metaphysical_saved_rr0); + ia64_dv_serialize_data(); + ia64_set_rr((VRN4 << VRN_SHIFT), + vcpu->arch.metaphysical_saved_rr4); + ia64_dv_serialize_data(); + } + ia64_set_rr((VRN1 << VRN_SHIFT), + vrrtomrr(VMX(vcpu, vrr[VRN1]))); + ia64_dv_serialize_data(); + ia64_set_rr((VRN2 << VRN_SHIFT), + vrrtomrr(VMX(vcpu, vrr[VRN2]))); + ia64_dv_serialize_data(); + ia64_set_rr((VRN3 << VRN_SHIFT), + vrrtomrr(VMX(vcpu, vrr[VRN3]))); + ia64_dv_serialize_data(); + ia64_set_rr((VRN5 << VRN_SHIFT), + vrrtomrr(VMX(vcpu, vrr[VRN5]))); + ia64_dv_serialize_data(); + ia64_set_rr((VRN7 << VRN_SHIFT), + vrrtomrr(VMX(vcpu, vrr[VRN7]))); + ia64_dv_serialize_data(); + ia64_srlz_d(); + ia64_set_psr(psr); +} + +int vmm_entry(void) +{ + VCPU *v; + v = current_vcpu; + + ia64_call_vsa(PAL_VPS_RESTORE, (unsigned long)v->arch.vpd, + 0, 0, 0, 0, 0, 0); + kvm_init_vtlb(v); + kvm_init_vhpt(v); + init_vcpu(v); + kvm_init_all_rr(v); + vmm_reset_entry(); + + return 0; +} + +void panic_vm(VCPU *v) +{ + struct exit_ctl_data *p = &v->arch.exit_data; + + p->exit_reason = EXIT_REASON_VM_PANIC; + vmm_transition(v); + /*Never to return*/ + while (1); +} + + -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-28 10:07:10
|
>From 0eb62fe62134e844ab66a5c3e43d1021ee56f8a8 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:48:13 +0800 Subject: [PATCH] kvm/ia64: Add trampoline for guest/host mode switch. trampoline.S is for guest/host mode switch. Signed-off-by: Anthony Xu <ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/trampoline.S | 1040 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1040 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/trampoline.S diff --git a/arch/ia64/kvm/trampoline.S b/arch/ia64/kvm/trampoline.S new file mode 100644 index 0000000..d3232b5 --- /dev/null +++ b/arch/ia64/kvm/trampoline.S @@ -0,0 +1,1040 @@ +/* Save all processor states + * + * Copyright (c) 2007 Fleming Feng <fle...@in...> + * Copyright (c) 2007 Anthony Xu <ant...@in...> + */ + +#include <asm/asmmacro.h> +#include "asm-offsets.h" + + +#define CTX(name) VMM_CTX_##name##_OFFSET + + /* + * r32: context_t base address + */ +#define SAVE_BRANCH_REGS \ + add r2 = CTX(B0),r32; \ + add r3 = CTX(B1),r32; \ + mov r16 = b0; \ + mov r17 = b1; \ + ;; \ + st8 [r2]=r16,16; \ + st8 [r3]=r17,16; \ + ;; \ + mov r16 = b2; \ + mov r17 = b3; \ + ;; \ + st8 [r2]=r16,16; \ + st8 [r3]=r17,16; \ + ;; \ + mov r16 = b4; \ + mov r17 = b5; \ + ;; \ + st8 [r2]=r16; \ + st8 [r3]=r17; \ + ;; + + /* + * r33: context_t base address + */ +#define RESTORE_BRANCH_REGS \ + add r2 = CTX(B0),r33; \ + add r3 = CTX(B1),r33; \ + ;; \ + ld8 r16=[r2],16; \ + ld8 r17=[r3],16; \ + ;; \ + mov b0 = r16; \ + mov b1 = r17; \ + ;; \ + ld8 r16=[r2],16; \ + ld8 r17=[r3],16; \ + ;; \ + mov b2 = r16; \ + mov b3 = r17; \ + ;; \ + ld8 r16=[r2]; \ + ld8 r17=[r3]; \ + ;; \ + mov b4=r16; \ + mov b5=r17; \ + ;; + + + /* + * r32: context_t base address + * bsw == 1 + * Save all bank1 general registers, r4 ~ r7 + */ +#define SAVE_GENERAL_REGS \ + add r2=CTX(R4),r32; \ + add r3=CTX(R5),r32; \ + ;; \ +.mem.offset 0,0; \ + st8.spill [r2]=r4,16; \ +.mem.offset 8,0; \ + st8.spill [r3]=r5,16; \ + ;; \ +.mem.offset 0,0; \ + st8.spill [r2]=r6,48; \ +.mem.offset 8,0; \ + st8.spill [r3]=r7,48; \ + ;; \ +.mem.offset 0,0; \ + st8.spill [r2]=r12; \ +.mem.offset 8,0; \ + st8.spill [r3]=r13; \ + ;; + + /* + * r33: context_t base address + * bsw == 1 + */ +#define RESTORE_GENERAL_REGS \ + add r2=CTX(R4),r33; \ + add r3=CTX(R5),r33; \ + ;; \ + ld8.fill r4=[r2],16; \ + ld8.fill r5=[r3],16; \ + ;; \ + ld8.fill r6=[r2],48; \ + ld8.fill r7=[r3],48; \ + ;; \ + ld8.fill r12=[r2]; \ + ld8.fill r13 =[r3]; \ + ;; + + + + + /* + * r32: context_t base address + */ +#define SAVE_KERNEL_REGS \ + add r2 = CTX(KR0),r32; \ + add r3 = CTX(KR1),r32; \ + mov r16 = ar.k0; \ + mov r17 = ar.k1; \ + ;; \ + st8 [r2] = r16,16; \ + st8 [r3] = r17,16; \ + ;; \ + mov r16 = ar.k2; \ + mov r17 = ar.k3; \ + ;; \ + st8 [r2] = r16,16; \ + st8 [r3] = r17,16; \ + ;; \ + mov r16 = ar.k4; \ + mov r17 = ar.k5; \ + ;; \ + st8 [r2] = r16,16; \ + st8 [r3] = r17,16; \ + ;; \ + mov r16 = ar.k6; \ + mov r17 = ar.k7; \ + ;; \ + st8 [r2] = r16; \ + st8 [r3] = r17; \ + ;; + + + + /* + * r33: context_t base address + */ +#define RESTORE_KERNEL_REGS \ + add r2 = CTX(KR0),r33; \ + add r3 = CTX(KR1),r33; \ + ;; \ + ld8 r16=[r2],16; \ + ld8 r17=[r3],16; \ + ;; \ + mov ar.k0=r16; \ + mov ar.k1=r17; \ + ;; \ + ld8 r16=[r2],16; \ + ld8 r17=[r3],16; \ + ;; \ + mov ar.k2=r16; \ + mov ar.k3=r17; \ + ;; \ + ld8 r16=[r2],16; \ + ld8 r17=[r3],16; \ + ;; \ + mov ar.k4=r16; \ + mov ar.k5=r17; \ + ;; \ + ld8 r16=[r2],16; \ + ld8 r17=[r3],16; \ + ;; \ + mov ar.k6=r16; \ + mov ar.k7=r17; \ + ;; + + + + /* + * r32: context_t base address + */ +#define SAVE_APP_REGS \ + add r2 = CTX(BSPSTORE),r32; \ + mov r16 = ar.bspstore; \ + ;; \ + st8 [r2] = r16,CTX(RNAT)-CTX(BSPSTORE);\ + mov r16 = ar.rnat; \ + ;; \ + st8 [r2] = r16,CTX(FCR)-CTX(RNAT); \ + mov r16 = ar.fcr; \ + ;; \ + st8 [r2] = r16,CTX(EFLAG)-CTX(FCR); \ + mov r16 = ar.eflag; \ + ;; \ + st8 [r2] = r16,CTX(CFLG)-CTX(EFLAG); \ + mov r16 = ar.cflg; \ + ;; \ + st8 [r2] = r16,CTX(FSR)-CTX(CFLG); \ + mov r16 = ar.fsr; \ + ;; \ + st8 [r2] = r16,CTX(FIR)-CTX(FSR); \ + mov r16 = ar.fir; \ + ;; \ + st8 [r2] = r16,CTX(FDR)-CTX(FIR); \ + mov r16 = ar.fdr; \ + ;; \ + st8 [r2] = r16,CTX(UNAT)-CTX(FDR); \ + mov r16 = ar.unat; \ + ;; \ + st8 [r2] = r16,CTX(FPSR)-CTX(UNAT); \ + mov r16 = ar.fpsr; \ + ;; \ + st8 [r2] = r16,CTX(PFS)-CTX(FPSR); \ + mov r16 = ar.pfs; \ + ;; \ + st8 [r2] = r16,CTX(LC)-CTX(PFS); \ + mov r16 = ar.lc; \ + ;; \ + st8 [r2] = r16; \ + ;; + + /* + * r33: context_t base address + */ +#define RESTORE_APP_REGS \ + add r2=CTX(BSPSTORE),r33; \ + ;; \ + ld8 r16=[r2],CTX(RNAT)-CTX(BSPSTORE); \ + ;; \ + mov ar.bspstore=r16; \ + ld8 r16=[r2],CTX(FCR)-CTX(RNAT); \ + ;; \ + mov ar.rnat=r16; \ + ld8 r16=[r2],CTX(EFLAG)-CTX(FCR); \ + ;; \ + mov ar.fcr=r16; \ + ld8 r16=[r2],CTX(CFLG)-CTX(EFLAG); \ + ;; \ + mov ar.eflag=r16; \ + ld8 r16=[r2],CTX(FSR)-CTX(CFLG); \ + ;; \ + mov ar.cflg=r16; \ + ld8 r16=[r2],CTX(FIR)-CTX(FSR); \ + ;; \ + mov ar.fsr=r16; \ + ld8 r16=[r2],CTX(FDR)-CTX(FIR); \ + ;; \ + mov ar.fir=r16; \ + ld8 r16=[r2],CTX(UNAT)-CTX(FDR); \ + ;; \ + mov ar.fdr=r16; \ + ld8 r16=[r2],CTX(FPSR)-CTX(UNAT); \ + ;; \ + mov ar.unat=r16; \ + ld8 r16=[r2],CTX(PFS)-CTX(FPSR); \ + ;; \ + mov ar.fpsr=r16; \ + ld8 r16=[r2],CTX(LC)-CTX(PFS); \ + ;; \ + mov ar.pfs=r16; \ + ld8 r16=[r2]; \ + ;; \ + mov ar.lc=r16; \ + ;; + + /* + * r32: context_t base address + */ +#define SAVE_CTL_REGS \ + add r2 = CTX(DCR),r32; \ + mov r16 = cr.dcr; \ + ;; \ + st8 [r2] = r16,CTX(IVA)-CTX(DCR); \ + ;; \ + mov r16 = cr.iva; \ + ;; \ + st8 [r2] = r16,CTX(PTA)-CTX(IVA); \ + ;; \ + mov r16 = cr.pta; \ + ;; \ + st8 [r2] = r16 ; \ + ;; + + /* + * r33: context_t base address + */ +#define RESTORE_CTL_REGS \ + add r2 = CTX(DCR),r33; \ + ;; \ + ld8 r16 = [r2],CTX(IVA)-CTX(DCR); \ + ;; \ + mov cr.dcr = r16; \ + dv_serialize_data; \ + ;; \ + ld8 r16 = [r2],CTX(PTA)-CTX(IVA); \ + ;; \ + mov cr.iva = r16; \ + dv_serialize_data; \ + ;; \ + ld8 r16 = [r2]; \ + ;; \ + mov cr.pta = r16; \ + dv_serialize_data; \ + ;; + + + /* + * r32: context_t base address + */ +#define SAVE_REGION_REGS \ + add r2=CTX(RR0),r32; \ + mov r16=rr[r0]; \ + dep.z r18=1,61,3; \ + ;; \ + st8 [r2]=r16,8; \ + mov r17=rr[r18]; \ + dep.z r18=2,61,3; \ + ;; \ + st8 [r2]=r17,8; \ + mov r16=rr[r18]; \ + dep.z r18=3,61,3; \ + ;; \ + st8 [r2]=r16,8; \ + mov r17=rr[r18]; \ + dep.z r18=4,61,3; \ + ;; \ + st8 [r2]=r17,8; \ + mov r16=rr[r18]; \ + dep.z r18=5,61,3; \ + ;; \ + st8 [r2]=r16,8; \ + mov r17=rr[r18]; \ + dep.z r18=7,61,3; \ + ;; \ + st8 [r2]=r17,16; \ + mov r16=rr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + ;; + + /* + * r33:context_t base address + */ +#define RESTORE_REGION_REGS \ + add r2=CTX(RR0),r33;\ + mov r18=r0; \ + ;; \ + ld8 r20=[r2],8; \ + ;; /* rr0 */ \ + ld8 r21=[r2],8; \ + ;; /* rr1 */ \ + ld8 r22=[r2],8; \ + ;; /* rr2 */ \ + ld8 r23=[r2],8; \ + ;; /* rr3 */ \ + ld8 r24=[r2],8; \ + ;; /* rr4 */ \ + ld8 r25=[r2],16; \ + ;; /* rr5 */ \ + ld8 r27=[r2]; \ + ;; /* rr7 */ \ + mov rr[r18]=r20; \ + dep.z r18=1,61,3; \ + ;; /* rr1 */ \ + mov rr[r18]=r21; \ + dep.z r18=2,61,3; \ + ;; /* rr2 */ \ + mov rr[r18]=r22; \ + dep.z r18=3,61,3; \ + ;; /* rr3 */ \ + mov rr[r18]=r23; \ + dep.z r18=4,61,3; \ + ;; /* rr4 */ \ + mov rr[r18]=r24; \ + dep.z r18=5,61,3; \ + ;; /* rr5 */ \ + mov rr[r18]=r25; \ + dep.z r18=7,61,3; \ + ;; /* rr7 */ \ + mov rr[r18]=r27; \ + ;; \ + srlz.i; \ + ;; + + + + /* + * r32: context_t base address + * r36~r39:scratch registers + */ +#define SAVE_DEBUG_REGS \ + add r2=CTX(IBR0),r32; \ + add r3=CTX(DBR0),r32; \ + mov r16=ibr[r0]; \ + mov r17=dbr[r0]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=1,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=2,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=2,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=3,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=4,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=5,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=6,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + add r18=7,r0; \ + ;; \ + mov r16=ibr[r18]; \ + mov r17=dbr[r18]; \ + ;; \ + st8 [r2]=r16,8; \ + st8 [r3]=r17,8; \ + ;; + + +/* + * r33: point to context_t structure + * ar.lc are corrupted. + */ +#define RESTORE_DEBUG_REGS \ + add r2=CTX(IBR0),r33; \ + add r3=CTX(DBR0),r33; \ + mov r16=7; \ + mov r17=r0; \ + ;; \ + mov ar.lc = r16; \ + ;; \ +1: \ + ld8 r18=[r2],8; \ + ld8 r19=[r3],8; \ + ;; \ + mov ibr[r17]=r18; \ + mov dbr[r17]=r19; \ + ;; \ + srlz.i; \ + ;; \ + add r17=1,r17; \ + br.cloop.sptk 1b; \ + ;; + + + /* + * r32: context_t base address + */ +#define SAVE_FPU_LOW \ + add r2=CTX(F2),r32; \ + add r3=CTX(F3),r32; \ + ;; \ + stf.spill.nta [r2]=f2,32; \ + stf.spill.nta [r3]=f3,32; \ + ;; \ + stf.spill.nta [r2]=f4,32; \ + stf.spill.nta [r3]=f5,32; \ + ;; \ + stf.spill.nta [r2]=f6,32; \ + stf.spill.nta [r3]=f7,32; \ + ;; \ + stf.spill.nta [r2]=f8,32; \ + stf.spill.nta [r3]=f9,32; \ + ;; \ + stf.spill.nta [r2]=f10,32; \ + stf.spill.nta [r3]=f11,32; \ + ;; \ + stf.spill.nta [r2]=f12,32; \ + stf.spill.nta [r3]=f13,32; \ + ;; \ + stf.spill.nta [r2]=f14,32; \ + stf.spill.nta [r3]=f15,32; \ + ;; \ + stf.spill.nta [r2]=f16,32; \ + stf.spill.nta [r3]=f17,32; \ + ;; \ + stf.spill.nta [r2]=f18,32; \ + stf.spill.nta [r3]=f19,32; \ + ;; \ + stf.spill.nta [r2]=f20,32; \ + stf.spill.nta [r3]=f21,32; \ + ;; \ + stf.spill.nta [r2]=f22,32; \ + stf.spill.nta [r3]=f23,32; \ + ;; \ + stf.spill.nta [r2]=f24,32; \ + stf.spill.nta [r3]=f25,32; \ + ;; \ + stf.spill.nta [r2]=f26,32; \ + stf.spill.nta [r3]=f27,32; \ + ;; \ + stf.spill.nta [r2]=f28,32; \ + stf.spill.nta [r3]=f29,32; \ + ;; \ + stf.spill.nta [r2]=f30; \ + stf.spill.nta [r3]=f31; \ + ;; + + /* + * r32: context_t base address + */ +#define SAVE_FPU_HIGH \ + add r2=CTX(F32),r32; \ + add r3=CTX(F33),r32; \ + ;; \ + stf.spill.nta [r2]=f32,32; \ + stf.spill.nta [r3]=f33,32; \ + ;; \ + stf.spill.nta [r2]=f34,32; \ + stf.spill.nta [r3]=f35,32; \ + ;; \ + stf.spill.nta [r2]=f36,32; \ + stf.spill.nta [r3]=f37,32; \ + ;; \ + stf.spill.nta [r2]=f38,32; \ + stf.spill.nta [r3]=f39,32; \ + ;; \ + stf.spill.nta [r2]=f40,32; \ + stf.spill.nta [r3]=f41,32; \ + ;; \ + stf.spill.nta [r2]=f42,32; \ + stf.spill.nta [r3]=f43,32; \ + ;; \ + stf.spill.nta [r2]=f44,32; \ + stf.spill.nta [r3]=f45,32; \ + ;; \ + stf.spill.nta [r2]=f46,32; \ + stf.spill.nta [r3]=f47,32; \ + ;; \ + stf.spill.nta [r2]=f48,32; \ + stf.spill.nta [r3]=f49,32; \ + ;; \ + stf.spill.nta [r2]=f50,32; \ + stf.spill.nta [r3]=f51,32; \ + ;; \ + stf.spill.nta [r2]=f52,32; \ + stf.spill.nta [r3]=f53,32; \ + ;; \ + stf.spill.nta [r2]=f54,32; \ + stf.spill.nta [r3]=f55,32; \ + ;; \ + stf.spill.nta [r2]=f56,32; \ + stf.spill.nta [r3]=f57,32; \ + ;; \ + stf.spill.nta [r2]=f58,32; \ + stf.spill.nta [r3]=f59,32; \ + ;; \ + stf.spill.nta [r2]=f60,32; \ + stf.spill.nta [r3]=f61,32; \ + ;; \ + stf.spill.nta [r2]=f62,32; \ + stf.spill.nta [r3]=f63,32; \ + ;; \ + stf.spill.nta [r2]=f64,32; \ + stf.spill.nta [r3]=f65,32; \ + ;; \ + stf.spill.nta [r2]=f66,32; \ + stf.spill.nta [r3]=f67,32; \ + ;; \ + stf.spill.nta [r2]=f68,32; \ + stf.spill.nta [r3]=f69,32; \ + ;; \ + stf.spill.nta [r2]=f70,32; \ + stf.spill.nta [r3]=f71,32; \ + ;; \ + stf.spill.nta [r2]=f72,32; \ + stf.spill.nta [r3]=f73,32; \ + ;; \ + stf.spill.nta [r2]=f74,32; \ + stf.spill.nta [r3]=f75,32; \ + ;; \ + stf.spill.nta [r2]=f76,32; \ + stf.spill.nta [r3]=f77,32; \ + ;; \ + stf.spill.nta [r2]=f78,32; \ + stf.spill.nta [r3]=f79,32; \ + ;; \ + stf.spill.nta [r2]=f80,32; \ + stf.spill.nta [r3]=f81,32; \ + ;; \ + stf.spill.nta [r2]=f82,32; \ + stf.spill.nta [r3]=f83,32; \ + ;; \ + stf.spill.nta [r2]=f84,32; \ + stf.spill.nta [r3]=f85,32; \ + ;; \ + stf.spill.nta [r2]=f86,32; \ + stf.spill.nta [r3]=f87,32; \ + ;; \ + stf.spill.nta [r2]=f88,32; \ + stf.spill.nta [r3]=f89,32; \ + ;; \ + stf.spill.nta [r2]=f90,32; \ + stf.spill.nta [r3]=f91,32; \ + ;; \ + stf.spill.nta [r2]=f92,32; \ + stf.spill.nta [r3]=f93,32; \ + ;; \ + stf.spill.nta [r2]=f94,32; \ + stf.spill.nta [r3]=f95,32; \ + ;; \ + stf.spill.nta [r2]=f96,32; \ + stf.spill.nta [r3]=f97,32; \ + ;; \ + stf.spill.nta [r2]=f98,32; \ + stf.spill.nta [r3]=f99,32; \ + ;; \ + stf.spill.nta [r2]=f100,32; \ + stf.spill.nta [r3]=f101,32; \ + ;; \ + stf.spill.nta [r2]=f102,32; \ + stf.spill.nta [r3]=f103,32; \ + ;; \ + stf.spill.nta [r2]=f104,32; \ + stf.spill.nta [r3]=f105,32; \ + ;; \ + stf.spill.nta [r2]=f106,32; \ + stf.spill.nta [r3]=f107,32; \ + ;; \ + stf.spill.nta [r2]=f108,32; \ + stf.spill.nta [r3]=f109,32; \ + ;; \ + stf.spill.nta [r2]=f110,32; \ + stf.spill.nta [r3]=f111,32; \ + ;; \ + stf.spill.nta [r2]=f112,32; \ + stf.spill.nta [r3]=f113,32; \ + ;; \ + stf.spill.nta [r2]=f114,32; \ + stf.spill.nta [r3]=f115,32; \ + ;; \ + stf.spill.nta [r2]=f116,32; \ + stf.spill.nta [r3]=f117,32; \ + ;; \ + stf.spill.nta [r2]=f118,32; \ + stf.spill.nta [r3]=f119,32; \ + ;; \ + stf.spill.nta [r2]=f120,32; \ + stf.spill.nta [r3]=f121,32; \ + ;; \ + stf.spill.nta [r2]=f122,32; \ + stf.spill.nta [r3]=f123,32; \ + ;; \ + stf.spill.nta [r2]=f124,32; \ + stf.spill.nta [r3]=f125,32; \ + ;; \ + stf.spill.nta [r2]=f126; \ + stf.spill.nta [r3]=f127; \ + ;; + + /* + * r33: point to context_t structure + */ +#define RESTORE_FPU_LOW \ + add r2 = CTX(F2), r33; \ + add r3 = CTX(F3), r33; \ + ;; \ + ldf.fill.nta f2 = [r2], 32; \ + ldf.fill.nta f3 = [r3], 32; \ + ;; \ + ldf.fill.nta f4 = [r2], 32; \ + ldf.fill.nta f5 = [r3], 32; \ + ;; \ + ldf.fill.nta f6 = [r2], 32; \ + ldf.fill.nta f7 = [r3], 32; \ + ;; \ + ldf.fill.nta f8 = [r2], 32; \ + ldf.fill.nta f9 = [r3], 32; \ + ;; \ + ldf.fill.nta f10 = [r2], 32; \ + ldf.fill.nta f11 = [r3], 32; \ + ;; \ + ldf.fill.nta f12 = [r2], 32; \ + ldf.fill.nta f13 = [r3], 32; \ + ;; \ + ldf.fill.nta f14 = [r2], 32; \ + ldf.fill.nta f15 = [r3], 32; \ + ;; \ + ldf.fill.nta f16 = [r2], 32; \ + ldf.fill.nta f17 = [r3], 32; \ + ;; \ + ldf.fill.nta f18 = [r2], 32; \ + ldf.fill.nta f19 = [r3], 32; \ + ;; \ + ldf.fill.nta f20 = [r2], 32; \ + ldf.fill.nta f21 = [r3], 32; \ + ;; \ + ldf.fill.nta f22 = [r2], 32; \ + ldf.fill.nta f23 = [r3], 32; \ + ;; \ + ldf.fill.nta f24 = [r2], 32; \ + ldf.fill.nta f25 = [r3], 32; \ + ;; \ + ldf.fill.nta f26 = [r2], 32; \ + ldf.fill.nta f27 = [r3], 32; \ + ;; \ + ldf.fill.nta f28 = [r2], 32; \ + ldf.fill.nta f29 = [r3], 32; \ + ;; \ + ldf.fill.nta f30 = [r2], 32; \ + ldf.fill.nta f31 = [r3], 32; \ + ;; + + + + /* + * r33: point to context_t structure + */ +#define RESTORE_FPU_HIGH \ + add r2 = CTX(F32), r33; \ + add r3 = CTX(F33), r33; \ + ;; \ + ldf.fill.nta f32 = [r2], 32; \ + ldf.fill.nta f33 = [r3], 32; \ + ;; \ + ldf.fill.nta f34 = [r2], 32; \ + ldf.fill.nta f35 = [r3], 32; \ + ;; \ + ldf.fill.nta f36 = [r2], 32; \ + ldf.fill.nta f37 = [r3], 32; \ + ;; \ + ldf.fill.nta f38 = [r2], 32; \ + ldf.fill.nta f39 = [r3], 32; \ + ;; \ + ldf.fill.nta f40 = [r2], 32; \ + ldf.fill.nta f41 = [r3], 32; \ + ;; \ + ldf.fill.nta f42 = [r2], 32; \ + ldf.fill.nta f43 = [r3], 32; \ + ;; \ + ldf.fill.nta f44 = [r2], 32; \ + ldf.fill.nta f45 = [r3], 32; \ + ;; \ + ldf.fill.nta f46 = [r2], 32; \ + ldf.fill.nta f47 = [r3], 32; \ + ;; \ + ldf.fill.nta f48 = [r2], 32; \ + ldf.fill.nta f49 = [r3], 32; \ + ;; \ + ldf.fill.nta f50 = [r2], 32; \ + ldf.fill.nta f51 = [r3], 32; \ + ;; \ + ldf.fill.nta f52 = [r2], 32; \ + ldf.fill.nta f53 = [r3], 32; \ + ;; \ + ldf.fill.nta f54 = [r2], 32; \ + ldf.fill.nta f55 = [r3], 32; \ + ;; \ + ldf.fill.nta f56 = [r2], 32; \ + ldf.fill.nta f57 = [r3], 32; \ + ;; \ + ldf.fill.nta f58 = [r2], 32; \ + ldf.fill.nta f59 = [r3], 32; \ + ;; \ + ldf.fill.nta f60 = [r2], 32; \ + ldf.fill.nta f61 = [r3], 32; \ + ;; \ + ldf.fill.nta f62 = [r2], 32; \ + ldf.fill.nta f63 = [r3], 32; \ + ;; \ + ldf.fill.nta f64 = [r2], 32; \ + ldf.fill.nta f65 = [r3], 32; \ + ;; \ + ldf.fill.nta f66 = [r2], 32; \ + ldf.fill.nta f67 = [r3], 32; \ + ;; \ + ldf.fill.nta f68 = [r2], 32; \ + ldf.fill.nta f69 = [r3], 32; \ + ;; \ + ldf.fill.nta f70 = [r2], 32; \ + ldf.fill.nta f71 = [r3], 32; \ + ;; \ + ldf.fill.nta f72 = [r2], 32; \ + ldf.fill.nta f73 = [r3], 32; \ + ;; \ + ldf.fill.nta f74 = [r2], 32; \ + ldf.fill.nta f75 = [r3], 32; \ + ;; \ + ldf.fill.nta f76 = [r2], 32; \ + ldf.fill.nta f77 = [r3], 32; \ + ;; \ + ldf.fill.nta f78 = [r2], 32; \ + ldf.fill.nta f79 = [r3], 32; \ + ;; \ + ldf.fill.nta f80 = [r2], 32; \ + ldf.fill.nta f81 = [r3], 32; \ + ;; \ + ldf.fill.nta f82 = [r2], 32; \ + ldf.fill.nta f83 = [r3], 32; \ + ;; \ + ldf.fill.nta f84 = [r2], 32; \ + ldf.fill.nta f85 = [r3], 32; \ + ;; \ + ldf.fill.nta f86 = [r2], 32; \ + ldf.fill.nta f87 = [r3], 32; \ + ;; \ + ldf.fill.nta f88 = [r2], 32; \ + ldf.fill.nta f89 = [r3], 32; \ + ;; \ + ldf.fill.nta f90 = [r2], 32; \ + ldf.fill.nta f91 = [r3], 32; \ + ;; \ + ldf.fill.nta f92 = [r2], 32; \ + ldf.fill.nta f93 = [r3], 32; \ + ;; \ + ldf.fill.nta f94 = [r2], 32; \ + ldf.fill.nta f95 = [r3], 32; \ + ;; \ + ldf.fill.nta f96 = [r2], 32; \ + ldf.fill.nta f97 = [r3], 32; \ + ;; \ + ldf.fill.nta f98 = [r2], 32; \ + ldf.fill.nta f99 = [r3], 32; \ + ;; \ + ldf.fill.nta f100 = [r2], 32; \ + ldf.fill.nta f101 = [r3], 32; \ + ;; \ + ldf.fill.nta f102 = [r2], 32; \ + ldf.fill.nta f103 = [r3], 32; \ + ;; \ + ldf.fill.nta f104 = [r2], 32; \ + ldf.fill.nta f105 = [r3], 32; \ + ;; \ + ldf.fill.nta f106 = [r2], 32; \ + ldf.fill.nta f107 = [r3], 32; \ + ;; \ + ldf.fill.nta f108 = [r2], 32; \ + ldf.fill.nta f109 = [r3], 32; \ + ;; \ + ldf.fill.nta f110 = [r2], 32; \ + ldf.fill.nta f111 = [r3], 32; \ + ;; \ + ldf.fill.nta f112 = [r2], 32; \ + ldf.fill.nta f113 = [r3], 32; \ + ;; \ + ldf.fill.nta f114 = [r2], 32; \ + ldf.fill.nta f115 = [r3], 32; \ + ;; \ + ldf.fill.nta f116 = [r2], 32; \ + ldf.fill.nta f117 = [r3], 32; \ + ;; \ + ldf.fill.nta f118 = [r2], 32; \ + ldf.fill.nta f119 = [r3], 32; \ + ;; \ + ldf.fill.nta f120 = [r2], 32; \ + ldf.fill.nta f121 = [r3], 32; \ + ;; \ + ldf.fill.nta f122 = [r2], 32; \ + ldf.fill.nta f123 = [r3], 32; \ + ;; \ + ldf.fill.nta f124 = [r2], 32; \ + ldf.fill.nta f125 = [r3], 32; \ + ;; \ + ldf.fill.nta f126 = [r2], 32; \ + ldf.fill.nta f127 = [r3], 32; \ + ;; + + /* + * r32: context_t base address + */ +#define SAVE_PTK_REGS \ + add r2=CTX(PKR0), r32; \ + mov r16=7; \ + ;; \ + mov ar.lc=r16; \ + mov r17=r0; \ + ;; \ +1: \ + mov r18=pkr[r17]; \ + ;; \ + srlz.i; \ + ;; \ + st8 [r2]=r18, 8; \ + ;; \ + add r17 =1,r17; \ + ;; \ + br.cloop.sptk 1b; \ + ;; + +/* + * r33: point to context_t structure + * ar.lc are corrupted. + */ +#define RESTORE_PTK_REGS \ + add r2=CTX(PKR0), r33; \ + mov r16=7; \ + ;; \ + mov ar.lc=r16; \ + mov r17=r0; \ + ;; \ +1: \ + ld8 r18=[r2], 8; \ + ;; \ + mov pkr[r17]=r18; \ + ;; \ + srlz.i; \ + ;; \ + add r17 =1,r17; \ + ;; \ + br.cloop.sptk 1b; \ + ;; + + +/* + * void vmm_trampoline( context_t * from, + * context_t * to) + * + * from: r32 + * to: r33 + * note: interrupt disabled before call this function. + */ +GLOBAL_ENTRY(vmm_trampoline) + mov r16 = psr + adds r2 = CTX(PSR), r32 + ;; + st8 [r2] = r16, 8 // psr + mov r17 = pr + ;; + st8 [r2] = r17, 8 // pr + mov r18 = ar.unat + ;; + st8 [r2] = r18 + mov r17 = ar.rsc + ;; + adds r2 = CTX(RSC),r32 + ;; + st8 [r2]= r17 + mov ar.rsc =0 + flushrs + ;; + SAVE_GENERAL_REGS + ;; + SAVE_KERNEL_REGS + ;; + SAVE_APP_REGS + ;; + SAVE_BRANCH_REGS + ;; + SAVE_CTL_REGS + ;; + SAVE_REGION_REGS + ;; + //SAVE_DEBUG_REGS + ;; + rsm psr.dfl + ;; + srlz.d + ;; + SAVE_FPU_LOW + ;; + rsm psr.dfh + ;; + srlz.d + ;; + SAVE_FPU_HIGH + ;; + SAVE_PTK_REGS + ;; + RESTORE_PTK_REGS + ;; + RESTORE_FPU_HIGH + ;; + RESTORE_FPU_LOW + ;; + //RESTORE_DEBUG_REGS + ;; + RESTORE_REGION_REGS + ;; + RESTORE_CTL_REGS + ;; + RESTORE_BRANCH_REGS + ;; + RESTORE_APP_REGS + ;; + RESTORE_KERNEL_REGS + ;; + RESTORE_GENERAL_REGS + ;; + adds r2=CTX(PSR), r33 + ;; + ld8 r16=[r2], 8 // psr + ;; + mov psr.l=r16 + ;; + srlz.d + ;; + ld8 r16=[r2], 8 // pr + ;; + mov pr =r16,-1 + ld8 r16=[r2] // unat + ;; + mov ar.unat=r16 + ;; + adds r2=CTX(RSC),r33 + ;; + ld8 r16 =[r2] + ;; + mov ar.rsc = r16 + ;; + br.ret.sptk.few b0 +END(vmm_trampoline) + + -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-28 10:07:05
|
>From 2dbf7c93ff5e36a221761c690ff12e7be48a6bb2 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:49:38 +0800 Subject: [PATCH] kvm/ia64: add optimization for some virtulization faults optvfault.S adds optimization for some performance-critical virtualization faults. Signed-off-by: Anthony Xu <ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/optvfault.S | 918 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 918 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/optvfault.S diff --git a/arch/ia64/kvm/optvfault.S b/arch/ia64/kvm/optvfault.S new file mode 100644 index 0000000..5de210e --- /dev/null +++ b/arch/ia64/kvm/optvfault.S @@ -0,0 +1,918 @@ +/* + * arch/ia64/vmx/optvfault.S + * optimize virtualization fault handler + * + * Copyright (C) 2006 Intel Co + * Xuefei Xu (Anthony Xu) <ant...@in...> + */ + +#include <asm/asmmacro.h> +#include <asm/processor.h> + +#include "vti.h" +#include "asm-offsets.h" + +#define ACCE_MOV_FROM_AR +#define ACCE_MOV_FROM_RR +#define ACCE_MOV_TO_RR +#define ACCE_RSM +#define ACCE_SSM +#define ACCE_MOV_TO_PSR +#define ACCE_THASH + +//mov r1=ar3 +GLOBAL_ENTRY(kvm_asm_mov_from_ar) +#ifndef ACCE_MOV_FROM_AR + br.many kvm_virtualization_fault_back +#endif + add r18=VMM_VCPU_ITC_OFS_OFFSET, r21 + add r16=VMM_VCPU_LAST_ITC_OFFSET,r21 + extr.u r17=r25,6,7 + ;; + ld8 r18=[r18] + mov r19=ar.itc + mov r24=b0 + ;; + add r19=r19,r18 + addl r20=@gprel(asm_mov_to_reg),gp + ;; + st8 [r16] = r19 + adds r30=kvm_resume_to_guest-asm_mov_to_reg,r20 + shladd r17=r17,4,r20 + ;; + mov b0=r17 + br.sptk.few b0 + ;; +END(kvm_asm_mov_from_ar) + + +// mov r1=rr[r3] +GLOBAL_ENTRY(kvm_asm_mov_from_rr) +#ifndef ACCE_MOV_FROM_RR + br.many kvm_virtualization_fault_back +#endif + extr.u r16=r25,20,7 + extr.u r17=r25,6,7 + addl r20=@gprel(asm_mov_from_reg),gp + ;; + adds r30=kvm_asm_mov_from_rr_back_1-asm_mov_from_reg,r20 + shladd r16=r16,4,r20 + mov r24=b0 + ;; + add r27=VMM_VCPU_VRR0_OFFSET,r21 + mov b0=r16 + br.many b0 + ;; +kvm_asm_mov_from_rr_back_1: + adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20 + adds r22=asm_mov_to_reg-asm_mov_from_reg,r20 + shr.u r26=r19,61 + ;; + shladd r17=r17,4,r22 + shladd r27=r26,3,r27 + ;; + ld8 r19=[r27] + mov b0=r17 + br.many b0 +END(kvm_asm_mov_from_rr) + + +// mov rr[r3]=r2 +GLOBAL_ENTRY(kvm_asm_mov_to_rr) +#ifndef ACCE_MOV_TO_RR + br.many kvm_virtualization_fault_back +#endif + extr.u r16=r25,20,7 + extr.u r17=r25,13,7 + addl r20=@gprel(asm_mov_from_reg),gp + ;; + adds r30=kvm_asm_mov_to_rr_back_1-asm_mov_from_reg,r20 + shladd r16=r16,4,r20 + mov r22=b0 + ;; + add r27=VMM_VCPU_VRR0_OFFSET,r21 + mov b0=r16 + br.many b0 + ;; +kvm_asm_mov_to_rr_back_1: + adds r30=kvm_asm_mov_to_rr_back_2-asm_mov_from_reg,r20 + shr.u r23=r19,61 + shladd r17=r17,4,r20 + ;; + //if rr6, go back + cmp.eq p6,p0=6,r23 + mov b0=r22 + (p6) br.cond.dpnt.many kvm_virtualization_fault_back + ;; + mov r28=r19 + mov b0=r17 + br.many b0 +kvm_asm_mov_to_rr_back_2: + adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20 + shladd r27=r23,3,r27 + ;; // vrr.rid<<4 |0xe + st8 [r27]=r19 + mov b0=r30 + ;; + extr.u r16=r19,8,26 + extr.u r18 =r19,2,6 + mov r17 =0xe + ;; + shladd r16 = r16, 4, r17 + extr.u r19 =r19,0,8 + ;; + shl r16 = r16,8 + ;; + add r19 = r19, r16 + ;; //set ve 1 + dep r19=-1,r19,0,1 + cmp.lt p6,p0=14,r18 + ;; + (p6) mov r18=14 + ;; + (p6) dep r19=r18,r19,2,6 + ;; + cmp.eq p6,p0=0,r23 + ;; + cmp.eq.or p6,p0=4,r23 + ;; + adds r16=VMM_VCPU_MODE_FLAGS_OFFSET,r21 + (p6) adds r17=VMM_VCPU_META_SAVED_RR0_OFFSET,r21 + ;; + ld4 r16=[r16] + cmp.eq p7,p0=r0,r0 + (p6) shladd r17=r23,1,r17 + ;; + (p6) st8 [r17]=r19 + (p6) tbit.nz p6,p7=r16,0 + ;; + (p7) mov rr[r28]=r19 + mov r24=r22 + br.many b0 +END(kvm_asm_mov_to_rr) + + +//rsm +GLOBAL_ENTRY(kvm_asm_rsm) +#ifndef ACCE_RSM + br.many kvm_virtualization_fault_back +#endif + add r16=VMM_VPD_BASE_OFFSET,r21 + extr.u r26=r25,6,21 + extr.u r27=r25,31,2 + ;; + ld8 r16=[r16] + extr.u r28=r25,36,1 + dep r26=r27,r26,21,2 + ;; + add r17=VPD_VPSR_START_OFFSET,r16 + add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21 + //r26 is imm24 + dep r26=r28,r26,23,1 + ;; + ld8 r18=[r17] + movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI + ld4 r23=[r22] + sub r27=-1,r26 + mov r24=b0 + ;; + mov r20=cr.ipsr + or r28=r27,r28 + and r19=r18,r27 + ;; + st8 [r17]=r19 + and r20=r20,r28 + /* Comment it out due to short of fp lazy alorgithm support + adds r27=IA64_VCPU_FP_PSR_OFFSET,r21 + ;; + ld8 r27=[r27] + ;; + tbit.nz p8,p0= r27,IA64_PSR_DFH_BIT + ;; + (p8) dep r20=-1,r20,IA64_PSR_DFH_BIT,1 + */ + ;; + mov cr.ipsr=r20 + tbit.nz p6,p0=r23,0 + ;; + tbit.z.or p6,p0=r26,IA64_PSR_DT_BIT + (p6) br.dptk kvm_resume_to_guest + ;; + add r26=VMM_VCPU_META_RR0_OFFSET,r21 + add r27=VMM_VCPU_META_RR0_OFFSET+8,r21 + dep r23=-1,r23,0,1 + ;; + ld8 r26=[r26] + ld8 r27=[r27] + st4 [r22]=r23 + dep.z r28=4,61,3 + ;; + mov rr[r0]=r26 + ;; + mov rr[r28]=r27 + ;; + srlz.d + br.many kvm_resume_to_guest +END(kvm_asm_rsm) + + +//ssm +GLOBAL_ENTRY(kvm_asm_ssm) +#ifndef ACCE_SSM + br.many kvm_virtualization_fault_back +#endif + add r16=VMM_VPD_BASE_OFFSET,r21 + extr.u r26=r25,6,21 + extr.u r27=r25,31,2 + ;; + ld8 r16=[r16] + extr.u r28=r25,36,1 + dep r26=r27,r26,21,2 + ;; //r26 is imm24 + add r27=VPD_VPSR_START_OFFSET,r16 + dep r26=r28,r26,23,1 + ;; //r19 vpsr + ld8 r29=[r27] + mov r24=b0 + ;; + add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21 + mov r20=cr.ipsr + or r19=r29,r26 + ;; + ld4 r23=[r22] + st8 [r27]=r19 + or r20=r20,r26 + ;; + mov cr.ipsr=r20 + movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT + ;; + and r19=r28,r19 + tbit.z p6,p0=r23,0 + ;; + cmp.ne.or p6,p0=r28,r19 + (p6) br.dptk kvm_asm_ssm_1 + ;; + add r26=VMM_VCPU_META_SAVED_RR0_OFFSET,r21 + add r27=VMM_VCPU_META_SAVED_RR0_OFFSET+8,r21 + dep r23=0,r23,0,1 + ;; + ld8 r26=[r26] + ld8 r27=[r27] + st4 [r22]=r23 + dep.z r28=4,61,3 + ;; + mov rr[r0]=r26 + ;; + mov rr[r28]=r27 + ;; + srlz.d + ;; +kvm_asm_ssm_1: + tbit.nz p6,p0=r29,IA64_PSR_I_BIT + ;; + tbit.z.or p6,p0=r19,IA64_PSR_I_BIT + (p6) br.dptk kvm_resume_to_guest + ;; + add r29=VPD_VTPR_START_OFFSET,r16 + add r30=VPD_VHPI_START_OFFSET,r16 + ;; + ld8 r29=[r29] + ld8 r30=[r30] + ;; + extr.u r17=r29,4,4 + extr.u r18=r29,16,1 + ;; + dep r17=r18,r17,4,1 + ;; + cmp.gt p6,p0=r30,r17 + (p6) br.dpnt.few kvm_asm_dispatch_vexirq + br.many kvm_resume_to_guest +END(kvm_asm_ssm) + + +//mov psr.l=r2 +GLOBAL_ENTRY(kvm_asm_mov_to_psr) +#ifndef ACCE_MOV_TO_PSR + br.many kvm_virtualization_fault_back +#endif + add r16=VMM_VPD_BASE_OFFSET,r21 + extr.u r26=r25,13,7 //r2 + ;; + ld8 r16=[r16] + addl r20=@gprel(asm_mov_from_reg),gp + ;; + adds r30=kvm_asm_mov_to_psr_back-asm_mov_from_reg,r20 + shladd r26=r26,4,r20 + mov r24=b0 + ;; + add r27=VPD_VPSR_START_OFFSET,r16 + mov b0=r26 + br.many b0 + ;; +kvm_asm_mov_to_psr_back: + ld8 r17=[r27] + add r22=VMM_VCPU_MODE_FLAGS_OFFSET,r21 + dep r19=0,r19,32,32 + ;; + ld4 r23=[r22] + dep r18=0,r17,0,32 + ;; + add r30=r18,r19 + movl r28=IA64_PSR_DT+IA64_PSR_RT+IA64_PSR_IT + ;; + st8 [r27]=r30 + and r27=r28,r30 + and r29=r28,r17 + ;; + cmp.eq p5,p0=r29,r27 + cmp.eq p6,p7=r28,r27 + (p5) br.many kvm_asm_mov_to_psr_1 + ;; + //virtual to physical + (p7) add r26=VMM_VCPU_META_RR0_OFFSET,r21 + (p7) add r27=VMM_VCPU_META_RR0_OFFSET+8,r21 + (p7) dep r23=-1,r23,0,1 + ;; + //physical to virtual + (p6) add r26=VMM_VCPU_META_SAVED_RR0_OFFSET,r21 + (p6) add r27=VMM_VCPU_META_SAVED_RR0_OFFSET+8,r21 + (p6) dep r23=0,r23,0,1 + ;; + ld8 r26=[r26] + ld8 r27=[r27] + st4 [r22]=r23 + dep.z r28=4,61,3 + ;; + mov rr[r0]=r26 + ;; + mov rr[r28]=r27 + ;; + srlz.d + ;; +kvm_asm_mov_to_psr_1: + mov r20=cr.ipsr + movl r28=IA64_PSR_IC+IA64_PSR_I+IA64_PSR_DT+IA64_PSR_SI+IA64_PSR_RT + ;; + or r19=r19,r28 + dep r20=0,r20,0,32 + ;; + add r20=r19,r20 + mov b0=r24 + ;; + /* Comment it out due to short of fp lazy algorithm support + adds r27=IA64_VCPU_FP_PSR_OFFSET,r21 + ;; + ld8 r27=[r27] + ;; + tbit.nz p8,p0=r27,IA64_PSR_DFH_BIT + ;; + (p8) dep r20=-1,r20,IA64_PSR_DFH_BIT,1 + ;; + */ + mov cr.ipsr=r20 + cmp.ne p6,p0=r0,r0 + ;; + tbit.nz.or p6,p0=r17,IA64_PSR_I_BIT + tbit.z.or p6,p0=r30,IA64_PSR_I_BIT + (p6) br.dpnt.few kvm_resume_to_guest + ;; + add r29=VPD_VTPR_START_OFFSET,r16 + add r30=VPD_VHPI_START_OFFSET,r16 + ;; + ld8 r29=[r29] + ld8 r30=[r30] + ;; + extr.u r17=r29,4,4 + extr.u r18=r29,16,1 + ;; + dep r17=r18,r17,4,1 + ;; + cmp.gt p6,p0=r30,r17 + (p6) br.dpnt.few kvm_asm_dispatch_vexirq + br.many kvm_resume_to_guest +END(kvm_asm_mov_to_psr) + + +ENTRY(kvm_asm_dispatch_vexirq) +//increment iip + mov r16=cr.ipsr + ;; + extr.u r17=r16,IA64_PSR_RI_BIT,2 + tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1 + ;; + (p6) mov r18=cr.iip + (p6) mov r17=r0 + (p7) add r17=1,r17 + ;; + (p6) add r18=0x10,r18 + dep r16=r17,r16,IA64_PSR_RI_BIT,2 + ;; + (p6) mov cr.iip=r18 + mov cr.ipsr=r16 + mov r30 =1 + br.many kvm_dispatch_vexirq +END(kvm_asm_dispatch_vexirq) + +// thash +// TODO: add support when pta.vf = 1 +GLOBAL_ENTRY(kvm_asm_thash) +#ifndef ACCE_THASH + br.many kvm_virtualization_fault_back +#endif + extr.u r17=r25,20,7 // get r3 from opcode in r25 + extr.u r18=r25,6,7 // get r1 from opcode in r25 + addl r20=@gprel(asm_mov_from_reg),gp + ;; + adds r30=kvm_asm_thash_back1-asm_mov_from_reg,r20 + shladd r17=r17,4,r20 // get addr of MOVE_FROM_REG(r17) + adds r16=VMM_VPD_BASE_OFFSET,r21 // get vcpu.arch.priveregs + ;; + mov r24=b0 + ;; + ld8 r16=[r16] // get VPD addr + mov b0=r17 + br.many b0 // r19 return value + ;; +kvm_asm_thash_back1: + shr.u r23=r19,61 // get RR number + adds r25=VMM_VCPU_VRR0_OFFSET,r21 // get vcpu->arch.vrr[0]'s addr + adds r16=VMM_VPD_VPTA_OFFSET,r16 // get vpta + ;; + shladd r27=r23,3,r25 // get vcpu->arch.vrr[r23]'s addr + ld8 r17=[r16] // get PTA + mov r26=1 + ;; + extr.u r29=r17,2,6 // get pta.size + ld8 r25=[r27] // get vcpu->arch.vrr[r23]'s value + ;; + extr.u r25=r25,2,6 // get rr.ps + shl r22=r26,r29 // 1UL << pta.size + ;; + shr.u r23=r19,r25 // vaddr >> rr.ps + adds r26=3,r29 // pta.size + 3 + shl r27=r17,3 // pta << 3 + ;; + shl r23=r23,3 // (vaddr >> rr.ps) << 3 + shr.u r27=r27,r26 // (pta << 3) >> (pta.size+3) + movl r16=7<<61 + ;; + adds r22=-1,r22 // (1UL << pta.size) - 1 + shl r27=r27,r29 // ((pta<<3)>>(pta.size+3))<<pta.size + and r19=r19,r16 // vaddr & VRN_MASK + ;; + and r22=r22,r23 // vhpt_offset + or r19=r19,r27 // (vadr&VRN_MASK) |(((pta<<3)>>(pta.size + 3))<<pta.size) + adds r26=asm_mov_to_reg-asm_mov_from_reg,r20 + ;; + or r19=r19,r22 // calc pval + shladd r17=r18,4,r26 + adds r30=kvm_resume_to_guest-asm_mov_from_reg,r20 + ;; + mov b0=r17 + br.many b0 +END(kvm_asm_thash) + +#define MOV_TO_REG0 \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + nop.b 0x0; \ + ;; \ +}; + + +#define MOV_TO_REG(n) \ +{; \ + mov r##n##=r19; \ + mov b0=r30; \ + br.sptk.many b0; \ + ;; \ +}; + + +#define MOV_FROM_REG(n) \ +{; \ + mov r19=r##n##; \ + mov b0=r30; \ + br.sptk.many b0; \ + ;; \ +}; + + +#define MOV_TO_BANK0_REG(n) \ +ENTRY_MIN_ALIGN(asm_mov_to_bank0_reg##n##); \ +{; \ + mov r26=r2; \ + mov r2=r19; \ + bsw.1; \ + ;; \ +}; \ +{; \ + mov r##n##=r2; \ + nop.b 0x0; \ + bsw.0; \ + ;; \ +}; \ +{; \ + mov r2=r26; \ + mov b0=r30; \ + br.sptk.many b0; \ + ;; \ +}; \ +END(asm_mov_to_bank0_reg##n##) + + +#define MOV_FROM_BANK0_REG(n) \ +ENTRY_MIN_ALIGN(asm_mov_from_bank0_reg##n##); \ +{; \ + mov r26=r2; \ + nop.b 0x0; \ + bsw.1; \ + ;; \ +}; \ +{; \ + mov r2=r##n##; \ + nop.b 0x0; \ + bsw.0; \ + ;; \ +}; \ +{; \ + mov r19=r2; \ + mov r2=r26; \ + mov b0=r30; \ +}; \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + br.sptk.many b0; \ + ;; \ +}; \ +END(asm_mov_from_bank0_reg##n##) + + +#define JMP_TO_MOV_TO_BANK0_REG(n) \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + br.sptk.many asm_mov_to_bank0_reg##n##; \ + ;; \ +} + + +#define JMP_TO_MOV_FROM_BANK0_REG(n) \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + br.sptk.many asm_mov_from_bank0_reg##n##; \ + ;; \ +} + + +MOV_FROM_BANK0_REG(16) +MOV_FROM_BANK0_REG(17) +MOV_FROM_BANK0_REG(18) +MOV_FROM_BANK0_REG(19) +MOV_FROM_BANK0_REG(20) +MOV_FROM_BANK0_REG(21) +MOV_FROM_BANK0_REG(22) +MOV_FROM_BANK0_REG(23) +MOV_FROM_BANK0_REG(24) +MOV_FROM_BANK0_REG(25) +MOV_FROM_BANK0_REG(26) +MOV_FROM_BANK0_REG(27) +MOV_FROM_BANK0_REG(28) +MOV_FROM_BANK0_REG(29) +MOV_FROM_BANK0_REG(30) +MOV_FROM_BANK0_REG(31) + + +// mov from reg table +ENTRY(asm_mov_from_reg) + MOV_FROM_REG(0) + MOV_FROM_REG(1) + MOV_FROM_REG(2) + MOV_FROM_REG(3) + MOV_FROM_REG(4) + MOV_FROM_REG(5) + MOV_FROM_REG(6) + MOV_FROM_REG(7) + MOV_FROM_REG(8) + MOV_FROM_REG(9) + MOV_FROM_REG(10) + MOV_FROM_REG(11) + MOV_FROM_REG(12) + MOV_FROM_REG(13) + MOV_FROM_REG(14) + MOV_FROM_REG(15) + JMP_TO_MOV_FROM_BANK0_REG(16) + JMP_TO_MOV_FROM_BANK0_REG(17) + JMP_TO_MOV_FROM_BANK0_REG(18) + JMP_TO_MOV_FROM_BANK0_REG(19) + JMP_TO_MOV_FROM_BANK0_REG(20) + JMP_TO_MOV_FROM_BANK0_REG(21) + JMP_TO_MOV_FROM_BANK0_REG(22) + JMP_TO_MOV_FROM_BANK0_REG(23) + JMP_TO_MOV_FROM_BANK0_REG(24) + JMP_TO_MOV_FROM_BANK0_REG(25) + JMP_TO_MOV_FROM_BANK0_REG(26) + JMP_TO_MOV_FROM_BANK0_REG(27) + JMP_TO_MOV_FROM_BANK0_REG(28) + JMP_TO_MOV_FROM_BANK0_REG(29) + JMP_TO_MOV_FROM_BANK0_REG(30) + JMP_TO_MOV_FROM_BANK0_REG(31) + MOV_FROM_REG(32) + MOV_FROM_REG(33) + MOV_FROM_REG(34) + MOV_FROM_REG(35) + MOV_FROM_REG(36) + MOV_FROM_REG(37) + MOV_FROM_REG(38) + MOV_FROM_REG(39) + MOV_FROM_REG(40) + MOV_FROM_REG(41) + MOV_FROM_REG(42) + MOV_FROM_REG(43) + MOV_FROM_REG(44) + MOV_FROM_REG(45) + MOV_FROM_REG(46) + MOV_FROM_REG(47) + MOV_FROM_REG(48) + MOV_FROM_REG(49) + MOV_FROM_REG(50) + MOV_FROM_REG(51) + MOV_FROM_REG(52) + MOV_FROM_REG(53) + MOV_FROM_REG(54) + MOV_FROM_REG(55) + MOV_FROM_REG(56) + MOV_FROM_REG(57) + MOV_FROM_REG(58) + MOV_FROM_REG(59) + MOV_FROM_REG(60) + MOV_FROM_REG(61) + MOV_FROM_REG(62) + MOV_FROM_REG(63) + MOV_FROM_REG(64) + MOV_FROM_REG(65) + MOV_FROM_REG(66) + MOV_FROM_REG(67) + MOV_FROM_REG(68) + MOV_FROM_REG(69) + MOV_FROM_REG(70) + MOV_FROM_REG(71) + MOV_FROM_REG(72) + MOV_FROM_REG(73) + MOV_FROM_REG(74) + MOV_FROM_REG(75) + MOV_FROM_REG(76) + MOV_FROM_REG(77) + MOV_FROM_REG(78) + MOV_FROM_REG(79) + MOV_FROM_REG(80) + MOV_FROM_REG(81) + MOV_FROM_REG(82) + MOV_FROM_REG(83) + MOV_FROM_REG(84) + MOV_FROM_REG(85) + MOV_FROM_REG(86) + MOV_FROM_REG(87) + MOV_FROM_REG(88) + MOV_FROM_REG(89) + MOV_FROM_REG(90) + MOV_FROM_REG(91) + MOV_FROM_REG(92) + MOV_FROM_REG(93) + MOV_FROM_REG(94) + MOV_FROM_REG(95) + MOV_FROM_REG(96) + MOV_FROM_REG(97) + MOV_FROM_REG(98) + MOV_FROM_REG(99) + MOV_FROM_REG(100) + MOV_FROM_REG(101) + MOV_FROM_REG(102) + MOV_FROM_REG(103) + MOV_FROM_REG(104) + MOV_FROM_REG(105) + MOV_FROM_REG(106) + MOV_FROM_REG(107) + MOV_FROM_REG(108) + MOV_FROM_REG(109) + MOV_FROM_REG(110) + MOV_FROM_REG(111) + MOV_FROM_REG(112) + MOV_FROM_REG(113) + MOV_FROM_REG(114) + MOV_FROM_REG(115) + MOV_FROM_REG(116) + MOV_FROM_REG(117) + MOV_FROM_REG(118) + MOV_FROM_REG(119) + MOV_FROM_REG(120) + MOV_FROM_REG(121) + MOV_FROM_REG(122) + MOV_FROM_REG(123) + MOV_FROM_REG(124) + MOV_FROM_REG(125) + MOV_FROM_REG(126) + MOV_FROM_REG(127) +END(asm_mov_from_reg) + + +/* must be in bank 0 + * parameter: + * r31: pr + * r24: b0 + */ +ENTRY(kvm_resume_to_guest) + adds r16 = VMM_VCPU_SAVED_GP_OFFSET,r21 + ;; + ld8 r1 =[r16] + adds r20 = VMM_VCPU_VSA_BASE_OFFSET,r21 + ;; + mov r16=cr.ipsr + ;; + ld8 r20 = [r20] + adds r19=VMM_VPD_BASE_OFFSET,r21 + ;; + ld8 r25=[r19] + extr.u r17=r16,IA64_PSR_RI_BIT,2 + tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1 + ;; + (p6) mov r18=cr.iip + (p6) mov r17=r0 + ;; + (p6) add r18=0x10,r18 + (p7) add r17=1,r17 + ;; + (p6) mov cr.iip=r18 + dep r16=r17,r16,IA64_PSR_RI_BIT,2 + ;; + mov cr.ipsr=r16 + adds r19= VPD_VPSR_START_OFFSET,r25 + add r28=PAL_VPS_RESUME_NORMAL,r20 + add r29=PAL_VPS_RESUME_HANDLER,r20 + ;; + ld8 r19=[r19] + mov b0=r29 + cmp.ne p6,p7 = r0,r0 + ;; + tbit.z p6,p7 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic + ;; + (p6) ld8 r26=[r25] + (p7) mov b0=r28 + mov pr=r31,-2 + br.sptk.many b0 // call pal service + ;; +END(kvm_resume_to_guest) + + +MOV_TO_BANK0_REG(16) +MOV_TO_BANK0_REG(17) +MOV_TO_BANK0_REG(18) +MOV_TO_BANK0_REG(19) +MOV_TO_BANK0_REG(20) +MOV_TO_BANK0_REG(21) +MOV_TO_BANK0_REG(22) +MOV_TO_BANK0_REG(23) +MOV_TO_BANK0_REG(24) +MOV_TO_BANK0_REG(25) +MOV_TO_BANK0_REG(26) +MOV_TO_BANK0_REG(27) +MOV_TO_BANK0_REG(28) +MOV_TO_BANK0_REG(29) +MOV_TO_BANK0_REG(30) +MOV_TO_BANK0_REG(31) + + +// mov to reg table +ENTRY(asm_mov_to_reg) + MOV_TO_REG0 + MOV_TO_REG(1) + MOV_TO_REG(2) + MOV_TO_REG(3) + MOV_TO_REG(4) + MOV_TO_REG(5) + MOV_TO_REG(6) + MOV_TO_REG(7) + MOV_TO_REG(8) + MOV_TO_REG(9) + MOV_TO_REG(10) + MOV_TO_REG(11) + MOV_TO_REG(12) + MOV_TO_REG(13) + MOV_TO_REG(14) + MOV_TO_REG(15) + JMP_TO_MOV_TO_BANK0_REG(16) + JMP_TO_MOV_TO_BANK0_REG(17) + JMP_TO_MOV_TO_BANK0_REG(18) + JMP_TO_MOV_TO_BANK0_REG(19) + JMP_TO_MOV_TO_BANK0_REG(20) + JMP_TO_MOV_TO_BANK0_REG(21) + JMP_TO_MOV_TO_BANK0_REG(22) + JMP_TO_MOV_TO_BANK0_REG(23) + JMP_TO_MOV_TO_BANK0_REG(24) + JMP_TO_MOV_TO_BANK0_REG(25) + JMP_TO_MOV_TO_BANK0_REG(26) + JMP_TO_MOV_TO_BANK0_REG(27) + JMP_TO_MOV_TO_BANK0_REG(28) + JMP_TO_MOV_TO_BANK0_REG(29) + JMP_TO_MOV_TO_BANK0_REG(30) + JMP_TO_MOV_TO_BANK0_REG(31) + MOV_TO_REG(32) + MOV_TO_REG(33) + MOV_TO_REG(34) + MOV_TO_REG(35) + MOV_TO_REG(36) + MOV_TO_REG(37) + MOV_TO_REG(38) + MOV_TO_REG(39) + MOV_TO_REG(40) + MOV_TO_REG(41) + MOV_TO_REG(42) + MOV_TO_REG(43) + MOV_TO_REG(44) + MOV_TO_REG(45) + MOV_TO_REG(46) + MOV_TO_REG(47) + MOV_TO_REG(48) + MOV_TO_REG(49) + MOV_TO_REG(50) + MOV_TO_REG(51) + MOV_TO_REG(52) + MOV_TO_REG(53) + MOV_TO_REG(54) + MOV_TO_REG(55) + MOV_TO_REG(56) + MOV_TO_REG(57) + MOV_TO_REG(58) + MOV_TO_REG(59) + MOV_TO_REG(60) + MOV_TO_REG(61) + MOV_TO_REG(62) + MOV_TO_REG(63) + MOV_TO_REG(64) + MOV_TO_REG(65) + MOV_TO_REG(66) + MOV_TO_REG(67) + MOV_TO_REG(68) + MOV_TO_REG(69) + MOV_TO_REG(70) + MOV_TO_REG(71) + MOV_TO_REG(72) + MOV_TO_REG(73) + MOV_TO_REG(74) + MOV_TO_REG(75) + MOV_TO_REG(76) + MOV_TO_REG(77) + MOV_TO_REG(78) + MOV_TO_REG(79) + MOV_TO_REG(80) + MOV_TO_REG(81) + MOV_TO_REG(82) + MOV_TO_REG(83) + MOV_TO_REG(84) + MOV_TO_REG(85) + MOV_TO_REG(86) + MOV_TO_REG(87) + MOV_TO_REG(88) + MOV_TO_REG(89) + MOV_TO_REG(90) + MOV_TO_REG(91) + MOV_TO_REG(92) + MOV_TO_REG(93) + MOV_TO_REG(94) + MOV_TO_REG(95) + MOV_TO_REG(96) + MOV_TO_REG(97) + MOV_TO_REG(98) + MOV_TO_REG(99) + MOV_TO_REG(100) + MOV_TO_REG(101) + MOV_TO_REG(102) + MOV_TO_REG(103) + MOV_TO_REG(104) + MOV_TO_REG(105) + MOV_TO_REG(106) + MOV_TO_REG(107) + MOV_TO_REG(108) + MOV_TO_REG(109) + MOV_TO_REG(110) + MOV_TO_REG(111) + MOV_TO_REG(112) + MOV_TO_REG(113) + MOV_TO_REG(114) + MOV_TO_REG(115) + MOV_TO_REG(116) + MOV_TO_REG(117) + MOV_TO_REG(118) + MOV_TO_REG(119) + MOV_TO_REG(120) + MOV_TO_REG(121) + MOV_TO_REG(122) + MOV_TO_REG(123) + MOV_TO_REG(124) + MOV_TO_REG(125) + MOV_TO_REG(126) + MOV_TO_REG(127) +END(asm_mov_to_reg) -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-28 10:07:05
|
>From f21b39650592fff4d07c94730b0f4e9aa093b9a8 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:50:13 +0800 Subject: [PATCH] kvm/ia64: Generate offset values for assembly code use. asm-offsets.c will generate offset values used for assembly code for some fileds of special structures. Signed-off-by: Anthony Xu <ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/asm-offsets.c | 251 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 251 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/asm-offsets.c diff --git a/arch/ia64/kvm/asm-offsets.c b/arch/ia64/kvm/asm-offsets.c new file mode 100644 index 0000000..fc2ac82 --- /dev/null +++ b/arch/ia64/kvm/asm-offsets.c @@ -0,0 +1,251 @@ +/* + * asm-offsets.c Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed + * to extract and format the required data. + * + * Anthony Xu <ant...@in...> + * Xiantao Zhang <xia...@in...> + * Copyright (c) 2007 Intel Corporation KVM support. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#include <linux/autoconf.h> +#include <linux/kvm_host.h> + +#include "vcpu.h" + +#define task_struct kvm_vcpu + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " (%0) " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : :) + +#define OFFSET(_sym, _str, _mem) \ + DEFINE(_sym, offsetof(_str, _mem)); + +void foo(void) +{ + DEFINE(VMM_TASK_SIZE, sizeof(struct kvm_vcpu)); + DEFINE(VMM_PT_REGS_SIZE, sizeof(struct kvm_pt_regs)); + + BLANK(); + + DEFINE(VMM_VCPU_META_RR0_OFFSET, + offsetof(struct kvm_vcpu, arch.metaphysical_rr0)); + DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET, + offsetof(struct kvm_vcpu, + arch.metaphysical_saved_rr0)); + DEFINE(VMM_VCPU_VRR0_OFFSET, + offsetof(struct kvm_vcpu, arch.vrr[0])); + DEFINE(VMM_VPD_IRR0_OFFSET, + offsetof(struct vpd, irr[0])); + DEFINE(VMM_VCPU_ITC_CHECK_OFFSET, + offsetof(struct kvm_vcpu, arch.itc_check)); + DEFINE(VMM_VCPU_IRQ_CHECK_OFFSET, + offsetof(struct kvm_vcpu, arch.irq_check)); + DEFINE(VMM_VPD_VHPI_OFFSET, + offsetof(struct vpd, vhpi)); + DEFINE(VMM_VCPU_VSA_BASE_OFFSET, + offsetof(struct kvm_vcpu, arch.vsa_base)); + DEFINE(VMM_VCPU_VPD_OFFSET, + offsetof(struct kvm_vcpu, arch.vpd)); + DEFINE(VMM_VCPU_IRQ_CHECK, + offsetof(struct kvm_vcpu, arch.irq_check)); + DEFINE(VMM_VCPU_TIMER_PENDING, + offsetof(struct kvm_vcpu, arch.timer_pending)); + DEFINE(VMM_VCPU_META_SAVED_RR0_OFFSET, + offsetof(struct kvm_vcpu, arch.metaphysical_saved_rr0)); + DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET, + offsetof(struct kvm_vcpu, arch.mode_flags)); + DEFINE(VMM_VCPU_ITC_OFS_OFFSET, + offsetof(struct kvm_vcpu, arch.itc_offset)); + DEFINE(VMM_VCPU_LAST_ITC_OFFSET, + offsetof(struct kvm_vcpu, arch.last_itc)); + DEFINE(VMM_VCPU_SAVED_GP_OFFSET, + offsetof(struct kvm_vcpu, arch.saved_gp)); + + BLANK(); + + DEFINE(VMM_PT_REGS_B6_OFFSET, + offsetof(struct kvm_pt_regs, b6)); + DEFINE(VMM_PT_REGS_B7_OFFSET, + offsetof(struct kvm_pt_regs, b7)); + DEFINE(VMM_PT_REGS_AR_CSD_OFFSET, + offsetof(struct kvm_pt_regs, ar_csd)); + DEFINE(VMM_PT_REGS_AR_SSD_OFFSET, + offsetof(struct kvm_pt_regs, ar_ssd)); + DEFINE(VMM_PT_REGS_R8_OFFSET, + offsetof(struct kvm_pt_regs, r8)); + DEFINE(VMM_PT_REGS_R9_OFFSET, + offsetof(struct kvm_pt_regs, r9)); + DEFINE(VMM_PT_REGS_R10_OFFSET, + offsetof(struct kvm_pt_regs, r10)); + DEFINE(VMM_PT_REGS_R11_OFFSET, + offsetof(struct kvm_pt_regs, r11)); + DEFINE(VMM_PT_REGS_CR_IPSR_OFFSET, + offsetof(struct kvm_pt_regs, cr_ipsr)); + DEFINE(VMM_PT_REGS_CR_IIP_OFFSET, + offsetof(struct kvm_pt_regs, cr_iip)); + DEFINE(VMM_PT_REGS_CR_IFS_OFFSET, + offsetof(struct kvm_pt_regs, cr_ifs)); + DEFINE(VMM_PT_REGS_AR_UNAT_OFFSET, + offsetof(struct kvm_pt_regs, ar_unat)); + DEFINE(VMM_PT_REGS_AR_PFS_OFFSET, + offsetof(struct kvm_pt_regs, ar_pfs)); + DEFINE(VMM_PT_REGS_AR_RSC_OFFSET, + offsetof(struct kvm_pt_regs, ar_rsc)); + DEFINE(VMM_PT_REGS_AR_RNAT_OFFSET, + offsetof(struct kvm_pt_regs, ar_rnat)); + + DEFINE(VMM_PT_REGS_AR_BSPSTORE_OFFSET, + offsetof(struct kvm_pt_regs, ar_bspstore)); + DEFINE(VMM_PT_REGS_PR_OFFSET, + offsetof(struct kvm_pt_regs, pr)); + DEFINE(VMM_PT_REGS_B0_OFFSET, + offsetof(struct kvm_pt_regs, b0)); + DEFINE(VMM_PT_REGS_LOADRS_OFFSET, + offsetof(struct kvm_pt_regs, loadrs)); + DEFINE(VMM_PT_REGS_R1_OFFSET, + offsetof(struct kvm_pt_regs, r1)); + DEFINE(VMM_PT_REGS_R12_OFFSET, + offsetof(struct kvm_pt_regs, r12)); + DEFINE(VMM_PT_REGS_R13_OFFSET, + offsetof(struct kvm_pt_regs, r13)); + DEFINE(VMM_PT_REGS_AR_FPSR_OFFSET, + offsetof(struct kvm_pt_regs, ar_fpsr)); + DEFINE(VMM_PT_REGS_R15_OFFSET, + offsetof(struct kvm_pt_regs, r15)); + DEFINE(VMM_PT_REGS_R14_OFFSET, + offsetof(struct kvm_pt_regs, r14)); + DEFINE(VMM_PT_REGS_R2_OFFSET, + offsetof(struct kvm_pt_regs, r2)); + DEFINE(VMM_PT_REGS_R3_OFFSET, + offsetof(struct kvm_pt_regs, r3)); + DEFINE(VMM_PT_REGS_R16_OFFSET, + offsetof(struct kvm_pt_regs, r16)); + DEFINE(VMM_PT_REGS_R17_OFFSET, + offsetof(struct kvm_pt_regs, r17)); + DEFINE(VMM_PT_REGS_R18_OFFSET, + offsetof(struct kvm_pt_regs, r18)); + DEFINE(VMM_PT_REGS_R19_OFFSET, + offsetof(struct kvm_pt_regs, r19)); + DEFINE(VMM_PT_REGS_R20_OFFSET, + offsetof(struct kvm_pt_regs, r20)); + DEFINE(VMM_PT_REGS_R21_OFFSET, + offsetof(struct kvm_pt_regs, r21)); + DEFINE(VMM_PT_REGS_R22_OFFSET, + offsetof(struct kvm_pt_regs, r22)); + DEFINE(VMM_PT_REGS_R23_OFFSET, + offsetof(struct kvm_pt_regs, r23)); + DEFINE(VMM_PT_REGS_R24_OFFSET, + offsetof(struct kvm_pt_regs, r24)); + DEFINE(VMM_PT_REGS_R25_OFFSET, + offsetof(struct kvm_pt_regs, r25)); + DEFINE(VMM_PT_REGS_R26_OFFSET, + offsetof(struct kvm_pt_regs, r26)); + DEFINE(VMM_PT_REGS_R27_OFFSET, + offsetof(struct kvm_pt_regs, r27)); + DEFINE(VMM_PT_REGS_R28_OFFSET, + offsetof(struct kvm_pt_regs, r28)); + DEFINE(VMM_PT_REGS_R29_OFFSET, + offsetof(struct kvm_pt_regs, r29)); + DEFINE(VMM_PT_REGS_R30_OFFSET, + offsetof(struct kvm_pt_regs, r30)); + DEFINE(VMM_PT_REGS_R31_OFFSET, + offsetof(struct kvm_pt_regs, r31)); + DEFINE(VMM_PT_REGS_AR_CCV_OFFSET, + offsetof(struct kvm_pt_regs, ar_ccv)); + DEFINE(VMM_PT_REGS_F6_OFFSET, + offsetof(struct kvm_pt_regs, f6)); + DEFINE(VMM_PT_REGS_F7_OFFSET, + offsetof(struct kvm_pt_regs, f7)); + DEFINE(VMM_PT_REGS_F8_OFFSET, + offsetof(struct kvm_pt_regs, f8)); + DEFINE(VMM_PT_REGS_F9_OFFSET, + offsetof(struct kvm_pt_regs, f9)); + DEFINE(VMM_PT_REGS_F10_OFFSET, + offsetof(struct kvm_pt_regs, f10)); + DEFINE(VMM_PT_REGS_F11_OFFSET, + offsetof(struct kvm_pt_regs, f11)); + DEFINE(VMM_PT_REGS_R4_OFFSET, + offsetof(struct kvm_pt_regs, r4)); + DEFINE(VMM_PT_REGS_R5_OFFSET, + offsetof(struct kvm_pt_regs, r5)); + DEFINE(VMM_PT_REGS_R6_OFFSET, + offsetof(struct kvm_pt_regs, r6)); + DEFINE(VMM_PT_REGS_R7_OFFSET, + offsetof(struct kvm_pt_regs, r7)); + DEFINE(VMM_PT_REGS_EML_UNAT_OFFSET, + offsetof(struct kvm_pt_regs, eml_unat)); + DEFINE(VMM_VCPU_IIPA_OFFSET, + offsetof(struct kvm_vcpu, arch.cr_iipa)); + DEFINE(VMM_VCPU_OPCODE_OFFSET, + offsetof(struct kvm_vcpu, arch.opcode)); + DEFINE(VMM_VCPU_CAUSE_OFFSET, offsetof(struct kvm_vcpu, arch.cause)); + DEFINE(VMM_VCPU_ISR_OFFSET, + offsetof(struct kvm_vcpu, arch.cr_isr)); + DEFINE(VMM_PT_REGS_R16_SLOT, + (((offsetof(struct kvm_pt_regs, r16) + - sizeof(struct kvm_pt_regs)) >> 3) & 0x3f)); + DEFINE(VMM_VCPU_MODE_FLAGS_OFFSET, + offsetof(struct kvm_vcpu, arch.mode_flags)); + DEFINE(VMM_VCPU_GP_OFFSET, offsetof(struct kvm_vcpu, arch.__gp)); + BLANK(); + + DEFINE(VMM_VPD_BASE_OFFSET, offsetof(struct kvm_vcpu, arch.vpd)); + DEFINE(VMM_VPD_VIFS_OFFSET, offsetof(struct vpd, ifs)); + DEFINE(VMM_VLSAPIC_INSVC_BASE_OFFSET, + offsetof(struct kvm_vcpu, arch.insvc[0])); + DEFINE(VMM_VPD_VPTA_OFFSET, offsetof(struct vpd, pta)); + DEFINE(VMM_VPD_VPSR_OFFSET, offsetof(struct vpd, vpsr)); + + DEFINE(VMM_CTX_R4_OFFSET, offsetof(context_t, gr[4])); + DEFINE(VMM_CTX_R5_OFFSET, offsetof(context_t, gr[5])); + DEFINE(VMM_CTX_R12_OFFSET, offsetof(context_t, gr[12])); + DEFINE(VMM_CTX_R13_OFFSET, offsetof(context_t, gr[13])); + DEFINE(VMM_CTX_KR0_OFFSET, offsetof(context_t, ar[0])); + DEFINE(VMM_CTX_KR1_OFFSET, offsetof(context_t, ar[1])); + DEFINE(VMM_CTX_B0_OFFSET, offsetof(context_t, br[0])); + DEFINE(VMM_CTX_B1_OFFSET, offsetof(context_t, br[1])); + DEFINE(VMM_CTX_B2_OFFSET, offsetof(context_t, br[2])); + DEFINE(VMM_CTX_RR0_OFFSET, offsetof(context_t, rr[0])); + DEFINE(VMM_CTX_RSC_OFFSET, offsetof(context_t, ar[16])); + DEFINE(VMM_CTX_BSPSTORE_OFFSET, offsetof(context_t, ar[18])); + DEFINE(VMM_CTX_RNAT_OFFSET, offsetof(context_t, ar[19])); + DEFINE(VMM_CTX_FCR_OFFSET, offsetof(context_t, ar[21])); + DEFINE(VMM_CTX_EFLAG_OFFSET, offsetof(context_t, ar[24])); + DEFINE(VMM_CTX_CFLG_OFFSET, offsetof(context_t, ar[27])); + DEFINE(VMM_CTX_FSR_OFFSET, offsetof(context_t, ar[28])); + DEFINE(VMM_CTX_FIR_OFFSET, offsetof(context_t, ar[29])); + DEFINE(VMM_CTX_FDR_OFFSET, offsetof(context_t, ar[30])); + DEFINE(VMM_CTX_UNAT_OFFSET, offsetof(context_t, ar[36])); + DEFINE(VMM_CTX_FPSR_OFFSET, offsetof(context_t, ar[40])); + DEFINE(VMM_CTX_PFS_OFFSET, offsetof(context_t, ar[64])); + DEFINE(VMM_CTX_LC_OFFSET, offsetof(context_t, ar[65])); + DEFINE(VMM_CTX_DCR_OFFSET, offsetof(context_t, cr[0])); + DEFINE(VMM_CTX_IVA_OFFSET, offsetof(context_t, cr[2])); + DEFINE(VMM_CTX_PTA_OFFSET, offsetof(context_t, cr[8])); + DEFINE(VMM_CTX_IBR0_OFFSET, offsetof(context_t, ibr[0])); + DEFINE(VMM_CTX_DBR0_OFFSET, offsetof(context_t, dbr[0])); + DEFINE(VMM_CTX_F2_OFFSET, offsetof(context_t, fr[2])); + DEFINE(VMM_CTX_F3_OFFSET, offsetof(context_t, fr[3])); + DEFINE(VMM_CTX_F32_OFFSET, offsetof(context_t, fr[32])); + DEFINE(VMM_CTX_F33_OFFSET, offsetof(context_t, fr[33])); + DEFINE(VMM_CTX_PKR0_OFFSET, offsetof(context_t, pkr[0])); + DEFINE(VMM_CTX_PSR_OFFSET, offsetof(context_t, psr)); + BLANK(); +} -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-28 10:03:42
|
>From 9118d25b4e98bef3a62429f8c150e8d429396c40 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 12:58:02 +0800 Subject: [PATCH] Implement smp_call_function_mask for ia64 This function provides more flexible interface for smp infrastructure. Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kernel/smp.c | 84 +++++++++++++++++++++++++++++++++++++---------- include/linux/smp.h | 3 ++ 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index 4e446aa..5bb241f 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -213,6 +213,19 @@ send_IPI_allbutself (int op) * Called with preemption disabled. */ static inline void +send_IPI_mask(cpumask_t mask, int op) +{ + unsigned int cpu; + + for_each_cpu_mask(cpu, mask) { + send_IPI_single(cpu, op); + } +} + +/* + * Called with preemption disabled. + */ +static inline void send_IPI_all (int op) { int i; @@ -401,33 +414,36 @@ smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int } EXPORT_SYMBOL(smp_call_function_single); -/* - * this function sends a 'generic call function' IPI to all other CPUs - * in the system. - */ - -/* - * [SUMMARY] Run a function on all other CPUs. - * <func> The function to run. This must be fast and non-blocking. - * <info> An arbitrary pointer to pass to the function. - * <nonatomic> currently unused. - * <wait> If true, wait (atomically) until function has completed on other CPUs. - * [RETURNS] 0 on success, else a negative status code. +/** + * smp_call_function_mask(): Run a function on a set of other CPUs. + * <mask> The set of cpus to run on. Must not include the current cpu. + * <func> The function to run. This must be fast and non-blocking. + * <info> An arbitrary pointer to pass to the function. + * <wait> If true, wait (atomically) until function + * has completed on other CPUs. * - * Does not return until remote CPUs are nearly ready to execute <func> or are or have - * executed. + * Returns 0 on success, else a negative status code. + * + * If @wait is true, then returns once @func has returned; otherwise + * it returns just before the target cpu calls @func. * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ -int -smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) +int smp_call_function_mask(cpumask_t mask, + void (*func)(void *), void *info, + int wait) { struct call_data_struct data; + cpumask_t allbutself; int cpus; spin_lock(&call_lock); - cpus = num_online_cpus() - 1; + allbutself = cpu_online_map; + cpu_clear(smp_processor_id(), allbutself); + + cpus_and(mask, mask, allbutself); + cpus = cpus_weight(mask); if (!cpus) { spin_unlock(&call_lock); return 0; @@ -445,7 +461,12 @@ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wai call_data = &data; mb(); /* ensure store to call_data precedes setting of IPI_CALL_FUNC */ - send_IPI_allbutself(IPI_CALL_FUNC); + + /* Send a message to other CPUs */ + if (cpus_equal(mask, allbutself)) + send_IPI_allbutself(IPI_CALL_FUNC); + else + send_IPI_mask(mask, IPI_CALL_FUNC); /* Wait for response */ while (atomic_read(&data.started) != cpus) @@ -458,6 +479,33 @@ smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wai spin_unlock(&call_lock); return 0; + +} +EXPORT_SYMBOL(smp_call_function_mask); + +/* + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +/* + * [SUMMARY] Run a function on all other CPUs. + * <func> The function to run. This must be fast and non-blocking. + * <info> An arbitrary pointer to pass to the function. + * <nonatomic> currently unused. + * <wait> If true, wait (atomically) until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute <func> or are or have + * executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler or from a bottom half handler. + */ +int +smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) +{ + return smp_call_function_mask(cpu_online_map, func, info, wait); } EXPORT_SYMBOL(smp_call_function); diff --git a/include/linux/smp.h b/include/linux/smp.h index 55232cc..b71820b 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -56,6 +56,9 @@ int smp_call_function(void(*func)(void *info), void *info, int retry, int wait); int smp_call_function_single(int cpuid, void (*func) (void *info), void *info, int retry, int wait); +int smp_call_function_mask(cpumask_t mask, + void (*func)(void *), void *info, + int wait); /* * Call a function on all processors -- 1.5.2 |
From: Zhang, X. <xia...@in...> - 2008-03-28 10:00:27
|
>From 56d3f7acf8d45d2491646be77ced344dcc516cd7 Mon Sep 17 00:00:00 2001 From: Xiantao Zhang <xia...@in...> Date: Wed, 12 Mar 2008 13:45:40 +0800 Subject: [PATCH] kvm/ia64: Add TLB virtulization support. vtlb.c includes tlb/VHPT virtulization. Signed-off-by: Anthony Xu <ant...@in...> Signed-off-by: Xiantao Zhang <xia...@in...> --- arch/ia64/kvm/vtlb.c | 631 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 631 insertions(+), 0 deletions(-) create mode 100644 arch/ia64/kvm/vtlb.c diff --git a/arch/ia64/kvm/vtlb.c b/arch/ia64/kvm/vtlb.c new file mode 100644 index 0000000..6e6ed25 --- /dev/null +++ b/arch/ia64/kvm/vtlb.c @@ -0,0 +1,631 @@ +/* + * vtlb.c: guest virtual tlb handling module. + * Copyright (c) 2004, Intel Corporation. + * Yaozu Dong (Eddie Dong) <Edd...@in...> + * Xuefei Xu (Anthony Xu) <ant...@in...> + * + * Copyright (c) 2007, Intel Corporation. + * Xuefei Xu (Anthony Xu) <ant...@in...> + * Xiantao Zhang <xia...@in...> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + +#include "vcpu.h" + +#include <linux/rwsem.h> +/* + * Check to see if the address rid:va is translated by the TLB + */ + +static int __is_tr_translated(thash_data_t *trp, u64 rid, u64 va) +{ + return ((trp->p) && (trp->rid == rid) + && ((va-trp->vadr) < PSIZE(trp->ps))); +} + +/* + * Only for GUEST TR format. + */ +static int __is_tr_overlap(thash_data_t *trp, u64 rid, u64 sva, u64 eva) +{ + u64 sa1, ea1; + + if (!trp->p || trp->rid != rid) + return 0; + + sa1 = trp->vadr; + ea1 = sa1 + PSIZE(trp->ps) - 1; + eva -= 1; + if ((sva > ea1) || (sa1 > eva)) + return 0; + else + return 1; + +} + +void machine_tlb_purge(u64 va, u64 ps) +{ + ia64_ptcl(va, ps << 2); +} + +void local_flush_tlb_all(void) +{ + int i, j; + unsigned long flags, count0, count1; + unsigned long stride0, stride1, addr; + + addr = current_vcpu->arch.ptce_base; + count0 = current_vcpu->arch.ptce_count[0]; + count1 = current_vcpu->arch.ptce_count[1]; + stride0 = current_vcpu->arch.ptce_stride[0]; + stride1 = current_vcpu->arch.ptce_stride[1]; + + local_irq_save(flags); + for (i = 0; i < count0; ++i) { + for (j = 0; j < count1; ++j) { + ia64_ptce(addr); + addr += stride1; + } + addr += stride0; + } + local_irq_restore(flags); + ia64_srlz_i(); /* srlz.i implies srlz.d */ +} + +int vhpt_enabled(VCPU *vcpu, u64 vadr, vhpt_ref_t ref) +{ + ia64_rr vrr; + ia64_pta vpta; + ia64_psr vpsr; + + vpsr.val = VCPU(vcpu, vpsr); + vrr.val = vcpu_get_rr(vcpu, vadr); + vpta.val = vcpu_get_pta(vcpu); + + if (vrr.ve & vpta.ve) { + switch (ref) { + case DATA_REF: + case NA_REF: + return vpsr.dt; + case INST_REF: + return vpsr.dt && vpsr.it && vpsr.ic; + case RSE_REF: + return vpsr.dt && vpsr.rt; + + } + } + return 0; +} + +thash_data_t *vsa_thash(ia64_pta vpta, u64 va, u64 vrr, u64 *tag) +{ + u64 index, pfn, rid, pfn_bits; + + pfn_bits = vpta.size - 5 - 8; + pfn = REGION_OFFSET(va) >> _REGION_PAGE_SIZE(vrr); + rid = _REGION_ID(vrr); + index = ((rid & 0xff) << pfn_bits)|(pfn & ((1UL << pfn_bits) - 1)); + *tag = ((rid >> 8) & 0xffff) | ((pfn >> pfn_bits) << 16); + + return (thash_data_t *)((vpta.base << PTA_BASE_SHIFT) + (index << 5)); +} + +thash_data_t *__vtr_lookup(VCPU *vcpu, u64 va, int type) +{ + + thash_data_t *trp; + int i; + u64 rid; + + rid = vcpu_get_rr(vcpu, va); + rid = rid & RR_RID_MASK;; + if (type == D_TLB) { + if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) { + for (trp = (thash_data_t *)&vcpu->arch.dtrs, i = 0; + i < NDTRS; i++, trp++) { + if (__is_tr_translated(trp, rid, va)) + return trp; + } + } + } else { + if (vcpu_quick_region_check(vcpu->arch.itr_regions, va)) { + for (trp = (thash_data_t *)&vcpu->arch.itrs, i = 0; + i < NITRS; i++, trp++) { + if (__is_tr_translated(trp, rid, va)) + return trp; + } + } + } + + return NULL; +} + +static void vhpt_insert(u64 pte, u64 itir, u64 ifa, u64 gpte) +{ + ia64_rr rr; + thash_data_t *head; + unsigned long ps, gpaddr; + + ps = itir_ps(itir); + + gpaddr = ((gpte & _PAGE_PPN_MASK) >> ps << ps) | + (ifa & ((1UL << ps) - 1)); + + rr.val = ia64_get_rr(ifa); + head = (thash_data_t *)ia64_thash(ifa); + head->etag = INVALID_TI_TAG; + ia64_mf(); + head->page_flags = pte & ~PAGE_FLAGS_RV_MASK; + head->itir = rr.ps << 2; + head->etag = ia64_ttag(ifa); + head->gpaddr = gpaddr; +} + +void mark_pages_dirty(VCPU *v, u64 pte, u64 ps) +{ + u64 i, dirty_pages = 1; + u64 base_gfn = (pte&_PAGE_PPN_MASK) >> PAGE_SHIFT; + spinlock_t *lock = __kvm_va(v->arch.dirty_log_lock_pa); + void *dirty_bitmap = (void *)v - (KVM_VCPU_OFS + v->vcpu_id * VCPU_SIZE) + + KVM_MEM_DIRTY_LOG_OFS; + dirty_pages <<= ps <= PAGE_SHIFT ? 0 : ps - PAGE_SHIFT; + + vmm_spin_lock(lock); + for (i = 0; i < dirty_pages; i++) { + /* avoid RMW */ + if (!test_bit(base_gfn + i, dirty_bitmap)) + set_bit(base_gfn + i , dirty_bitmap); + } + vmm_spin_unlock(lock); +} + +void thash_vhpt_insert(VCPU *v, u64 pte, u64 itir, u64 va, int type) +{ + u64 phy_pte, psr; + ia64_rr mrr; + + mrr.val = ia64_get_rr(va); + phy_pte = translate_phy_pte(&pte, itir, va); + + if (itir_ps(itir) >= mrr.ps) { + vhpt_insert(phy_pte, itir, va, pte); + } else { + phy_pte &= ~PAGE_FLAGS_RV_MASK; + psr = ia64_clear_ic(); + ia64_itc(type, va, phy_pte, itir_ps(itir)); + ia64_set_psr(psr); + } + + if (!(pte&VTLB_PTE_IO)) + mark_pages_dirty(v, pte, itir_ps(itir)); +} + +/* + * vhpt lookup + */ +thash_data_t *vhpt_lookup(u64 va) +{ + thash_data_t *head; + u64 tag; + + head = (thash_data_t *)ia64_thash(va); + tag = ia64_ttag(va); + if (head->etag == tag) + return head; + return NULL; +} + +u64 guest_vhpt_lookup(u64 iha, u64 *pte) +{ + u64 ret; + thash_data_t *data; + + data = __vtr_lookup(current_vcpu, iha, D_TLB); + if (data != NULL) + thash_vhpt_insert(current_vcpu, data->page_flags, + data->itir, iha, D_TLB); + + asm volatile ("rsm psr.ic|psr.i;;" + "srlz.d;;" + "ld8.s r9=[%1];;" + "tnat.nz p6,p7=r9;;" + "(p6) mov %0=1;" + "(p6) mov r9=r0;" + "(p7) extr.u r9=r9,0,53;;" + "(p7) mov %0=r0;" + "(p7) st8 [%2]=r9;;" + "ssm psr.ic;;" + "srlz.d;;" + /* "ssm psr.i;;" Once interrupts in vmm open, need fix*/ + : "=r"(ret) : "r"(iha), "r"(pte):"memory"); + + return ret; +} + +/* + * purge software guest tlb + */ + +static void vtlb_purge(VCPU *v, u64 va, u64 ps) +{ + thash_data_t *cur; + u64 start, curadr, size, psbits, tag, rr_ps, num; + ia64_rr vrr; + thash_cb_t *hcb = &v->arch.vtlb; + + vrr.val = vcpu_get_rr(v, va); + psbits = VMX(v, psbits[(va >> 61)]); + start = va & ~((1UL << ps) - 1); + while (psbits) { + curadr = start; + rr_ps = __ffs(psbits); + psbits &= ~(1UL << rr_ps); + num = 1UL << ((ps < rr_ps) ? 0 : (ps - rr_ps)); + size = PSIZE(rr_ps); + vrr.ps = rr_ps; + while (num) { + cur = vsa_thash(hcb->pta, curadr, vrr.val, &tag); + if (cur->etag == tag && cur->ps == rr_ps) + cur->etag = INVALID_TI_TAG; + curadr += size; + num--; + } + } +} + + +/* + * purge VHPT and machine TLB + */ +static void vhpt_purge(VCPU *v, u64 va, u64 ps) +{ + thash_data_t *cur; + u64 start, size, tag, num; + ia64_rr rr; + + start = va & ~((1UL << ps) - 1); + rr.val = ia64_get_rr(va); + size = PSIZE(rr.ps); + num = 1UL << ((ps < rr.ps) ? 0 : (ps - rr.ps)); + while (num) { + cur = (thash_data_t *)ia64_thash(start); + tag = ia64_ttag(start); + if (cur->etag == tag) + cur->etag = INVALID_TI_TAG; + start += size; + num--; + } + machine_tlb_purge(va, ps); +} + +/* + * Insert an entry into hash TLB or VHPT. + * NOTES: + * 1: When inserting VHPT to thash, "va" is a must covered + * address by the inserted machine VHPT entry. + * 2: The format of entry is always in TLB. + * 3: The caller need to make sure the new entry will not overlap + * with any existed entry. + */ +void vtlb_insert(VCPU *v, u64 pte, u64 itir, u64 va) +{ + thash_data_t *head; + ia64_rr vrr; + u64 tag; + thash_cb_t *hcb = &v->arch.vtlb; + + vrr.val = vcpu_get_rr(v, va); + vrr.ps = itir_ps(itir); + VMX(v, psbits[va >> 61]) |= (1UL << vrr.ps); + head = vsa_thash(hcb->pta, va, vrr.val, &tag); + head->page_flags = pte; + head->itir = itir; + head->etag = tag; +} + +int vtr_find_overlap(VCPU *vcpu, u64 va, u64 ps, int type) +{ + thash_data_t *trp; + int i; + u64 end, rid; + + rid = vcpu_get_rr(vcpu, va); + rid = rid & RR_RID_MASK; + end = va + PSIZE(ps); + if (type == D_TLB) { + if (vcpu_quick_region_check(vcpu->arch.dtr_regions, va)) { + for (trp = (thash_data_t *)&vcpu->arch.dtrs, i = 0; + i < NDTRS; i++, trp++) { + if (__is_tr_overlap(trp, rid, va, end)) + return i; + } + } + } else { + if (vcpu_quick_region_check(vcpu->arch.itr_regions, va)) { + for (trp = (thash_data_t *)&vcpu->arch.itrs, i = 0; + i < NITRS; i++, trp++) { + if (__is_tr_overlap(trp, rid, va, end)) + return i; + } + } + } + return -1; +} + +/* + * Purge entries in VTLB and VHPT + */ +void thash_purge_entries(VCPU *v, u64 va, u64 ps) +{ + if (vcpu_quick_region_check(v->arch.tc_regions, va)) + vtlb_purge(v, va, ps); + vhpt_purge(v, va, ps); +} + +void thash_purge_entries_remote(VCPU *v, u64 va, u64 ps) +{ + u64 old_va = va; + va = REGION_OFFSET(va); + if (vcpu_quick_region_check(v->arch.tc_regions, old_va)) + vtlb_purge(v, va, ps); + vhpt_purge(v, va, ps); +} + +u64 translate_phy_pte(u64 *pte, u64 itir, u64 va) +{ + u64 ps, ps_mask, paddr, maddr; + union pte_flags phy_pte; + + ps = itir_ps(itir); + ps_mask = ~((1UL << ps) - 1); + phy_pte.val = *pte; + paddr = *pte; + paddr = ((paddr & _PAGE_PPN_MASK) & ps_mask) | (va & ~ps_mask); + maddr = kvm_lookup_mpa(paddr >> PAGE_SHIFT); + if (maddr & GPFN_IO_MASK) { + *pte |= VTLB_PTE_IO; + return -1; + } + maddr = ((maddr & _PAGE_PPN_MASK) & PAGE_MASK) | + (paddr & ~PAGE_MASK); + phy_pte.ppn = maddr >> ARCH_PAGE_SHIFT; + return phy_pte.val; +} + +/* + * Purge overlap TCs and then insert the new entry to emulate itc ops. + * Notes: Only TC entry can purge and insert. + * 1 indicates this is MMIO + */ +int thash_purge_and_insert(VCPU *v, u64 pte, u64 itir, u64 ifa, int type) +{ + u64 ps; + u64 phy_pte; + ia64_rr vrr, mrr; + int ret = 0; + + ps = itir_ps(itir); + vrr.val = vcpu_get_rr(v, ifa); + mrr.val = ia64_get_rr(ifa); + + phy_pte = translate_phy_pte(&pte, itir, ifa); + + /* Ensure WB attribute if pte is related to a normal mem page, + * which is required by vga acceleration since qemu maps shared + * vram buffer with WB. + */ + if (!(pte & VTLB_PTE_IO) && ((pte & _PAGE_MA_MASK) != _PAGE_MA_NAT)) { + pte &= ~_PAGE_MA_MASK; + phy_pte &= ~_PAGE_MA_MASK; + } + + if (pte & VTLB_PTE_IO) + ret = 1; + + vtlb_purge(v, ifa, ps); + vhpt_purge(v, ifa, ps); + + if (ps == mrr.ps) { + if (!(pte&VTLB_PTE_IO)) { + vhpt_insert(phy_pte, itir, ifa, pte); + } else { + vtlb_insert(v, pte, itir, ifa); + vcpu_quick_region_set(VMX(v, tc_regions), ifa); + } + } else if (ps > mrr.ps) { + vtlb_insert(v, pte, itir, ifa); + vcpu_quick_region_set(VMX(v, tc_regions), ifa); + if (!(pte&VTLB_PTE_IO)) + vhpt_insert(phy_pte, itir, ifa, pte); + } else { + u64 psr; + phy_pte &= ~PAGE_FLAGS_RV_MASK; + psr = ia64_clear_ic(); + ia64_itc(type, ifa, phy_pte, ps); + ia64_set_psr(psr); + } + if (!(pte&VTLB_PTE_IO)) + mark_pages_dirty(v, pte, ps); + + return ret; +} + +/* + * Purge all TCs or VHPT entries including those in Hash table. + * + */ + +void thash_purge_all(VCPU *v) +{ + int i; + thash_data_t *head; + thash_cb_t *vtlb, *vhpt; + vtlb = &v->arch.vtlb; + vhpt = &v->arch.vhpt; + + for (i = 0; i < 8; i++) + VMX(v, psbits[i]) = 0; + + head = vtlb->hash; + for (i = 0; i < vtlb->num; i++) { + head->page_flags = 0; + head->etag = INVALID_TI_TAG; + head->itir = 0; + head->next = 0; + head++; + }; + + head = vhpt->hash; + for (i = 0; i < vhpt->num; i++) { + head->page_flags = 0; + head->etag = INVALID_TI_TAG; + head->itir = 0; + head->next = 0; + head++; + }; + + local_flush_tlb_all(); +} + + +/* + * Lookup the hash table and its collision chain to find an entry + * covering this address rid:va or the entry. + * + * INPUT: + * in: TLB format for both VHPT & TLB. + */ + +thash_data_t *vtlb_lookup(VCPU *v, u64 va, int is_data) +{ + thash_data_t *cch; + u64 psbits, ps, tag; + ia64_rr vrr; + + thash_cb_t *hcb = &v->arch.vtlb; + + cch = __vtr_lookup(v, va, is_data);; + if (cch) + return cch; + + if (vcpu_quick_region_check(v->arch.tc_regions, va) == 0) + return NULL; + + psbits = VMX(v, psbits[(va >> 61)]); + vrr.val = vcpu_get_rr(v, va); + while (psbits) { + ps = __ffs(psbits); + psbits &= ~(1UL << ps); + vrr.ps = ps; + cch = vsa_thash(hcb->pta, va, vrr.val, &tag); + if (cch->etag == tag && cch->ps == ps) + return cch; + } + + return NULL; +} + + +/* + * Initialize internal control data before service. + */ +void thash_init(thash_cb_t *hcb, u64 sz) +{ + int i; + thash_data_t *head; + + hcb->pta.val = (unsigned long)hcb->hash; + hcb->pta.vf = 1; + hcb->pta.ve = 1; + hcb->pta.size = sz; + head = hcb->hash; + for (i = 0; i < hcb->num; i++) { + head->page_flags = 0; + head->itir = 0; + head->etag = INVALID_TI_TAG; + head->next = 0; + head++; + } +} + +u64 kvm_lookup_mpa(u64 gpfn) +{ + u64 *base = (u64 *) KVM_P2M_BASE; + return *(base + gpfn); +} + +u64 kvm_gpa_to_mpa(u64 gpa) +{ + u64 pte = kvm_lookup_mpa(gpa >> PAGE_SHIFT); + return (pte >> PAGE_SHIFT << PAGE_SHIFT) | (gpa & ~PAGE_MASK); +} + + +/* + * Fetch guest bundle code. + * INPUT: + * gip: guest ip + * pbundle: used to return fetched bundle. + */ +int fetch_code(VCPU *vcpu, u64 gip, IA64_BUNDLE *pbundle) +{ + u64 gpip = 0; /* guest physical IP*/ + u64 *vpa; + thash_data_t *tlb; + u64 maddr; + + if (!(VCPU(vcpu, vpsr) & IA64_PSR_IT)) { + /* I-side physical mode */ + gpip = gip; + } else { + tlb = vtlb_lookup(vcpu, gip, I_TLB); + if (tlb) + gpip = (tlb->ppn >> (tlb->ps - 12) << tlb->ps) | + (gip & (PSIZE(tlb->ps) - 1)); + } + if (gpip) { + maddr = kvm_gpa_to_mpa(gpip); + } else { + tlb = vhpt_lookup(gip); + if (tlb == NULL) { + ia64_ptcl(gip, ARCH_PAGE_SHIFT << 2); + return IA64_FAULT; + } + maddr = (tlb->ppn >> (tlb->ps - 12) << tlb->ps) + | (gip & (PSIZE(tlb->ps) - 1)); + } + vpa = (u64 *)__kvm_va(maddr); + + pbundle->i64[0] = *vpa++; + pbundle->i64[1] = *vpa; + + return IA64_NO_FAULT; +} + + +void kvm_init_vhpt(VCPU *v) +{ + v->arch.vhpt.num = VHPT_NUM_ENTRIES; + thash_init(&v->arch.vhpt, VHPT_SHIFT); + ia64_set_pta(v->arch.vhpt.pta.val); + /*Enable VHPT here?*/ +} + +void kvm_init_vtlb(VCPU *v) +{ + v->arch.vtlb.num = VTLB_NUM_ENTRIES; + thash_init(&v->arch.vtlb, VTLB_SHIFT); +} -- 1.5.2 |