vmx.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 2,245 行 · 第 1/5 页
C
2,245 行
}static void __restore_debug_registers(struct vcpu *v){ if ( v->arch.hvm_vcpu.flag_dr_dirty ) return; v->arch.hvm_vcpu.flag_dr_dirty = 1; write_debugreg(0, v->arch.guest_context.debugreg[0]); write_debugreg(1, v->arch.guest_context.debugreg[1]); write_debugreg(2, v->arch.guest_context.debugreg[2]); write_debugreg(3, v->arch.guest_context.debugreg[3]); write_debugreg(6, v->arch.guest_context.debugreg[6]); /* DR7 is loaded from the VMCS. */}/* * DR7 is saved and restored on every vmexit. Other debug registers only * need to be restored if their value is going to affect execution -- i.e., * if one of the breakpoints is enabled. So mask out all bits that don't * enable some breakpoint functionality. */static void vmx_restore_dr(struct vcpu *v){ /* NB. __vmread() is not usable here, so we cannot read from the VMCS. */ if ( unlikely(v->arch.guest_context.debugreg[7] & DR7_ACTIVE_MASK) ) __restore_debug_registers(v);}static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c){ uint32_t ev; vmx_vmcs_enter(v); c->cr0 = v->arch.hvm_vcpu.guest_cr[0]; c->cr2 = v->arch.hvm_vcpu.guest_cr[2]; c->cr3 = v->arch.hvm_vcpu.guest_cr[3]; c->cr4 = v->arch.hvm_vcpu.guest_cr[4]; c->msr_efer = v->arch.hvm_vcpu.guest_efer; c->sysenter_cs = __vmread(GUEST_SYSENTER_CS); c->sysenter_esp = __vmread(GUEST_SYSENTER_ESP); c->sysenter_eip = __vmread(GUEST_SYSENTER_EIP); c->pending_event = 0; c->error_code = 0; if ( ((ev = __vmread(VM_ENTRY_INTR_INFO)) & INTR_INFO_VALID_MASK) && hvm_event_needs_reinjection((ev >> 8) & 7, ev & 0xff) ) { c->pending_event = ev; c->error_code = __vmread(VM_ENTRY_EXCEPTION_ERROR_CODE); } vmx_vmcs_exit(v);}static int vmx_restore_cr0_cr3( struct vcpu *v, unsigned long cr0, unsigned long cr3){ unsigned long mfn = 0; p2m_type_t p2mt; if ( paging_mode_shadow(v->domain) ) { if ( cr0 & X86_CR0_PG ) { mfn = mfn_x(gfn_to_mfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt)); if ( !p2m_is_ram(p2mt) || !get_page(mfn_to_page(mfn), v->domain) ) { gdprintk(XENLOG_ERR, "Invalid CR3 value=0x%lx\n", cr3); return -EINVAL; } } if ( hvm_paging_enabled(v) ) put_page(pagetable_get_page(v->arch.guest_table)); v->arch.guest_table = pagetable_from_pfn(mfn); } v->arch.hvm_vcpu.guest_cr[0] = cr0 | X86_CR0_ET; v->arch.hvm_vcpu.guest_cr[3] = cr3; return 0;}static int vmx_vmcs_restore(struct vcpu *v, struct hvm_hw_cpu *c){ int rc; if ( c->pending_valid && ((c->pending_type == 1) || (c->pending_type > 6) || (c->pending_reserved != 0)) ) { gdprintk(XENLOG_ERR, "Invalid pending event 0x%"PRIx32".\n", c->pending_event); return -EINVAL; } rc = vmx_restore_cr0_cr3(v, c->cr0, c->cr3); if ( rc ) return rc; vmx_vmcs_enter(v); v->arch.hvm_vcpu.guest_cr[2] = c->cr2; v->arch.hvm_vcpu.guest_cr[4] = c->cr4; vmx_update_guest_cr(v, 0); vmx_update_guest_cr(v, 2); vmx_update_guest_cr(v, 4); v->arch.hvm_vcpu.guest_efer = c->msr_efer; vmx_update_guest_efer(v); __vmwrite(GUEST_SYSENTER_CS, c->sysenter_cs); __vmwrite(GUEST_SYSENTER_ESP, c->sysenter_esp); __vmwrite(GUEST_SYSENTER_EIP, c->sysenter_eip); __vmwrite(GUEST_DR7, c->dr7); vmx_vmcs_exit(v); paging_update_paging_modes(v); if ( c->pending_valid ) { gdprintk(XENLOG_INFO, "Re-injecting 0x%"PRIx32", 0x%"PRIx32"\n", c->pending_event, c->error_code); if ( hvm_event_needs_reinjection(c->pending_type, c->pending_vector) ) { vmx_vmcs_enter(v); __vmwrite(VM_ENTRY_INTR_INFO, c->pending_event); __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, c->error_code); vmx_vmcs_exit(v); } } return 0;}static void vmx_save_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data){#ifdef __x86_64__ struct vmx_msr_state *guest_state = &v->arch.hvm_vmx.msr_state; unsigned long guest_flags = guest_state->flags; data->shadow_gs = v->arch.hvm_vmx.shadow_gs; data->msr_cstar = v->arch.hvm_vmx.cstar; /* save msrs */ data->msr_flags = guest_flags; data->msr_lstar = guest_state->msrs[VMX_INDEX_MSR_LSTAR]; data->msr_star = guest_state->msrs[VMX_INDEX_MSR_STAR]; data->msr_syscall_mask = guest_state->msrs[VMX_INDEX_MSR_SYSCALL_MASK];#endif data->tsc = hvm_get_guest_tsc(v);}static void vmx_load_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data){#ifdef __x86_64__ struct vmx_msr_state *guest_state = &v->arch.hvm_vmx.msr_state; /* restore msrs */ guest_state->flags = data->msr_flags & 7; guest_state->msrs[VMX_INDEX_MSR_LSTAR] = data->msr_lstar; guest_state->msrs[VMX_INDEX_MSR_STAR] = data->msr_star; guest_state->msrs[VMX_INDEX_MSR_SYSCALL_MASK] = data->msr_syscall_mask; v->arch.hvm_vmx.cstar = data->msr_cstar; v->arch.hvm_vmx.shadow_gs = data->shadow_gs;#endif hvm_set_guest_tsc(v, data->tsc);}static void vmx_save_vmcs_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt){ vmx_save_cpu_state(v, ctxt); vmx_vmcs_save(v, ctxt);}static int vmx_load_vmcs_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt){ vmx_load_cpu_state(v, ctxt); if ( vmx_vmcs_restore(v, ctxt) ) { gdprintk(XENLOG_ERR, "vmx_vmcs restore failed!\n"); domain_crash(v->domain); return -EINVAL; } return 0;}static void vmx_fpu_enter(struct vcpu *v){ setup_fpu(v); __vm_clear_bit(EXCEPTION_BITMAP, TRAP_no_device); v->arch.hvm_vmx.host_cr0 &= ~X86_CR0_TS; __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0);}static void vmx_fpu_leave(struct vcpu *v){ ASSERT(!v->fpu_dirtied); ASSERT(read_cr0() & X86_CR0_TS); if ( !(v->arch.hvm_vmx.host_cr0 & X86_CR0_TS) ) { v->arch.hvm_vmx.host_cr0 |= X86_CR0_TS; __vmwrite(HOST_CR0, v->arch.hvm_vmx.host_cr0); } /* * If the guest does not have TS enabled then we must cause and handle an * exception on first use of the FPU. If the guest *does* have TS enabled * then this is not necessary: no FPU activity can occur until the guest * clears CR0.TS, and we will initialise the FPU when that happens. */ if ( !(v->arch.hvm_vcpu.guest_cr[0] & X86_CR0_TS) ) { v->arch.hvm_vcpu.hw_cr[0] |= X86_CR0_TS; __vmwrite(GUEST_CR0, v->arch.hvm_vcpu.hw_cr[0]); __vm_set_bit(EXCEPTION_BITMAP, TRAP_no_device); }}static void vmx_ctxt_switch_from(struct vcpu *v){ vmx_fpu_leave(v); vmx_save_guest_msrs(v); vmx_restore_host_msrs(); vmx_save_dr(v); vpmu_save(v);}static void vmx_ctxt_switch_to(struct vcpu *v){ /* HOST_CR4 in VMCS is always mmu_cr4_features. Sync CR4 now. */ if ( unlikely(read_cr4() != mmu_cr4_features) ) write_cr4(mmu_cr4_features); vmx_restore_guest_msrs(v); vmx_restore_dr(v); vpmu_load(v);}static void vmx_get_segment_register(struct vcpu *v, enum x86_segment seg, struct segment_register *reg){ uint32_t attr = 0; vmx_vmcs_enter(v); switch ( seg ) { case x86_seg_cs: reg->sel = __vmread(GUEST_CS_SELECTOR); reg->limit = __vmread(GUEST_CS_LIMIT); reg->base = __vmread(GUEST_CS_BASE); attr = __vmread(GUEST_CS_AR_BYTES); break; case x86_seg_ds: reg->sel = __vmread(GUEST_DS_SELECTOR); reg->limit = __vmread(GUEST_DS_LIMIT); reg->base = __vmread(GUEST_DS_BASE); attr = __vmread(GUEST_DS_AR_BYTES); break; case x86_seg_es: reg->sel = __vmread(GUEST_ES_SELECTOR); reg->limit = __vmread(GUEST_ES_LIMIT); reg->base = __vmread(GUEST_ES_BASE); attr = __vmread(GUEST_ES_AR_BYTES); break; case x86_seg_fs: reg->sel = __vmread(GUEST_FS_SELECTOR); reg->limit = __vmread(GUEST_FS_LIMIT); reg->base = __vmread(GUEST_FS_BASE); attr = __vmread(GUEST_FS_AR_BYTES); break; case x86_seg_gs: reg->sel = __vmread(GUEST_GS_SELECTOR); reg->limit = __vmread(GUEST_GS_LIMIT); reg->base = __vmread(GUEST_GS_BASE); attr = __vmread(GUEST_GS_AR_BYTES); break; case x86_seg_ss: reg->sel = __vmread(GUEST_SS_SELECTOR); reg->limit = __vmread(GUEST_SS_LIMIT); reg->base = __vmread(GUEST_SS_BASE); attr = __vmread(GUEST_SS_AR_BYTES); break; case x86_seg_tr: reg->sel = __vmread(GUEST_TR_SELECTOR); reg->limit = __vmread(GUEST_TR_LIMIT); reg->base = __vmread(GUEST_TR_BASE); attr = __vmread(GUEST_TR_AR_BYTES); break; case x86_seg_gdtr: reg->limit = __vmread(GUEST_GDTR_LIMIT); reg->base = __vmread(GUEST_GDTR_BASE); break; case x86_seg_idtr: reg->limit = __vmread(GUEST_IDTR_LIMIT); reg->base = __vmread(GUEST_IDTR_BASE); break; case x86_seg_ldtr: reg->sel = __vmread(GUEST_LDTR_SELECTOR); reg->limit = __vmread(GUEST_LDTR_LIMIT); reg->base = __vmread(GUEST_LDTR_BASE); attr = __vmread(GUEST_LDTR_AR_BYTES); break; default: BUG(); } vmx_vmcs_exit(v); reg->attr.bytes = (attr & 0xff) | ((attr >> 4) & 0xf00); /* Unusable flag is folded into Present flag. */ if ( attr & (1u<<16) ) reg->attr.fields.p = 0;}static void vmx_set_segment_register(struct vcpu *v, enum x86_segment seg, struct segment_register *reg){ uint32_t attr; attr = reg->attr.bytes; attr = ((attr & 0xf00) << 4) | (attr & 0xff); /* Not-present must mean unusable. */ if ( !reg->attr.fields.p ) attr |= (1u << 16); /* VMX has strict consistency requirement for flag G. */ attr |= !!(reg->limit >> 20) << 15; vmx_vmcs_enter(v); switch ( seg ) { case x86_seg_cs: __vmwrite(GUEST_CS_SELECTOR, reg->sel); __vmwrite(GUEST_CS_LIMIT, reg->limit); __vmwrite(GUEST_CS_BASE, reg->base); __vmwrite(GUEST_CS_AR_BYTES, attr); break; case x86_seg_ds: __vmwrite(GUEST_DS_SELECTOR, reg->sel); __vmwrite(GUEST_DS_LIMIT, reg->limit); __vmwrite(GUEST_DS_BASE, reg->base); __vmwrite(GUEST_DS_AR_BYTES, attr); break; case x86_seg_es: __vmwrite(GUEST_ES_SELECTOR, reg->sel); __vmwrite(GUEST_ES_LIMIT, reg->limit); __vmwrite(GUEST_ES_BASE, reg->base); __vmwrite(GUEST_ES_AR_BYTES, attr); break; case x86_seg_fs: __vmwrite(GUEST_FS_SELECTOR, reg->sel); __vmwrite(GUEST_FS_LIMIT, reg->limit); __vmwrite(GUEST_FS_BASE, reg->base); __vmwrite(GUEST_FS_AR_BYTES, attr); break; case x86_seg_gs: __vmwrite(GUEST_GS_SELECTOR, reg->sel); __vmwrite(GUEST_GS_LIMIT, reg->limit); __vmwrite(GUEST_GS_BASE, reg->base); __vmwrite(GUEST_GS_AR_BYTES, attr); break; case x86_seg_ss: __vmwrite(GUEST_SS_SELECTOR, reg->sel); __vmwrite(GUEST_SS_LIMIT, reg->limit); __vmwrite(GUEST_SS_BASE, reg->base); __vmwrite(GUEST_SS_AR_BYTES, attr); break; case x86_seg_tr: __vmwrite(GUEST_TR_SELECTOR, reg->sel); __vmwrite(GUEST_TR_LIMIT, reg->limit); __vmwrite(GUEST_TR_BASE, reg->base); /* VMX checks that the the busy flag (bit 1) is set. */ __vmwrite(GUEST_TR_AR_BYTES, attr | 2); break; case x86_seg_gdtr: __vmwrite(GUEST_GDTR_LIMIT, reg->limit); __vmwrite(GUEST_GDTR_BASE, reg->base); break; case x86_seg_idtr: __vmwrite(GUEST_IDTR_LIMIT, reg->limit); __vmwrite(GUEST_IDTR_BASE, reg->base); break; case x86_seg_ldtr: __vmwrite(GUEST_LDTR_SELECTOR, reg->sel); __vmwrite(GUEST_LDTR_LIMIT, reg->limit); __vmwrite(GUEST_LDTR_BASE, reg->base); __vmwrite(GUEST_LDTR_AR_BYTES, attr); break; default: BUG(); } vmx_vmcs_exit(v);}static void vmx_set_tsc_offset(struct vcpu *v, u64 offset){ vmx_vmcs_enter(v); __vmwrite(TSC_OFFSET, offset);#if defined (__i386__) __vmwrite(TSC_OFFSET_HIGH, offset >> 32);#endif vmx_vmcs_exit(v);}void do_nmi(struct cpu_user_regs *);static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page){ char *p; int i; for ( i = 0; i < (PAGE_SIZE / 32); i++ ) { p = (char *)(hypercall_page + (i * 32)); *(u8 *)(p + 0) = 0xb8; /* mov imm32, %eax */ *(u32 *)(p + 1) = i; *(u8 *)(p + 5) = 0x0f; /* vmcall */ *(u8 *)(p + 6) = 0x01; *(u8 *)(p + 7) = 0xc1; *(u8 *)(p + 8) = 0xc3; /* ret */ } /* Don't support HYPERVISOR_iret at the moment */ *(u16 *)(hypercall_page + (__HYPERVISOR_iret * 32)) = 0x0b0f; /* ud2 */}static unsigned int vmx_get_interrupt_shadow(struct vcpu *v){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?