# HG changeset patch # User Tristan Gingold # Date 1183601001 -7200 # Node ID 29b29459c94ccd1bbef2c901888bb8d10691d417 # Parent 3b7216fae72141d68a933e90dd266b417e1bdf2c Renames vmx_process.c into vmx_fault.c Minor reformating and comments added. Signed-off-by: Tristan Gingold diff -r 3b7216fae721 -r 29b29459c94c xen/arch/ia64/vmx/Makefile --- a/xen/arch/ia64/vmx/Makefile Thu Jul 05 03:45:46 2007 +0200 +++ b/xen/arch/ia64/vmx/Makefile Thu Jul 05 04:03:21 2007 +0200 @@ -10,7 +10,7 @@ obj-y += vmx_interrupt.o obj-y += vmx_interrupt.o obj-y += vmx_ivt.o obj-y += vmx_phy_mode.o -obj-y += vmx_process.o +obj-y += vmx_fault.o obj-y += vmx_support.o obj-y += vmx_utility.o obj-y += vmx_vcpu.o diff -r 3b7216fae721 -r 29b29459c94c xen/arch/ia64/vmx/vmx_fault.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/vmx/vmx_fault.c Thu Jul 05 04:03:21 2007 +0200 @@ -0,0 +1,543 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_fault.c: handling VMX architecture-related VM exits + * 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. + * + * Xiaoyan Feng (Fleming Feng) + * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include /* FOR EFI_UNIMPLEMENTED */ +#include /* FOR struct ia64_sal_retval */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */ +#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 + + +extern void die_if_kernel(char *str, struct pt_regs *regs, long err); +extern void rnat_consumption (VCPU *vcpu); +extern void alt_itlb (VCPU *vcpu, u64 vadr); +extern void itlb_fault (VCPU *vcpu, u64 vadr); +extern void ivhpt_fault (VCPU *vcpu, u64 vadr); +extern unsigned long handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr); + +#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 +}; + + + +void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim, + u64 vec, REGS *regs) +{ + u64 status, vector; + VCPU *vcpu = current; + u64 vpsr = VCPU(vcpu, vpsr); + + vector = vec2off[vec]; + + switch (vec) { + case 5: // IA64_DATA_NESTED_TLB_VECTOR + break; + case 22: // IA64_INST_ACCESS_RIGHTS_VECTOR + if (!(vpsr & IA64_PSR_IC)) + goto nested_fault; + if (vhpt_access_rights_fixup(vcpu, ifa, 0)) + return; + break; + + case 25: // IA64_DISABLED_FPREG_VECTOR + if (!(vpsr & IA64_PSR_IC)) + goto nested_fault; + if (FP_PSR(vcpu) & IA64_PSR_DFH) { + FP_PSR(vcpu) = IA64_PSR_MFH; + if (__ia64_per_cpu_var(fp_owner) != vcpu) + __ia64_load_fpu(vcpu->arch._thread.fph); + } + if (!(VCPU(vcpu, vpsr) & IA64_PSR_DFH)) { + regs->cr_ipsr &= ~IA64_PSR_DFH; + return; + } + + break; + + case 32: // IA64_FP_FAULT_VECTOR + if (!(vpsr & IA64_PSR_IC)) + goto nested_fault; + // handle fpswa emulation + // fp fault + status = handle_fpu_swa(1, regs, isr); + if (!status) { + vcpu_increment_iip(vcpu); + return; + } else if (IA64_RETRY == status) + return; + break; + + case 33: // IA64_FP_TRAP_VECTOR + if (!(vpsr & IA64_PSR_IC)) + goto nested_fault; + //fp trap + status = handle_fpu_swa(0, regs, isr); + if (!status) + return; + else if (IA64_RETRY == status) { + vcpu_decrement_iip(vcpu); + return; + } + break; + + case 29: // IA64_DEBUG_VECTOR + case 35: // IA64_TAKEN_BRANCH_TRAP_VECTOR + case 36: // IA64_SINGLE_STEP_TRAP_VECTOR + if (vmx_guest_kernel_mode(regs) + && current->domain->debugger_attached) { + domain_pause_for_debugger(); + return; + } + if (!(vpsr & IA64_PSR_IC)) + goto nested_fault; + break; + + default: + if (!(vpsr & IA64_PSR_IC)) + goto nested_fault; + 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); + return; + + nested_fault: + panic_domain(regs, "Guest nested fault vector=%lx!\n", vector); +} + + +IA64FAULT +vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) +{ + struct domain *d = current->domain; + struct vcpu *v = current; + + perfc_incr(vmx_ia64_handle_break); +#ifdef CRASH_DEBUG + if ((iim == 0 || iim == CDB_BREAK_NUM) && !guest_mode(regs) && + IS_VMM_ADDRESS(regs->cr_iip)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don't care */, regs); + } else +#endif + { + if (iim == 0) + vmx_die_if_kernel("Break 0 in Hypervisor.", regs, iim); + + if (ia64_psr(regs)->cpl == 0) { + /* Allow hypercalls only when cpl = 0. */ + if (iim == d->arch.breakimm) { + ia64_hypercall(regs); + vcpu_increment_iip(v); + return IA64_NO_FAULT; + } + else if(iim == DOMN_PAL_REQUEST){ + pal_emul(v); + vcpu_increment_iip(v); + return IA64_NO_FAULT; + }else if(iim == DOMN_SAL_REQUEST){ + sal_emul(v); + vcpu_increment_iip(v); + return IA64_NO_FAULT; + } + } + vmx_reflect_interruption(ifa,isr,iim,11,regs); + } + return IA64_NO_FAULT; +} + + +void save_banked_regs_to_vpd(VCPU *v, REGS *regs) +{ + unsigned long i=0UL, * src,* dst, *sunat, *dunat; + IA64_PSR vpsr; + src=®s->r16; + sunat=®s->eml_unat; + vpsr.val = VCPU(v, vpsr); + if(vpsr.bn){ + dst = &VCPU(v, vgr[0]); + dunat =&VCPU(v, vnat); + __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;; \ + dep %2 = %0, %2, 0, 16;; \ + st8 [%3] = %2;;" + ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); + + }else{ + dst = &VCPU(v, vbgr[0]); +// dunat =&VCPU(v, vbnat); +// __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;; +// dep %2 = %0, %2, 16, 16;; +// st8 [%3] = %2;;" +// ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); + + } + for(i=0; i<16; i++) + *dst++ = *src++; +} + + +// ONLY gets called from ia64_leave_kernel +// ONLY call with interrupts disabled?? (else might miss one?) +// NEVER successful if already reflecting a trap/fault because psr.i==0 +void leave_hypervisor_tail(void) +{ + struct domain *d = current->domain; + struct vcpu *v = current; + + // FIXME: Will this work properly if doing an RFI??? + if (!is_idle_domain(d) ) { // always comes from guest +// struct pt_regs *user_regs = vcpu_regs(current); + local_irq_enable(); + do_softirq(); + local_irq_disable(); + + if (v->vcpu_id == 0) { + unsigned long callback_irq = + d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; + + if ( v->arch.arch_vmx.pal_init_pending ) { + /*inject INIT interruption to guest pal*/ + v->arch.arch_vmx.pal_init_pending = 0; + deliver_pal_init(v); + return; + } + + /* + * val[63:56] == 1: val[55:0] is a delivery PCI INTx line: + * Domain = val[47:32], Bus = val[31:16], + * DevFn = val[15: 8], IntX = val[ 1: 0] + * val[63:56] == 0: val[55:0] is a delivery as GSI + */ + if (callback_irq != 0 && local_events_need_delivery()) { + /* change level for para-device callback irq */ + /* use level irq to send discrete event */ + if ((uint8_t)(callback_irq >> 56) == 1) { + /* case of using PCI INTx line as callback irq */ + int pdev = (callback_irq >> 11) & 0x1f; + int pintx = callback_irq & 3; + viosapic_set_pci_irq(d, pdev, pintx, 1); + viosapic_set_pci_irq(d, pdev, pintx, 0); + } else { + /* case of using GSI as callback irq */ + viosapic_set_irq(d, callback_irq, 1); + viosapic_set_irq(d, callback_irq, 0); + } + } + } + + rmb(); + if (xchg(&v->arch.irq_new_pending, 0)) { + v->arch.irq_new_condition = 0; + vmx_check_pending_irq(v); + return; + } + + if (v->arch.irq_new_condition) { + v->arch.irq_new_condition = 0; + vhpi_detection(v); + } + } +} + +extern ia64_rr vmx_vcpu_rr(VCPU *vcpu, u64 vadr); + +static int vmx_handle_lds(REGS* regs) +{ + regs->cr_ipsr |=IA64_PSR_ED; + return IA64_FAULT; +} + +/* We came here because the H/W VHPT walker failed to find an entry */ +IA64FAULT +vmx_hpw_miss(u64 vadr, u64 vec, REGS* regs) +{ + IA64_PSR vpsr; + int type; + u64 vhpt_adr, gppa, pteval, rr, itir; + ISR misr; + PTA vpta; + thash_data_t *data; + VCPU *v = current; + + vpsr.val = VCPU(v, vpsr); + misr.val = VMX(v,cr_isr); + + if (vec == 1) + type = ISIDE_TLB; + else if (vec == 2) + type = DSIDE_TLB; + else + panic_domain(regs, "wrong vec:%lx\n", vec); + + /* Physical mode and region is 0 or 4. */ + if (is_physical_mode(v) && (!((vadr<<1)>>62))) { + if (vec == 2) { + /* DTLB miss. */ + if (misr.sp) /* Refer to SDM Vol2 Table 4-11,4-12 */ + return vmx_handle_lds(regs); + if (v->domain != dom0 + && __gpfn_is_io(v->domain, (vadr << 1) >> (PAGE_SHIFT + 1))) { + emulate_io_inst(v, ((vadr<<1)>>1),4); // UC + return IA64_FAULT; + } + } + physical_tlb_miss(v, vadr, type); + return IA64_FAULT; + } + +try_again: + if ((data=vtlb_lookup(v, vadr,type)) != 0) { + if (v->domain != dom0 && type == DSIDE_TLB) { + if (misr.sp) { /* Refer to SDM Vol2 Table 4-10,4-12 */ + if ((data->ma == VA_MATTR_UC) || (data->ma == VA_MATTR_UCE)) + return vmx_handle_lds(regs); + } + gppa = (vadr & ((1UL << data->ps) - 1)) + + (data->ppn >> (data->ps - 12) << data->ps); + if (__gpfn_is_io(v->domain, gppa >> PAGE_SHIFT)) { + if (misr.sp) + panic_domain(NULL, "ld.s on I/O page not with UC attr." + " pte=0x%lx\n", data->page_flags); + 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 IA64_FAULT; + } + } + thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type); + + } + else if (type == DSIDE_TLB) { + + if (misr.sp) + return vmx_handle_lds(regs); + + vcpu_get_rr(v, vadr, &rr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + + if (!vhpt_enabled(v, vadr, misr.rs ? RSE_REF : DATA_REF)){ + if (GOS_WINDOWS(v)) { + /* windows use region 4 and 5 for identity mapping */ + if (REGION_NUMBER(vadr) == 4 && !(regs->cr_ipsr & IA64_PSR_CPL) + && (REGION_OFFSET(vadr) <= _PAGE_PPN_MASK)) { + + pteval = PAGEALIGN(REGION_OFFSET(vadr), itir_ps(itir)) | + (_PAGE_P | _PAGE_A | _PAGE_D | + _PAGE_MA_WB | _PAGE_AR_RW); + + if (thash_purge_and_insert(v, pteval, itir, vadr, type)) + goto try_again; + + return IA64_NO_FAULT; + } + + if (REGION_NUMBER(vadr) == 5 && !(regs->cr_ipsr & IA64_PSR_CPL) + && (REGION_OFFSET(vadr) <= _PAGE_PPN_MASK)) { + + pteval = PAGEALIGN(REGION_OFFSET(vadr),itir_ps(itir)) | + (_PAGE_P | _PAGE_A | _PAGE_D | + _PAGE_MA_UC | _PAGE_AR_RW); + + if (thash_purge_and_insert(v, pteval, itir, vadr, type)) + goto try_again; + + return IA64_NO_FAULT; + } + } + + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + alt_dtlb(v, vadr); + return IA64_FAULT; + } + else { + nested_dtlb(v); + return IA64_FAULT; + } + } + + vpta.val = vmx_vcpu_get_pta(v); + if (vpta.vf) { + /* Long format is not yet supported. */ + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + return IA64_FAULT; + } + else { + nested_dtlb(v); + return IA64_FAULT; + } + } + + /* avoid recursively walking (short format) VHPT */ + if (!GOS_WINDOWS(v) && + (((vadr ^ vpta.val) << 3) >> (vpta.size + 3)) == 0) { + + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + return IA64_FAULT; + } + else { + nested_dtlb(v); + return IA64_FAULT; + } + } + + vhpt_adr = vmx_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); + return IA64_FAULT; + } + else { + nested_dtlb(v); + return IA64_FAULT; + } + } + else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) { + thash_purge_and_insert(v, pteval, itir, vadr, DSIDE_TLB); + return IA64_NO_FAULT; + } + else if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + return IA64_FAULT; + } + else { + nested_dtlb(v); + return IA64_FAULT; + } + } + else { + /* Can't read VHPT. */ + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dvhpt_fault(v, vadr); + return IA64_FAULT; + } + else { + nested_dtlb(v); + return IA64_FAULT; + } + } + } + else if (type == ISIDE_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 IA64_FAULT; + } + + vpta.val = vmx_vcpu_get_pta(v); + if (vpta.vf) { + /* Long format is not yet supported. */ + vcpu_set_isr(v, misr.val); + itlb_fault(v, vadr); + return IA64_FAULT; + } + + + vhpt_adr = vmx_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 IA64_FAULT; + } + vcpu_get_rr(v, vadr, &rr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + thash_purge_and_insert(v, pteval, itir, vadr, ISIDE_TLB); + return IA64_NO_FAULT; + } + else { + vcpu_set_isr(v, misr.val); + inst_page_not_present(v, vadr); + return IA64_FAULT; + } + } + else { + vcpu_set_isr(v, misr.val); + ivhpt_fault(v, vadr); + return IA64_FAULT; + } + } + return IA64_NO_FAULT; +} diff -r 3b7216fae721 -r 29b29459c94c xen/arch/ia64/vmx/vmx_process.c --- a/xen/arch/ia64/vmx/vmx_process.c Thu Jul 05 03:45:46 2007 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,528 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_process.c: handling VMX architecture-related VM exits - * 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. - * - * Xiaoyan Feng (Fleming Feng) - * Xuefei Xu (Anthony Xu) (Anthony.xu@xxxxxxxxx) - */ - -#include -#include -#include -#include -#include -#include -#include - -#include /* FOR EFI_UNIMPLEMENTED */ -#include /* FOR struct ia64_sal_retval */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */ -#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 - - -extern void die_if_kernel(char *str, struct pt_regs *regs, long err); -extern void rnat_consumption (VCPU *vcpu); -extern void alt_itlb (VCPU *vcpu, u64 vadr); -extern void itlb_fault (VCPU *vcpu, u64 vadr); -extern void ivhpt_fault (VCPU *vcpu, u64 vadr); -extern unsigned long handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr); - -#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 -}; - - - -void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim, - u64 vec, REGS *regs) -{ - u64 status, vector; - VCPU *vcpu = current; - u64 vpsr = VCPU(vcpu, vpsr); - - vector = vec2off[vec]; - - switch (vec) { - case 5: // IA64_DATA_NESTED_TLB_VECTOR - break; - case 22: // IA64_INST_ACCESS_RIGHTS_VECTOR - if (!(vpsr & IA64_PSR_IC)) - goto nested_fault; - if (vhpt_access_rights_fixup(vcpu, ifa, 0)) - return; - break; - - case 25: // IA64_DISABLED_FPREG_VECTOR - if (!(vpsr & IA64_PSR_IC)) - goto nested_fault; - if (FP_PSR(vcpu) & IA64_PSR_DFH) { - FP_PSR(vcpu) = IA64_PSR_MFH; - if (__ia64_per_cpu_var(fp_owner) != vcpu) - __ia64_load_fpu(vcpu->arch._thread.fph); - } - if (!(VCPU(vcpu, vpsr) & IA64_PSR_DFH)) { - regs->cr_ipsr &= ~IA64_PSR_DFH; - return; - } - - break; - - case 32: // IA64_FP_FAULT_VECTOR - if (!(vpsr & IA64_PSR_IC)) - goto nested_fault; - // handle fpswa emulation - // fp fault - status = handle_fpu_swa(1, regs, isr); - if (!status) { - vcpu_increment_iip(vcpu); - return; - } else if (IA64_RETRY == status) - return; - break; - - case 33: // IA64_FP_TRAP_VECTOR - if (!(vpsr & IA64_PSR_IC)) - goto nested_fault; - //fp trap - status = handle_fpu_swa(0, regs, isr); - if (!status) - return; - else if (IA64_RETRY == status) { - vcpu_decrement_iip(vcpu); - return; - } - break; - - case 29: // IA64_DEBUG_VECTOR - case 35: // IA64_TAKEN_BRANCH_TRAP_VECTOR - case 36: // IA64_SINGLE_STEP_TRAP_VECTOR - if (vmx_guest_kernel_mode(regs) - && current->domain->debugger_attached) { - domain_pause_for_debugger(); - return; - } - if (!(vpsr & IA64_PSR_IC)) - goto nested_fault; - break; - - default: - if (!(vpsr & IA64_PSR_IC)) - goto nested_fault; - 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); - return; - - nested_fault: - panic_domain(regs, "Guest nested fault vector=%lx!\n", vector); -} - - -IA64FAULT -vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) -{ - struct domain *d = current->domain; - struct vcpu *v = current; - - perfc_incr(vmx_ia64_handle_break); -#ifdef CRASH_DEBUG - if ((iim == 0 || iim == CDB_BREAK_NUM) && !guest_mode(regs) && - IS_VMM_ADDRESS(regs->cr_iip)) { - if (iim == 0) - show_registers(regs); - debugger_trap_fatal(0 /* don't care */, regs); - } else -#endif - { - if (iim == 0) - vmx_die_if_kernel("Break 0 in Hypervisor.", regs, iim); - - if (ia64_psr(regs)->cpl == 0) { - /* Allow hypercalls only when cpl = 0. */ - if (iim == d->arch.breakimm) { - ia64_hypercall(regs); - vcpu_increment_iip(v); - return IA64_NO_FAULT; - } - else if(iim == DOMN_PAL_REQUEST){ - pal_emul(v); - vcpu_increment_iip(v); - return IA64_NO_FAULT; - }else if(iim == DOMN_SAL_REQUEST){ - sal_emul(v); - vcpu_increment_iip(v); - return IA64_NO_FAULT; - } - } - vmx_reflect_interruption(ifa,isr,iim,11,regs); - } - return IA64_NO_FAULT; -} - - -void save_banked_regs_to_vpd(VCPU *v, REGS *regs) -{ - unsigned long i=0UL, * src,* dst, *sunat, *dunat; - IA64_PSR vpsr; - src=®s->r16; - sunat=®s->eml_unat; - vpsr.val = VCPU(v, vpsr); - if(vpsr.bn){ - dst = &VCPU(v, vgr[0]); - dunat =&VCPU(v, vnat); - __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;; \ - dep %2 = %0, %2, 0, 16;; \ - st8 [%3] = %2;;" - ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); - - }else{ - dst = &VCPU(v, vbgr[0]); -// dunat =&VCPU(v, vbnat); -// __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;; -// dep %2 = %0, %2, 16, 16;; -// st8 [%3] = %2;;" -// ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); - - } - for(i=0; i<16; i++) - *dst++ = *src++; -} - - -// ONLY gets called from ia64_leave_kernel -// ONLY call with interrupts disabled?? (else might miss one?) -// NEVER successful if already reflecting a trap/fault because psr.i==0 -void leave_hypervisor_tail(void) -{ - struct domain *d = current->domain; - struct vcpu *v = current; - - // FIXME: Will this work properly if doing an RFI??? - if (!is_idle_domain(d) ) { // always comes from guest -// struct pt_regs *user_regs = vcpu_regs(current); - local_irq_enable(); - do_softirq(); - local_irq_disable(); - - if (v->vcpu_id == 0) { - unsigned long callback_irq = - d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; - - if ( v->arch.arch_vmx.pal_init_pending ) { - /*inject INIT interruption to guest pal*/ - v->arch.arch_vmx.pal_init_pending = 0; - deliver_pal_init(v); - return; - } - - /* - * val[63:56] == 1: val[55:0] is a delivery PCI INTx line: - * Domain = val[47:32], Bus = val[31:16], - * DevFn = val[15: 8], IntX = val[ 1: 0] - * val[63:56] == 0: val[55:0] is a delivery as GSI - */ - if (callback_irq != 0 && local_events_need_delivery()) { - /* change level for para-device callback irq */ - /* use level irq to send discrete event */ - if ((uint8_t)(callback_irq >> 56) == 1) { - /* case of using PCI INTx line as callback irq */ - int pdev = (callback_irq >> 11) & 0x1f; - int pintx = callback_irq & 3; - viosapic_set_pci_irq(d, pdev, pintx, 1); - viosapic_set_pci_irq(d, pdev, pintx, 0); - } else { - /* case of using GSI as callback irq */ - viosapic_set_irq(d, callback_irq, 1); - viosapic_set_irq(d, callback_irq, 0); - } - } - } - - rmb(); - if (xchg(&v->arch.irq_new_pending, 0)) { - v->arch.irq_new_condition = 0; - vmx_check_pending_irq(v); - return; - } - - if (v->arch.irq_new_condition) { - v->arch.irq_new_condition = 0; - vhpi_detection(v); - } - } -} - -extern ia64_rr vmx_vcpu_rr(VCPU *vcpu, u64 vadr); - -static int vmx_handle_lds(REGS* regs) -{ - regs->cr_ipsr |=IA64_PSR_ED; - return IA64_FAULT; -} - -/* We came here because the H/W VHPT walker failed to find an entry */ -IA64FAULT -vmx_hpw_miss(u64 vadr , u64 vec, REGS* regs) -{ - IA64_PSR vpsr; - int type; - u64 vhpt_adr, gppa, pteval, rr, itir; - ISR misr; - PTA vpta; - thash_data_t *data; - VCPU *v = current; - - vpsr.val = VCPU(v, vpsr); - misr.val = VMX(v,cr_isr); - - if (vec == 1) - type = ISIDE_TLB; - else if (vec == 2) - type = DSIDE_TLB; - else - panic_domain(regs, "wrong vec:%lx\n", vec); - - if(is_physical_mode(v)&&(!(vadr<<1>>62))){ - if(vec==2){ - if (misr.sp) /* Refer to SDM Vol2 Table 4-11,4-12 */ - return vmx_handle_lds(regs); - if (v->domain != dom0 - && __gpfn_is_io(v->domain, (vadr << 1) >> (PAGE_SHIFT + 1))) { - emulate_io_inst(v,((vadr<<1)>>1),4); // UC - return IA64_FAULT; - } - } - physical_tlb_miss(v, vadr, type); - return IA64_FAULT; - } - -try_again: - if((data=vtlb_lookup(v, vadr,type))!=0){ - if (v->domain != dom0 && type == DSIDE_TLB) { - if (misr.sp) { /* Refer to SDM Vol2 Table 4-10,4-12 */ - if ((data->ma == VA_MATTR_UC) || (data->ma == VA_MATTR_UCE)) - return vmx_handle_lds(regs); - } - gppa = (vadr & ((1UL << data->ps) - 1)) + - (data->ppn >> (data->ps - 12) << data->ps); - if (__gpfn_is_io(v->domain, gppa >> PAGE_SHIFT)) { - if (misr.sp) - panic_domain(NULL, "ld.s on I/O page not with UC attr." - " pte=0x%lx\n", data->page_flags); - 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 IA64_FAULT; - } - } - thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type); - - }else if(type == DSIDE_TLB){ - - if (misr.sp) - return vmx_handle_lds(regs); - - vcpu_get_rr(v, vadr, &rr); - itir = rr & (RR_RID_MASK | RR_PS_MASK); - - if(!vhpt_enabled(v, vadr, misr.rs?RSE_REF:DATA_REF)){ - if (GOS_WINDOWS(v)) { - /* windows use region 4 and 5 for identity mapping */ - if (REGION_NUMBER(vadr) == 4 && !(regs->cr_ipsr & IA64_PSR_CPL) - && (REGION_OFFSET(vadr)<= _PAGE_PPN_MASK)) { - - pteval = PAGEALIGN(REGION_OFFSET(vadr), itir_ps(itir)) | - (_PAGE_P | _PAGE_A | _PAGE_D | - _PAGE_MA_WB | _PAGE_AR_RW); - - if (thash_purge_and_insert(v, pteval, itir, vadr, type)) - goto try_again; - - return IA64_NO_FAULT; - } - - if (REGION_NUMBER(vadr) == 5 && !(regs->cr_ipsr & IA64_PSR_CPL) - && (REGION_OFFSET(vadr)<= _PAGE_PPN_MASK)) { - - pteval = PAGEALIGN(REGION_OFFSET(vadr),itir_ps(itir)) | - (_PAGE_P | _PAGE_A | _PAGE_D | - _PAGE_MA_UC | _PAGE_AR_RW); - - if (thash_purge_and_insert(v, pteval, itir, vadr, type)) - goto try_again; - - return IA64_NO_FAULT; - } - } - - if(vpsr.ic){ - vcpu_set_isr(v, misr.val); - alt_dtlb(v, vadr); - return IA64_FAULT; - } else{ - nested_dtlb(v); - return IA64_FAULT; - } - } - - vpta.val = vmx_vcpu_get_pta(v); - if (vpta.vf) { - /* Long format is not yet supported. */ - if (vpsr.ic) { - vcpu_set_isr(v, misr.val); - dtlb_fault(v, vadr); - return IA64_FAULT; - } else { - nested_dtlb(v); - return IA64_FAULT; - } - } - - /* avoid recursively walking (short format) VHPT */ - if (!GOS_WINDOWS(v) && - (((vadr ^ vpta.val) << 3) >> (vpta.size + 3)) == 0) { - - if (vpsr.ic) { - vcpu_set_isr(v, misr.val); - dtlb_fault(v, vadr); - return IA64_FAULT; - } else { - nested_dtlb(v); - return IA64_FAULT; - } - } - - vhpt_adr = vmx_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); - return IA64_FAULT; - } else { - nested_dtlb(v); - return IA64_FAULT; - } - } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) { - thash_purge_and_insert(v, pteval, itir, vadr, DSIDE_TLB); - return IA64_NO_FAULT; - } else if (vpsr.ic) { - vcpu_set_isr(v, misr.val); - dtlb_fault(v, vadr); - return IA64_FAULT; - }else{ - nested_dtlb(v); - return IA64_FAULT; - } - } else { - /* Can't read VHPT. */ - if (vpsr.ic) { - vcpu_set_isr(v, misr.val); - dvhpt_fault(v, vadr); - return IA64_FAULT; - } else { - nested_dtlb(v); - return IA64_FAULT; - } - } - }else if(type == ISIDE_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 IA64_FAULT; - } - - vpta.val = vmx_vcpu_get_pta(v); - if (vpta.vf) { - /* Long format is not yet supported. */ - vcpu_set_isr(v, misr.val); - itlb_fault(v, vadr); - return IA64_FAULT; - } - - - vhpt_adr = vmx_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 IA64_FAULT; - } - vcpu_get_rr(v, vadr, &rr); - itir = rr & (RR_RID_MASK | RR_PS_MASK); - thash_purge_and_insert(v, pteval, itir, vadr, ISIDE_TLB); - return IA64_NO_FAULT; - } else { - vcpu_set_isr(v, misr.val); - inst_page_not_present(v, vadr); - return IA64_FAULT; - } - } else { - vcpu_set_isr(v, misr.val); - ivhpt_fault(v, vadr); - return IA64_FAULT; - } - } - return IA64_NO_FAULT; -}