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 + -
显示快捷键?