📄 faults.c
字号:
/* * Miscellaneous process/domain related routines * * Copyright (C) 2004 Hewlett-Packard Co. * Dan Magenheimer (dan.magenheimer@hp.com) * */#include <xen/config.h>#include <xen/lib.h>#include <xen/errno.h>#include <xen/sched.h>#include <xen/smp.h>#include <asm/ptrace.h>#include <xen/delay.h>#include <xen/perfc.h>#include <xen/mm.h>#include <asm/system.h>#include <asm/processor.h>#include <xen/irq.h>#include <xen/event.h>#include <asm/privop.h>#include <asm/vcpu.h>#include <asm/ia64_int.h>#include <asm/dom_fw.h>#include <asm/vhpt.h>#include <asm/debugger.h>#include <asm/fpswa.h>#include <asm/bundle.h>#include <asm/asm-xsi-offsets.h>#include <asm/shadow.h>#include <asm/uaccess.h>#include <asm/p2m_entry.h>extern void die_if_kernel(char *str, struct pt_regs *regs, long err);/* FIXME: where these declarations shold be there ? */extern int ia64_hyperprivop(unsigned long, REGS *);extern IA64FAULT ia64_hypercall(struct pt_regs *regs);extern void do_ssc(unsigned long ssc, struct pt_regs *regs);// should never panic domain... if it does, stack may have been overrunstatic void check_bad_nested_interruption(unsigned long isr, struct pt_regs *regs, unsigned long vector){ struct vcpu *v = current; if (!(PSCB(v, ipsr) & IA64_PSR_DT)) { panic_domain(regs, "psr.dt off, trying to deliver nested dtlb!\n"); } vector &= ~0xf; if (vector != IA64_DATA_TLB_VECTOR && vector != IA64_ALT_DATA_TLB_VECTOR && vector != IA64_VHPT_TRANS_VECTOR) { panic_domain(regs, "psr.ic off, delivering fault=%lx," "ipsr=%lx,iip=%lx,ifa=%lx,isr=%lx,PSCB.iip=%lx\n", vector, regs->cr_ipsr, regs->cr_iip, PSCB(v, ifa), isr, PSCB(v, iip)); }}static void reflect_interruption(unsigned long isr, struct pt_regs *regs, unsigned long vector){ struct vcpu *v = current; if (!PSCB(v, interrupt_collection_enabled)) check_bad_nested_interruption(isr, regs, vector); PSCB(v, unat) = regs->ar_unat; // not sure if this is really needed? PSCB(v, precover_ifs) = regs->cr_ifs; PSCB(v, ipsr) = vcpu_get_psr(v); vcpu_bsw0(v); PSCB(v, isr) = isr; PSCB(v, iip) = regs->cr_iip; PSCB(v, ifs) = 0; regs->cr_iip = ((unsigned long)PSCBX(v, iva) + vector) & ~0xffUL; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; regs->cr_ipsr = vcpu_pl_adjust(regs->cr_ipsr, IA64_PSR_CPL0_BIT); if (PSCB(v, dcr) & IA64_DCR_BE) regs->cr_ipsr |= IA64_PSR_BE; else regs->cr_ipsr &= ~IA64_PSR_BE; if (PSCB(v, hpsr_dfh)) regs->cr_ipsr |= IA64_PSR_DFH; PSCB(v, vpsr_dfh) = 0; v->vcpu_info->evtchn_upcall_mask = 1; PSCB(v, interrupt_collection_enabled) = 0; perfc_incra(slow_reflect, vector >> 8); debugger_event(vector == IA64_EXTINT_VECTOR ? XEN_IA64_DEBUG_ON_EXTINT : XEN_IA64_DEBUG_ON_EXCEPT);}void reflect_event(void){ struct vcpu *v = current; struct pt_regs *regs; unsigned long isr; if (!event_pending(v)) return; /* Sanity check */ if (is_idle_vcpu(v)) { //printk("WARN: invocation to reflect_event in nested xen\n"); return; } regs = vcpu_regs(v); isr = regs->cr_ipsr & IA64_PSR_RI; if (!PSCB(v, interrupt_collection_enabled)) printk("psr.ic off, delivering event, ipsr=%lx,iip=%lx," "isr=%lx,viip=0x%lx\n", regs->cr_ipsr, regs->cr_iip, isr, PSCB(v, iip)); PSCB(v, unat) = regs->ar_unat; // not sure if this is really needed? PSCB(v, precover_ifs) = regs->cr_ifs; PSCB(v, ipsr) = vcpu_get_psr(v); vcpu_bsw0(v); PSCB(v, isr) = isr; PSCB(v, iip) = regs->cr_iip; PSCB(v, ifs) = 0; regs->cr_iip = v->arch.event_callback_ip; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; regs->cr_ipsr = vcpu_pl_adjust(regs->cr_ipsr, IA64_PSR_CPL0_BIT); if (PSCB(v, dcr) & IA64_DCR_BE) regs->cr_ipsr |= IA64_PSR_BE; else regs->cr_ipsr &= ~IA64_PSR_BE; if (PSCB(v, hpsr_dfh)) regs->cr_ipsr |= IA64_PSR_DFH; PSCB(v, vpsr_dfh) = 0; v->vcpu_info->evtchn_upcall_mask = 1; PSCB(v, interrupt_collection_enabled) = 0; debugger_event(XEN_IA64_DEBUG_ON_EVENT);}static int handle_lazy_cover(struct vcpu *v, struct pt_regs *regs){ if (!PSCB(v, interrupt_collection_enabled)) { PSCB(v, ifs) = regs->cr_ifs; regs->cr_ifs = 0; perfc_incr(lazy_cover); return 1; // retry same instruction with cr.ifs off } return 0;}void ia64_do_page_fault(unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir){ unsigned long iip = regs->cr_iip, iha; // FIXME should validate address here unsigned long pteval; unsigned long is_data = !((isr >> IA64_ISR_X_BIT) & 1UL); IA64FAULT fault; int is_ptc_l_needed = 0; ia64_itir_t _itir = {.itir = itir}; if ((isr & IA64_ISR_SP) || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { /* * This fault was due to a speculative load or lfetch.fault, * set the "ed" bit in the psr to ensure forward progress. * (Target register will get a NaT for ld.s, lfetch will be * canceled.) */ ia64_psr(regs)->ed = 1; return; } again: fault = vcpu_translate(current, address, is_data, &pteval, &itir, &iha); if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) { struct p2m_entry entry; unsigned long m_pteval; m_pteval = translate_domain_pte(pteval, address, itir, &(_itir.itir), &entry); vcpu_itc_no_srlz(current, is_data ? 2 : 1, address, m_pteval, pteval, _itir.itir, &entry); if ((fault == IA64_USE_TLB && !current->arch.dtlb.pte.p) || p2m_entry_retry(&entry)) { /* dtlb has been purged in-between. This dtlb was matching. Undo the work. */ vcpu_flush_tlb_vhpt_range(address, _itir.ps); // the stale entry which we inserted above // may remains in tlb cache. // we don't purge it now hoping next itc purges it. is_ptc_l_needed = 1; goto again; } return; } if (is_ptc_l_needed) vcpu_ptc_l(current, address, _itir.ps); if (!guest_mode(regs)) { /* The fault occurs inside Xen. */ if (!ia64_done_with_exception(regs)) { // should never happen. If it does, region 0 addr may // indicate a bad xen pointer printk("*** xen_handle_domain_access: exception table" " lookup failed, iip=0x%lx, addr=0x%lx, " "spinning...\n", iip, address); panic_domain(regs, "*** xen_handle_domain_access: " "exception table lookup failed, " "iip=0x%lx, addr=0x%lx, spinning...\n", iip, address); } return; } if ((isr & IA64_ISR_IR) && handle_lazy_cover(current, regs)) return; if (!PSCB(current, interrupt_collection_enabled)) { check_bad_nested_interruption(isr, regs, fault); //printk("Delivering NESTED DATA TLB fault\n"); fault = IA64_DATA_NESTED_TLB_VECTOR; regs->cr_iip = ((unsigned long)PSCBX(current, iva) + fault) & ~0xffUL; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; regs->cr_ipsr = vcpu_pl_adjust(regs->cr_ipsr, IA64_PSR_CPL0_BIT); if (PSCB(current, dcr) & IA64_DCR_BE) regs->cr_ipsr |= IA64_PSR_BE; else regs->cr_ipsr &= ~IA64_PSR_BE; if (PSCB(current, hpsr_dfh)) regs->cr_ipsr |= IA64_PSR_DFH; PSCB(current, vpsr_dfh) = 0; perfc_incra(slow_reflect, fault >> 8); return; } PSCB(current, itir) = itir; PSCB(current, iha) = iha; PSCB(current, ifa) = address; reflect_interruption(isr, regs, fault);}fpswa_interface_t *fpswa_interface = 0;void __init trap_init(void){ if (ia64_boot_param->fpswa) /* FPSWA fixup: make the interface pointer a virtual address */ fpswa_interface = __va(ia64_boot_param->fpswa); else printk("No FPSWA supported.\n");}static fpswa_ret_tfp_emulate(int fp_fault, void *bundle, unsigned long *ipsr, unsigned long *fpsr, unsigned long *isr, unsigned long *pr, unsigned long *ifs, struct pt_regs *regs){ fp_state_t fp_state; fpswa_ret_t ret; XEN_EFI_RR_DECLARE(rr6, rr7); if (!fpswa_interface) return (fpswa_ret_t) {-1, 0, 0, 0}; memset(&fp_state, 0, sizeof(fp_state_t)); /* * compute fp_state. only FP registers f6 - f11 are used by the * kernel, so set those bits in the mask and set the low volatile * pointer to point to these registers. */ fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; /* * 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); */ XEN_EFI_RR_ENTER(rr6, rr7); ret = (*fpswa_interface->fpswa) (fp_fault, bundle, ipsr, fpsr, isr, pr, ifs, &fp_state); XEN_EFI_RR_LEAVE(rr6, rr7); return ret;}/* * Handle floating-point assist faults and traps for domain. */unsigned longhandle_fpu_swa(int fp_fault, struct pt_regs *regs, unsigned long isr){ struct vcpu *v = current; 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 (VMX_DOMAIN(current)) { if (IA64_RETRY == __vmx_get_domain_bundle(fault_ip, &bundle)) return IA64_RETRY; } else bundle = __get_domain_bundle(fault_ip); if (!bundle.i64[0] && !bundle.i64[1]) { printk("%s: floating-point bundle at 0x%lx not mapped\n", __FUNCTION__, fault_ip); return -1; } ret = fp_emulate(fp_fault, &bundle, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, ®s->cr_ifs, regs); if (ret.status) { PSCBX(v, fpswa_ret) = ret; printk("%s(%s): fp_emulate() returned %ld\n", __FUNCTION__, fp_fault ? "fault" : "trap", ret.status); } return ret.status;}voidia64_fault(unsigned long vector, unsigned long isr, unsigned long ifa, unsigned long iim, unsigned long itir, unsigned long arg5, unsigned long arg6, unsigned long arg7, unsigned long stack){ struct pt_regs *regs = (struct pt_regs *)&stack; unsigned long code; static const char *const reason[] = { "IA-64 Illegal Operation fault", "IA-64 Privileged Operation fault", "IA-64 Privileged Register fault", "IA-64 Reserved Register/Field fault", "Disabled Instruction Set Transition fault", "Unknown fault 5", "Unknown fault 6", "Unknown fault 7", "Illegal Hazard fault", "Unknown fault 9", "Unknown fault 10", "Unknown fault 11", "Unknown fault 12", "Unknown fault 13", "Unknown fault 14", "Unknown fault 15" }; printk("ia64_fault, vector=0x%lx, ifa=0x%016lx, iip=0x%016lx, " "ipsr=0x%016lx, isr=0x%016lx\n", vector, ifa, regs->cr_iip, regs->cr_ipsr, isr); if ((isr & IA64_ISR_NA) && ((isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { /* * This fault was due to lfetch.fault, set "ed" bit in the * psr to cancel the lfetch. */ ia64_psr(regs)->ed = 1; printk("ia64_fault: handled lfetch.fault\n"); return; } switch (vector) { case 0: printk("VHPT Translation.\n"); break; case 4: printk("Alt DTLB.\n"); break; case 6: printk("Instruction Key Miss.\n"); break; case 7: printk("Data Key Miss.\n"); break; case 8: printk("Dirty-bit.\n"); break; case 20: printk("Page Not Found.\n"); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -