📄 traps.c
字号:
{ unsigned int width, i, match = 0; unsigned long start; if ( !(v->arch.guest_context.debugreg[5]) || !(v->arch.guest_context.ctrlreg[4] & X86_CR4_DE) ) return 0; for ( i = 0; i < 4; i++ ) { if ( !(v->arch.guest_context.debugreg[5] & (3 << (i * DR_ENABLE_SIZE))) ) continue; start = v->arch.guest_context.debugreg[i]; width = 0; switch ( (v->arch.guest_context.debugreg[7] >> (DR_CONTROL_SHIFT + i * DR_CONTROL_SIZE)) & 0xc ) { case DR_LEN_1: width = 1; break; case DR_LEN_2: width = 2; break; case DR_LEN_4: width = 4; break; case DR_LEN_8: width = 8; break; } if ( (start < (port + len)) && ((start + width) > port) ) match |= 1 << i; } return match;}/* * Called from asm to set up the NMI trapbounce info. * Returns 0 if no callback is set up, else 1. */asmlinkage int set_guest_nmi_trapbounce(void){ struct vcpu *v = current; struct trap_bounce *tb = &v->arch.trap_bounce; do_guest_trap(TRAP_nmi, guest_cpu_user_regs(), 0); tb->flags &= ~TBF_EXCEPTION; /* not needed for NMI delivery path */ return !null_trap_bounce(v, tb);}static inline void do_trap( int trapnr, struct cpu_user_regs *regs, int use_error_code){ unsigned long fixup; DEBUGGER_trap_entry(trapnr, regs); if ( guest_mode(regs) ) { do_guest_trap(trapnr, regs, use_error_code); return; } if ( likely((fixup = search_exception_table(regs->eip)) != 0) ) { dprintk(XENLOG_ERR, "Trap %d: %p -> %p\n", trapnr, _p(regs->eip), _p(fixup)); regs->eip = fixup; return; } DEBUGGER_trap_fatal(trapnr, regs); show_execution_state(regs); panic("FATAL TRAP: vector = %d (%s)\n" "[error_code=%04x]\n", trapnr, trapstr(trapnr), regs->error_code);}#define DO_ERROR_NOCODE(trapnr, name) \asmlinkage void do_##name(struct cpu_user_regs *regs) \{ \ do_trap(trapnr, regs, 0); \}#define DO_ERROR(trapnr, name) \asmlinkage void do_##name(struct cpu_user_regs *regs) \{ \ do_trap(trapnr, regs, 1); \}DO_ERROR_NOCODE(TRAP_divide_error, divide_error)DO_ERROR_NOCODE(TRAP_overflow, overflow)DO_ERROR_NOCODE(TRAP_bounds, bounds)DO_ERROR_NOCODE(TRAP_copro_seg, coprocessor_segment_overrun)DO_ERROR( TRAP_invalid_tss, invalid_TSS)DO_ERROR( TRAP_no_segment, segment_not_present)DO_ERROR( TRAP_stack_error, stack_segment)DO_ERROR_NOCODE(TRAP_copro_error, coprocessor_error)DO_ERROR( TRAP_alignment_check, alignment_check)DO_ERROR_NOCODE(TRAP_simd_error, simd_coprocessor_error)int rdmsr_hypervisor_regs( uint32_t idx, uint32_t *eax, uint32_t *edx){ idx -= 0x40000000; if ( idx > 0 ) return 0; switch ( idx ) { case 0: { *eax = *edx = 0; break; } default: BUG(); } return 1;}int wrmsr_hypervisor_regs( uint32_t idx, uint32_t eax, uint32_t edx){ struct domain *d = current->domain; idx -= 0x40000000; if ( idx > 0 ) return 0; switch ( idx ) { case 0: { void *hypercall_page; unsigned long mfn; unsigned long gmfn = ((unsigned long)edx << 20) | (eax >> 12); unsigned int idx = eax & 0xfff; if ( idx > 0 ) { gdprintk(XENLOG_WARNING, "Out of range index %u to MSR %08x\n", idx, 0x40000000); return 0; } mfn = gmfn_to_mfn(d, gmfn); if ( !mfn_valid(mfn) || !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) ) { gdprintk(XENLOG_WARNING, "Bad GMFN %lx (MFN %lx) to MSR %08x\n", gmfn, mfn, 0x40000000); return 0; } hypercall_page = map_domain_page(mfn); hypercall_page_initialise(d, hypercall_page); unmap_domain_page(hypercall_page); put_page_and_type(mfn_to_page(mfn)); break; } default: BUG(); } return 1;}int cpuid_hypervisor_leaves( uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx){ idx -= 0x40000000; if ( idx > 2 ) return 0; switch ( idx ) { case 0: *eax = 0x40000002; /* Largest leaf */ *ebx = 0x566e6558; /* Signature 1: "XenV" */ *ecx = 0x65584d4d; /* Signature 2: "MMXe" */ *edx = 0x4d4d566e; /* Signature 3: "nVMM" */ break; case 1: *eax = (xen_major_version() << 16) | xen_minor_version(); *ebx = 0; /* Reserved */ *ecx = 0; /* Reserved */ *edx = 0; /* Reserved */ break; case 2: *eax = 1; /* Number of hypercall-transfer pages */ *ebx = 0x40000000; /* MSR base address */ *ecx = 0; /* Features 1 */ *edx = 0; /* Features 2 */ break; default: BUG(); } return 1;}static int emulate_forced_invalid_op(struct cpu_user_regs *regs){ char sig[5], instr[2]; uint32_t a, b, c, d; unsigned long eip, rc; a = regs->eax; b = regs->ebx; c = regs->ecx; d = regs->edx; eip = regs->eip; /* Check for forced emulation signature: ud2 ; .ascii "xen". */ if ( (rc = copy_from_user(sig, (char *)eip, sizeof(sig))) != 0 ) { propagate_page_fault(eip + sizeof(sig) - rc, 0); return EXCRET_fault_fixed; } if ( memcmp(sig, "\xf\xbxen", sizeof(sig)) ) return 0; eip += sizeof(sig); /* We only emulate CPUID. */ if ( ( rc = copy_from_user(instr, (char *)eip, sizeof(instr))) != 0 ) { propagate_page_fault(eip + sizeof(instr) - rc, 0); return EXCRET_fault_fixed; } if ( memcmp(instr, "\xf\xa2", sizeof(instr)) ) return 0; eip += sizeof(instr); asm ( "cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "0" (a), "1" (b), "2" (c), "3" (d) ); if ( (regs->eax & 0x7fffffff) == 1 ) { /* Modify Feature Information. */ __clear_bit(X86_FEATURE_VME, &d); __clear_bit(X86_FEATURE_PSE, &d); __clear_bit(X86_FEATURE_PGE, &d); __clear_bit(X86_FEATURE_MCE, &d); __clear_bit(X86_FEATURE_MCA, &d); if ( !IS_PRIV(current->domain) ) __clear_bit(X86_FEATURE_MTRR, &d); __clear_bit(X86_FEATURE_PSE36, &d); } switch ( (uint32_t)regs->eax ) { case 1: /* Modify Feature Information. */ if ( !cpu_has_sep ) __clear_bit(X86_FEATURE_SEP, &d);#ifdef __i386__ if ( !supervisor_mode_kernel ) __clear_bit(X86_FEATURE_SEP, &d);#endif __clear_bit(X86_FEATURE_DS, &d); __clear_bit(X86_FEATURE_ACC, &d); __clear_bit(X86_FEATURE_PBE, &d); __clear_bit(X86_FEATURE_DTES64 % 32, &c); __clear_bit(X86_FEATURE_MWAIT % 32, &c); __clear_bit(X86_FEATURE_DSCPL % 32, &c); __clear_bit(X86_FEATURE_VMXE % 32, &c); __clear_bit(X86_FEATURE_SMXE % 32, &c); __clear_bit(X86_FEATURE_EST % 32, &c); __clear_bit(X86_FEATURE_TM2 % 32, &c); if ( is_pv_32bit_vcpu(current) ) __clear_bit(X86_FEATURE_CX16 % 32, &c); __clear_bit(X86_FEATURE_XTPR % 32, &c); __clear_bit(X86_FEATURE_PDCM % 32, &c); __clear_bit(X86_FEATURE_DCA % 32, &c); break; case 0x80000001: /* Modify Feature Information. */ if ( is_pv_32bit_vcpu(current) ) { __clear_bit(X86_FEATURE_LM % 32, &d); __clear_bit(X86_FEATURE_LAHF_LM % 32, &c); }#ifndef __i386__ if ( is_pv_32on64_vcpu(current) && boot_cpu_data.x86_vendor != X86_VENDOR_AMD )#endif __clear_bit(X86_FEATURE_SYSCALL % 32, &d); __clear_bit(X86_FEATURE_PAGE1GB % 32, &d); __clear_bit(X86_FEATURE_RDTSCP % 32, &d); __clear_bit(X86_FEATURE_SVME % 32, &c); __clear_bit(X86_FEATURE_OSVW % 32, &c); __clear_bit(X86_FEATURE_IBS % 32, &c); __clear_bit(X86_FEATURE_SKINIT % 32, &c); __clear_bit(X86_FEATURE_WDT % 32, &c); break; case 5: /* MONITOR/MWAIT */ case 0xa: /* Architectural Performance Monitor Features */ case 0x8000000a: /* SVM revision and features */ case 0x8000001b: /* Instruction Based Sampling */ a = b = c = d = 0; break; default: (void)cpuid_hypervisor_leaves(regs->eax, &a, &b, &c, &d); break; } regs->eax = a; regs->ebx = b; regs->ecx = c; regs->edx = d; instruction_done(regs, eip, 0); trace_trap_one_addr(TRC_PV_FORCED_INVALID_OP, regs->eip); return EXCRET_fault_fixed;}asmlinkage void do_invalid_op(struct cpu_user_regs *regs){ struct bug_frame bug; struct bug_frame_str bug_str; char *filename, *predicate, *eip = (char *)regs->eip; unsigned long fixup; int id, lineno; DEBUGGER_trap_entry(TRAP_invalid_op, regs); if ( likely(guest_mode(regs)) ) { if ( !emulate_forced_invalid_op(regs) ) do_guest_trap(TRAP_invalid_op, regs, 0); return; } if ( !is_kernel(eip) || __copy_from_user(&bug, eip, sizeof(bug)) || memcmp(bug.ud2, "\xf\xb", sizeof(bug.ud2)) || (bug.ret != 0xc2) ) goto die; eip += sizeof(bug); id = bug.id & 3; if ( id == BUGFRAME_dump ) { show_execution_state(regs); regs->eip = (unsigned long)eip; return; } /* WARN, BUG or ASSERT: decode the filename pointer and line number. */ if ( !is_kernel(eip) || __copy_from_user(&bug_str, eip, sizeof(bug_str)) || memcmp(bug_str.mov, BUG_MOV_STR, sizeof(bug_str.mov)) ) goto die; eip += sizeof(bug_str); filename = is_kernel(bug_str.str) ? (char *)bug_str.str : "<unknown>"; lineno = bug.id >> 2; if ( id == BUGFRAME_warn ) { printk("Xen WARN at %.50s:%d\n", filename, lineno); show_execution_state(regs); regs->eip = (unsigned long)eip; return; } if ( id == BUGFRAME_bug ) { printk("Xen BUG at %.50s:%d\n", filename, lineno); DEBUGGER_trap_fatal(TRAP_invalid_op, regs); show_execution_state(regs); panic("Xen BUG at %.50s:%d\n", filename, lineno); } /* ASSERT: decode the predicate string pointer. */ ASSERT(id == BUGFRAME_assert); if ( !is_kernel(eip) || __copy_from_user(&bug_str, eip, sizeof(bug_str)) || memcmp(bug_str.mov, BUG_MOV_STR, sizeof(bug_str.mov)) ) goto die; eip += sizeof(bug_str); predicate = is_kernel(bug_str.str) ? (char *)bug_str.str : "<unknown>"; printk("Assertion '%s' failed at %.50s:%d\n", predicate, filename, lineno); DEBUGGER_trap_fatal(TRAP_invalid_op, regs); show_execution_state(regs); panic("Assertion '%s' failed at %.50s:%d\n", predicate, filename, lineno); die: if ( (fixup = search_exception_table(regs->eip)) != 0 ) { regs->eip = fixup; return; } DEBUGGER_trap_fatal(TRAP_invalid_op, regs); show_execution_state(regs); panic("FATAL TRAP: vector = %d (invalid opcode)\n", TRAP_invalid_op);}asmlinkage void do_int3(struct cpu_user_regs *regs){ DEBUGGER_trap_entry(TRAP_int3, regs); if ( !guest_mode(regs) ) { debugger_trap_fatal(TRAP_int3, regs); return; } do_guest_trap(TRAP_int3, regs, 0);}asmlinkage void do_machine_check(struct cpu_user_regs *regs){ extern fastcall void (*machine_check_vector)( struct cpu_user_regs *, long error_code);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -