hvm.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 2,304 行 · 第 1/5 页
C
2,304 行
ctxt.r9 = vc->user_regs.r9; ctxt.r10 = vc->user_regs.r10; ctxt.r11 = vc->user_regs.r11; ctxt.r12 = vc->user_regs.r12; ctxt.r13 = vc->user_regs.r13; ctxt.r14 = vc->user_regs.r14; ctxt.r15 = vc->user_regs.r15;#endif ctxt.dr0 = vc->debugreg[0]; ctxt.dr1 = vc->debugreg[1]; ctxt.dr2 = vc->debugreg[2]; ctxt.dr3 = vc->debugreg[3]; ctxt.dr6 = vc->debugreg[6]; ctxt.dr7 = vc->debugreg[7]; if ( hvm_save_entry(CPU, v->vcpu_id, h, &ctxt) != 0 ) return 1; } return 0;}static int hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h){ int vcpuid, rc; struct vcpu *v; struct hvm_hw_cpu ctxt; struct segment_register seg; struct vcpu_guest_context *vc; /* Which vcpu is this? */ vcpuid = hvm_load_instance(h); if ( vcpuid > MAX_VIRT_CPUS || (v = d->vcpu[vcpuid]) == NULL ) { gdprintk(XENLOG_ERR, "HVM restore: domain has no vcpu %u\n", vcpuid); return -EINVAL; } vc = &v->arch.guest_context; /* Need to init this vcpu before loading its contents */ domain_lock(d); if ( !v->is_initialised ) if ( (rc = boot_vcpu(d, vcpuid, vc)) != 0 ) return rc; domain_unlock(d); if ( hvm_load_entry(CPU, h, &ctxt) != 0 ) return -EINVAL; /* Sanity check some control registers. */ if ( (ctxt.cr0 & HVM_CR0_GUEST_RESERVED_BITS) || !(ctxt.cr0 & X86_CR0_ET) || ((ctxt.cr0 & (X86_CR0_PE|X86_CR0_PG)) == X86_CR0_PG) ) { gdprintk(XENLOG_ERR, "HVM restore: bad CR0 0x%"PRIx64"\n", ctxt.cr0); return -EINVAL; } if ( ctxt.cr4 & HVM_CR4_GUEST_RESERVED_BITS ) { gdprintk(XENLOG_ERR, "HVM restore: bad CR4 0x%"PRIx64"\n", ctxt.cr4); return -EINVAL; } if ( (ctxt.msr_efer & ~(EFER_FFXSE | EFER_LME | EFER_LMA | EFER_NX | EFER_SCE)) || ((sizeof(long) != 8) && (ctxt.msr_efer & EFER_LME)) || (!cpu_has_nx && (ctxt.msr_efer & EFER_NX)) || (!cpu_has_syscall && (ctxt.msr_efer & EFER_SCE)) || (!cpu_has_ffxsr && (ctxt.msr_efer & EFER_FFXSE)) || ((ctxt.msr_efer & (EFER_LME|EFER_LMA)) == EFER_LMA) ) { gdprintk(XENLOG_ERR, "HVM restore: bad EFER 0x%"PRIx64"\n", ctxt.msr_efer); return -EINVAL; } /* Architecture-specific vmcs/vmcb bits */ if ( hvm_funcs.load_cpu_ctxt(v, &ctxt) < 0 ) return -EINVAL; seg.limit = ctxt.idtr_limit; seg.base = ctxt.idtr_base; hvm_set_segment_register(v, x86_seg_idtr, &seg); seg.limit = ctxt.gdtr_limit; seg.base = ctxt.gdtr_base; hvm_set_segment_register(v, x86_seg_gdtr, &seg); seg.sel = ctxt.cs_sel; seg.limit = ctxt.cs_limit; seg.base = ctxt.cs_base; seg.attr.bytes = ctxt.cs_arbytes; hvm_set_segment_register(v, x86_seg_cs, &seg); seg.sel = ctxt.ds_sel; seg.limit = ctxt.ds_limit; seg.base = ctxt.ds_base; seg.attr.bytes = ctxt.ds_arbytes; hvm_set_segment_register(v, x86_seg_ds, &seg); seg.sel = ctxt.es_sel; seg.limit = ctxt.es_limit; seg.base = ctxt.es_base; seg.attr.bytes = ctxt.es_arbytes; hvm_set_segment_register(v, x86_seg_es, &seg); seg.sel = ctxt.ss_sel; seg.limit = ctxt.ss_limit; seg.base = ctxt.ss_base; seg.attr.bytes = ctxt.ss_arbytes; hvm_set_segment_register(v, x86_seg_ss, &seg); seg.sel = ctxt.fs_sel; seg.limit = ctxt.fs_limit; seg.base = ctxt.fs_base; seg.attr.bytes = ctxt.fs_arbytes; hvm_set_segment_register(v, x86_seg_fs, &seg); seg.sel = ctxt.gs_sel; seg.limit = ctxt.gs_limit; seg.base = ctxt.gs_base; seg.attr.bytes = ctxt.gs_arbytes; hvm_set_segment_register(v, x86_seg_gs, &seg); seg.sel = ctxt.tr_sel; seg.limit = ctxt.tr_limit; seg.base = ctxt.tr_base; seg.attr.bytes = ctxt.tr_arbytes; hvm_set_segment_register(v, x86_seg_tr, &seg); seg.sel = ctxt.ldtr_sel; seg.limit = ctxt.ldtr_limit; seg.base = ctxt.ldtr_base; seg.attr.bytes = ctxt.ldtr_arbytes; hvm_set_segment_register(v, x86_seg_ldtr, &seg); memcpy(&vc->fpu_ctxt, ctxt.fpu_regs, sizeof(ctxt.fpu_regs)); vc->user_regs.eax = ctxt.rax; vc->user_regs.ebx = ctxt.rbx; vc->user_regs.ecx = ctxt.rcx; vc->user_regs.edx = ctxt.rdx; vc->user_regs.ebp = ctxt.rbp; vc->user_regs.esi = ctxt.rsi; vc->user_regs.edi = ctxt.rdi; vc->user_regs.esp = ctxt.rsp; vc->user_regs.eip = ctxt.rip; vc->user_regs.eflags = ctxt.rflags | 2;#ifdef __x86_64__ vc->user_regs.r8 = ctxt.r8; vc->user_regs.r9 = ctxt.r9; vc->user_regs.r10 = ctxt.r10; vc->user_regs.r11 = ctxt.r11; vc->user_regs.r12 = ctxt.r12; vc->user_regs.r13 = ctxt.r13; vc->user_regs.r14 = ctxt.r14; vc->user_regs.r15 = ctxt.r15;#endif vc->debugreg[0] = ctxt.dr0; vc->debugreg[1] = ctxt.dr1; vc->debugreg[2] = ctxt.dr2; vc->debugreg[3] = ctxt.dr3; vc->debugreg[6] = ctxt.dr6; vc->debugreg[7] = ctxt.dr7; vc->flags = VGCF_online; v->fpu_initialised = 1; /* Auxiliary processors should be woken immediately. */ if ( test_and_clear_bit(_VPF_down, &v->pause_flags) ) vcpu_wake(v); return 0;}HVM_REGISTER_SAVE_RESTORE(CPU, hvm_save_cpu_ctxt, hvm_load_cpu_ctxt, 1, HVMSR_PER_VCPU);int hvm_vcpu_initialise(struct vcpu *v){ int rc; if ( (rc = vlapic_init(v)) != 0 ) goto fail1; if ( (rc = hvm_funcs.vcpu_initialise(v)) != 0 ) goto fail2; /* Create ioreq event channel. */ rc = alloc_unbound_xen_event_channel(v, 0); if ( rc < 0 ) goto fail3; /* Register ioreq event channel. */ v->arch.hvm_vcpu.xen_port = rc; spin_lock(&v->domain->arch.hvm_domain.ioreq.lock); if ( v->domain->arch.hvm_domain.ioreq.va != NULL ) get_ioreq(v)->vp_eport = v->arch.hvm_vcpu.xen_port; spin_unlock(&v->domain->arch.hvm_domain.ioreq.lock); spin_lock_init(&v->arch.hvm_vcpu.tm_lock); INIT_LIST_HEAD(&v->arch.hvm_vcpu.tm_list); rc = hvm_vcpu_cacheattr_init(v); if ( rc != 0 ) goto fail3; v->arch.guest_context.user_regs.eflags = 2; if ( v->vcpu_id == 0 ) { /* NB. All these really belong in hvm_domain_initialise(). */ pit_init(v, cpu_khz); pmtimer_init(v); hpet_init(v); /* Init guest TSC to start from zero. */ hvm_set_guest_tsc(v, 0); /* Can start up without SIPI-SIPI or setvcpucontext domctl. */ v->is_initialised = 1; clear_bit(_VPF_down, &v->pause_flags); } return 0; fail3: hvm_funcs.vcpu_destroy(v); fail2: vlapic_destroy(v); fail1: return rc;}void hvm_vcpu_destroy(struct vcpu *v){ hvm_vcpu_cacheattr_destroy(v); vlapic_destroy(v); hvm_funcs.vcpu_destroy(v); /* Event channel is already freed by evtchn_destroy(). */ /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/}void hvm_vcpu_down(struct vcpu *v){ struct domain *d = v->domain; int online_count = 0; /* Doesn't halt us immediately, but we'll never return to guest context. */ set_bit(_VPF_down, &v->pause_flags); vcpu_sleep_nosync(v); /* Any other VCPUs online? ... */ domain_lock(d); for_each_vcpu ( d, v ) if ( !test_bit(_VPF_down, &v->pause_flags) ) online_count++; domain_unlock(d); /* ... Shut down the domain if not. */ if ( online_count == 0 ) { gdprintk(XENLOG_INFO, "All CPUs offline -- powering off.\n"); domain_shutdown(d, SHUTDOWN_poweroff); }}void hvm_send_assist_req(struct vcpu *v){ ioreq_t *p; if ( unlikely(!vcpu_start_shutdown_deferral(v)) ) return; /* implicitly bins the i/o operation */ p = &get_ioreq(v)->vp_ioreq; if ( unlikely(p->state != STATE_IOREQ_NONE) ) { /* This indicates a bug in the device model. Crash the domain. */ gdprintk(XENLOG_ERR, "Device model set bad IO state %d.\n", p->state); domain_crash(v->domain); return; } prepare_wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port); /* * Following happens /after/ blocking and setting up ioreq contents. * prepare_wait_on_xen_event_channel() is an implicit barrier. */ p->state = STATE_IOREQ_READY; notify_via_xen_event_channel(v->arch.hvm_vcpu.xen_port);}void hvm_hlt(unsigned long rflags){ struct vcpu *curr = current; if ( hvm_event_pending(curr) ) return; /* * If we halt with interrupts disabled, that's a pretty sure sign that we * want to shut down. In a real processor, NMIs are the only way to break * out of this. */ if ( unlikely(!(rflags & X86_EFLAGS_IF)) ) return hvm_vcpu_down(curr); do_sched_op_compat(SCHEDOP_block, 0); HVMTRACE_1D(HLT, curr, /* pending = */ vcpu_runnable(curr));}void hvm_triple_fault(void){ struct vcpu *v = current; gdprintk(XENLOG_INFO, "Triple fault on VCPU%d - " "invoking HVM system reset.\n", v->vcpu_id); domain_shutdown(v->domain, SHUTDOWN_reboot);}int hvm_set_efer(uint64_t value){ struct vcpu *v = current; value &= ~EFER_LMA; if ( (value & ~(EFER_FFXSE | EFER_LME | EFER_NX | EFER_SCE)) || ((sizeof(long) != 8) && (value & EFER_LME)) || (!cpu_has_nx && (value & EFER_NX)) || (!cpu_has_syscall && (value & EFER_SCE)) || (!cpu_has_ffxsr && (value & EFER_FFXSE)) ) { gdprintk(XENLOG_WARNING, "Trying to set reserved bit in " "EFER: %"PRIx64"\n", value); hvm_inject_exception(TRAP_gp_fault, 0, 0); return X86EMUL_EXCEPTION; } if ( ((value ^ v->arch.hvm_vcpu.guest_efer) & EFER_LME) && hvm_paging_enabled(v) ) { gdprintk(XENLOG_WARNING, "Trying to change EFER.LME with paging enabled\n"); hvm_inject_exception(TRAP_gp_fault, 0, 0); return X86EMUL_EXCEPTION; } value |= v->arch.hvm_vcpu.guest_efer & EFER_LMA; v->arch.hvm_vcpu.guest_efer = value; hvm_update_guest_efer(v); return X86EMUL_OKAY;}extern void shadow_blow_tables_per_domain(struct domain *d);extern bool_t mtrr_pat_not_equal(struct vcpu *vd, struct vcpu *vs);/* Exit UC mode only if all VCPUs agree on MTRR/PAT and are not in no_fill. */static bool_t domain_exit_uc_mode(struct vcpu *v){ struct domain *d = v->domain; struct vcpu *vs; for_each_vcpu ( d, vs ) { if ( (vs == v) || !vs->is_initialised ) continue; if ( (vs->arch.hvm_vcpu.cache_mode == NO_FILL_CACHE_MODE) || mtrr_pat_not_equal(vs, v) ) return 0; } return 1;}static void local_flush_cache(void *info){ wbinvd();}static void hvm_set_uc_mode(struct vcpu *v, bool_t is_in_uc_mode){ v->domain->arch.hvm_domain.is_in_uc_mode = is_in_uc_mode; shadow_blow_tables_per_domain(v->domain); if ( hvm_funcs.set_uc_mode ) return hvm_funcs.set_uc_mode(v);}int hvm_set_cr0(unsigned long value){ struct vcpu *v = current; p2m_type_t p2mt; unsigned long gfn, mfn, old_value = v->arch.hvm_vcpu.guest_cr[0]; HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR0 value = %lx", value); if ( (u32)value != value ) { HVM_DBG_LOG(DBG_LEVEL_1, "Guest attempts to set upper 32 bits in CR0: %lx", value); goto gpf; } value &= ~HVM_CR0_GUEST_RESERVED_BITS; /* ET is reserved and should be always be 1. */ value |= X86_CR0_ET; if ( (value & (X86_CR0_PE | X86_CR0_PG)) == X86_CR0_PG ) goto gpf; if ( (value & X86_CR0_PG) && !(old_value & X86_CR0_PG) ) { if ( v->arch.hvm_vcpu.guest_efer & EFER_LME ) { if ( !(v->arch.hvm_vcpu.guest_cr[4] & X86_CR4_PAE) ) { HVM_DBG_LOG(DBG_LEVEL_1, "Enable paging before PAE enable"); goto gpf; } HVM_DBG_LOG(DBG_LEVEL_1, "Enabling long mode"); v->arch.hvm_vcpu.guest_efer |= EFER_LMA; hvm_update_guest_efer(v); } if ( !paging_mode_hap(v->domain) ) { /* The guest CR3 must be pointing to the guest physical. */ gfn = v->arch.hvm_vcpu.guest_cr[3]>>PAGE_SHIFT; mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt)); if ( !p2m_is_ram(p2mt) || !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain)) { gdprintk(XENLOG_ERR, "Invalid CR3 value = %lx (mfn=%lx)\n", v->arch.hvm_vcpu.guest_cr[3], mfn); domain_crash(v->domain); return X86EMUL_UNHANDLEABLE; } /* Now arch.guest_table points to machine physical. */ v->arch.guest_table = pagetable_from_pfn(mfn); HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx", v->arch.hvm_vcpu.guest_cr[3], mfn); } } else if ( !(value & X86_CR0_PG) && (old_value & X86_CR0_PG) ) { /* When CR0.PG is cleared, LMA is cleared immediately. */ if ( hvm_long_mode_enabled(v) ) { v->arch.hvm_vcpu.guest_efer &= ~EFER_LMA; hvm_update_guest_efer(v); } if ( !paging_mode_hap(v->domain) )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?