📄 traps.c
字号:
}void __devinit subarch_percpu_traps_init(void){ struct tss_struct *tss = &doublefault_tss; asmlinkage int hypercall(void); if ( smp_processor_id() != 0 ) return; /* The hypercall entry vector is only accessible from ring 1. */ _set_gate(idt_table+HYPERCALL_VECTOR, 14, 1, &hypercall); /* * Make a separate task for double faults. This will get us debug output if * we blow the kernel stack. */ memset(tss, 0, sizeof(*tss)); tss->ds = __HYPERVISOR_DS; tss->es = __HYPERVISOR_DS; tss->ss = __HYPERVISOR_DS; tss->esp = (unsigned long)&doublefault_stack[DOUBLEFAULT_STACK_SIZE]; tss->__cr3 = __pa(idle_pg_table); tss->cs = __HYPERVISOR_CS; tss->eip = (unsigned long)do_double_fault; tss->eflags = 2; tss->bitmap = IOBMP_INVALID_OFFSET; _set_tssldt_desc( gdt_table + __DOUBLEFAULT_TSS_ENTRY - FIRST_RESERVED_GDT_ENTRY, (unsigned long)tss, 235, 9); set_task_gate(TRAP_double_fault, __DOUBLEFAULT_TSS_ENTRY<<3);}void init_int80_direct_trap(struct vcpu *v){ struct trap_info *ti = &v->arch.guest_context.trap_ctxt[0x80]; /* * We can't virtualise interrupt gates, as there's no way to get * the CPU to automatically clear the events_mask variable. Also we * must ensure that the CS is safe to poke into an interrupt gate. * * When running with supervisor_mode_kernel enabled a direct trap * to the guest OS cannot be used because the INT instruction will * switch to the Xen stack and we need to swap back to the guest * kernel stack before passing control to the system call entry point. */ if ( TI_GET_IF(ti) || !guest_gate_selector_okay(v->domain, ti->cs) || supervisor_mode_kernel ) { v->arch.int80_desc.a = v->arch.int80_desc.b = 0; return; } v->arch.int80_desc.a = (ti->cs << 16) | (ti->address & 0xffff); v->arch.int80_desc.b = (ti->address & 0xffff0000) | 0x8f00 | ((TI_GET_DPL(ti) & 3) << 13); if ( v == current ) set_int80_direct_trap(v);}#ifdef CONFIG_X86_SUPERVISOR_MODE_KERNELstatic void do_update_sysenter(void *info){ xen_callback_t *address = info; wrmsr(MSR_IA32_SYSENTER_CS, address->cs, 0); wrmsr(MSR_IA32_SYSENTER_EIP, address->eip, 0);}#endifstatic long register_guest_callback(struct callback_register *reg){ long ret = 0; struct vcpu *v = current; fixup_guest_code_selector(v->domain, reg->address.cs); switch ( reg->type ) { case CALLBACKTYPE_event: v->arch.guest_context.event_callback_cs = reg->address.cs; v->arch.guest_context.event_callback_eip = reg->address.eip; break; case CALLBACKTYPE_failsafe: v->arch.guest_context.failsafe_callback_cs = reg->address.cs; v->arch.guest_context.failsafe_callback_eip = reg->address.eip; if ( reg->flags & CALLBACKF_mask_events ) set_bit(_VGCF_failsafe_disables_events, &v->arch.guest_context.flags); else clear_bit(_VGCF_failsafe_disables_events, &v->arch.guest_context.flags); break;#ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL case CALLBACKTYPE_sysenter_deprecated: if ( !cpu_has_sep ) ret = -EINVAL; else if ( on_each_cpu(do_update_sysenter, ®->address, 1, 1) != 0 ) ret = -EIO; break; case CALLBACKTYPE_sysenter: if ( !cpu_has_sep ) ret = -EINVAL; else do_update_sysenter(®->address); break;#endif case CALLBACKTYPE_nmi: ret = register_guest_nmi_callback(reg->address.eip); break; default: ret = -ENOSYS; break; } return ret;}static long unregister_guest_callback(struct callback_unregister *unreg){ long ret; switch ( unreg->type ) { case CALLBACKTYPE_event: case CALLBACKTYPE_failsafe:#ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL case CALLBACKTYPE_sysenter_deprecated: case CALLBACKTYPE_sysenter:#endif ret = -EINVAL; break; case CALLBACKTYPE_nmi: ret = unregister_guest_nmi_callback(); break; default: ret = -ENOSYS; break; } return ret;}long do_callback_op(int cmd, XEN_GUEST_HANDLE(const_void) arg){ long ret; switch ( cmd ) { case CALLBACKOP_register: { struct callback_register reg; ret = -EFAULT; if ( copy_from_guest(®, arg, 1) ) break; ret = register_guest_callback(®); } break; case CALLBACKOP_unregister: { struct callback_unregister unreg; ret = -EFAULT; if ( copy_from_guest(&unreg, arg, 1) ) break; ret = unregister_guest_callback(&unreg); } break; default: ret = -ENOSYS; break; } return ret;}long do_set_callbacks(unsigned long event_selector, unsigned long event_address, unsigned long failsafe_selector, unsigned long failsafe_address){ struct callback_register event = { .type = CALLBACKTYPE_event, .address = { event_selector, event_address }, }; struct callback_register failsafe = { .type = CALLBACKTYPE_failsafe, .address = { failsafe_selector, failsafe_address }, }; register_guest_callback(&event); register_guest_callback(&failsafe); return 0;}static void hypercall_page_initialise_ring0_kernel(void *hypercall_page){ extern asmlinkage int hypercall(void); char *p; int i; /* Fill in all the transfer points with template machine code. */ for ( i = 0; i < (PAGE_SIZE / 32); i++ ) { p = (char *)(hypercall_page + (i * 32)); *(u8 *)(p+ 0) = 0x9c; /* pushf */ *(u8 *)(p+ 1) = 0xfa; /* cli */ *(u8 *)(p+ 2) = 0xb8; /* mov $<i>,%eax */ *(u32 *)(p+ 3) = i; *(u8 *)(p+ 7) = 0x9a; /* lcall $__HYPERVISOR_CS,&hypercall */ *(u32 *)(p+ 8) = (u32)&hypercall; *(u16 *)(p+12) = (u16)__HYPERVISOR_CS; *(u8 *)(p+14) = 0xc3; /* ret */ } /* * HYPERVISOR_iret is special because it doesn't return and expects a * special stack frame. Guests jump at this transfer point instead of * calling it. */ p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32)); *(u8 *)(p+ 0) = 0x50; /* push %eax */ *(u8 *)(p+ 1) = 0x9c; /* pushf */ *(u8 *)(p+ 2) = 0xfa; /* cli */ *(u8 *)(p+ 3) = 0xb8; /* mov $<i>,%eax */ *(u32 *)(p+ 4) = __HYPERVISOR_iret; *(u8 *)(p+ 8) = 0x9a; /* lcall $__HYPERVISOR_CS,&hypercall */ *(u32 *)(p+ 9) = (u32)&hypercall; *(u16 *)(p+13) = (u16)__HYPERVISOR_CS;}static void hypercall_page_initialise_ring1_kernel(void *hypercall_page){ char *p; int i; /* Fill in all the transfer points with template machine code. */ for ( i = 0; i < (PAGE_SIZE / 32); i++ ) { p = (char *)(hypercall_page + (i * 32)); *(u8 *)(p+ 0) = 0xb8; /* mov $<i>,%eax */ *(u32 *)(p+ 1) = i; *(u16 *)(p+ 5) = 0x82cd; /* int $0x82 */ *(u8 *)(p+ 7) = 0xc3; /* ret */ } /* * HYPERVISOR_iret is special because it doesn't return and expects a * special stack frame. Guests jump at this transfer point instead of * calling it. */ p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32)); *(u8 *)(p+ 0) = 0x50; /* push %eax */ *(u8 *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */ *(u32 *)(p+ 2) = __HYPERVISOR_iret; *(u16 *)(p+ 6) = 0x82cd; /* int $0x82 */}void hypercall_page_initialise(struct domain *d, void *hypercall_page){ memset(hypercall_page, 0xCC, PAGE_SIZE); if ( is_hvm_domain(d) ) hvm_hypercall_page_initialise(d, hypercall_page); else if ( supervisor_mode_kernel ) hypercall_page_initialise_ring0_kernel(hypercall_page); else hypercall_page_initialise_ring1_kernel(hypercall_page);}/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -