[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [HVM][SVM] Add save/restore support.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1169663407 0
# Node ID e75107963846bf053f270deb921b36e57860102a
# Parent  bc7363b9b8921b477479db5d8b7d5e50886269e2
[HVM][SVM] Add save/restore support.
From: Mats Petersson <Mats.Petersson@xxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/hvm/svm/svm.c |  277 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 277 insertions(+)

diff -r bc7363b9b892 -r e75107963846 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Jan 24 18:23:23 2007 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed Jan 24 18:30:07 2007 +0000
@@ -361,6 +361,280 @@ static inline void __restore_debug_regis
 }
 
 
+int svm_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
+{
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+    c->eip = vmcb->rip;
+
+#ifdef HVM_DEBUG_SUSPEND
+    printk("%s: eip=0x%"PRIx64".\n", 
+           __func__,
+           inst_len, c->eip);
+#endif
+
+    c->esp = vmcb->rsp;
+    c->eflags = vmcb->rflags;
+
+    c->cr0 = v->arch.hvm_svm.cpu_shadow_cr0;
+    c->cr3 = v->arch.hvm_svm.cpu_cr3;
+    c->cr4 = v->arch.hvm_svm.cpu_shadow_cr4;
+
+#ifdef HVM_DEBUG_SUSPEND
+    printk("%s: cr3=0x%"PRIx64", cr0=0x%"PRIx64", cr4=0x%"PRIx64".\n",
+           __func__,
+           c->cr3,
+           c->cr0,
+           c->cr4);
+#endif
+
+    c->idtr_limit = vmcb->idtr.limit;
+    c->idtr_base  = vmcb->idtr.base;
+
+    c->gdtr_limit = vmcb->gdtr.limit;
+    c->gdtr_base  = vmcb->gdtr.base; 
+
+    c->cs_sel = vmcb->cs.sel;
+    c->cs_limit = vmcb->cs.limit;
+    c->cs_base = vmcb->cs.base;
+    c->cs_arbytes = vmcb->cs.attr.bytes;
+
+    c->ds_sel = vmcb->ds.sel;
+    c->ds_limit = vmcb->ds.limit;
+    c->ds_base = vmcb->ds.base;
+    c->ds_arbytes = vmcb->ds.attr.bytes;
+
+    c->es_sel = vmcb->es.sel;
+    c->es_limit = vmcb->es.limit;
+    c->es_base = vmcb->es.base;
+    c->es_arbytes = vmcb->es.attr.bytes;
+
+    c->ss_sel = vmcb->ss.sel;
+    c->ss_limit = vmcb->ss.limit;
+    c->ss_base = vmcb->ss.base;
+    c->ss_arbytes = vmcb->ss.attr.bytes;
+
+    c->fs_sel = vmcb->fs.sel;
+    c->fs_limit = vmcb->fs.limit;
+    c->fs_base = vmcb->fs.base;
+    c->fs_arbytes = vmcb->fs.attr.bytes;
+
+    c->gs_sel = vmcb->gs.sel;
+    c->gs_limit = vmcb->gs.limit;
+    c->gs_base = vmcb->gs.base;
+    c->gs_arbytes = vmcb->gs.attr.bytes;
+
+    c->tr_sel = vmcb->tr.sel;
+    c->tr_limit = vmcb->tr.limit;
+    c->tr_base = vmcb->tr.base;
+    c->tr_arbytes = vmcb->tr.attr.bytes;
+
+    c->ldtr_sel = vmcb->ldtr.sel;
+    c->ldtr_limit = vmcb->ldtr.limit;
+    c->ldtr_base = vmcb->ldtr.base;
+    c->ldtr_arbytes = vmcb->ldtr.attr.bytes;
+
+    c->sysenter_cs = vmcb->sysenter_cs;
+    c->sysenter_esp = vmcb->sysenter_esp;
+    c->sysenter_eip = vmcb->sysenter_eip;
+
+    return 1;
+}
+
+
+int svm_vmcb_restore(struct vcpu *v, struct hvm_hw_cpu *c)
+{
+    unsigned long mfn, old_base_mfn;
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+    vmcb->rip    = c->eip;
+    vmcb->rsp    = c->esp;
+    vmcb->rflags = c->eflags;
+
+    v->arch.hvm_svm.cpu_shadow_cr0 = c->cr0;
+
+#ifdef HVM_DEBUG_SUSPEND
+    printk("%s: cr3=0x%"PRIx64", cr0=0x%"PRIx64", cr4=0x%"PRIx64".\n",
+           __func__,
+            c->cr3,
+            c->cr0,
+            c->cr4);
+#endif
+
+    if (!svm_paging_enabled(v)) {
+        printk("%s: paging not enabled.", __func__);
+        goto skip_cr3;
+    }
+
+    if (c->cr3 == v->arch.hvm_svm.cpu_cr3) {
+        /*
+         * This is simple TLB flush, implying the guest has
+         * removed some translation or changed page attributes.
+         * We simply invalidate the shadow.
+         */
+        mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT);
+        if (mfn != pagetable_get_pfn(v->arch.guest_table)) {
+            goto bad_cr3;
+        }
+    } else {
+        /*
+         * If different, make a shadow. Check if the PDBR is valid
+         * first.
+         */
+        HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 c->cr3 = %"PRIx64"", c->cr3);
+        /* current!=vcpu as not called by arch_vmx_do_launch */
+        mfn = gmfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT);
+        if( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), v->domain)) {
+            goto bad_cr3;
+        }
+        old_base_mfn = pagetable_get_pfn(v->arch.guest_table);
+        v->arch.guest_table = pagetable_from_pfn(mfn);
+        if (old_base_mfn)
+             put_page(mfn_to_page(old_base_mfn));
+        /*
+         * arch.shadow_table should now hold the next CR3 for shadow
+         */
+        v->arch.hvm_svm.cpu_cr3 = c->cr3;
+    }
+
+ skip_cr3:
+#if defined(__x86_64__) && 0
+    if (vmx_long_mode_enabled(v)) {
+        unsigned long vm_entry_value;
+        vm_entry_value = __vmread(VM_ENTRY_CONTROLS);
+        vm_entry_value |= VM_ENTRY_IA32E_MODE;
+        __vmwrite(VM_ENTRY_CONTROLS, vm_entry_value);
+    }
+#endif
+
+    vmcb->cr4 = c->cr4 | SVM_CR4_HOST_MASK;
+    v->arch.hvm_svm.cpu_shadow_cr4 = c->cr4;
+    
+    vmcb->idtr.limit = c->idtr_limit;
+    vmcb->idtr.base  = c->idtr_base;
+
+    vmcb->gdtr.limit = c->gdtr_limit;
+    vmcb->gdtr.base  = c->gdtr_base;
+
+    vmcb->cs.sel        = c->cs_sel;
+    vmcb->cs.limit      = c->cs_limit;
+    vmcb->cs.base       = c->cs_base;
+    vmcb->cs.attr.bytes = c->cs_arbytes;
+
+    vmcb->ds.sel        = c->ds_sel;
+    vmcb->ds.limit      = c->ds_limit;
+    vmcb->ds.base       = c->ds_base;
+    vmcb->ds.attr.bytes = c->ds_arbytes;
+
+    vmcb->es.sel        = c->es_sel;
+    vmcb->es.limit      = c->es_limit;
+    vmcb->es.base       = c->es_base;
+    vmcb->es.attr.bytes = c->es_arbytes;
+
+    vmcb->ss.sel        = c->ss_sel;
+    vmcb->ss.limit      = c->ss_limit;
+    vmcb->ss.base       = c->ss_base;
+    vmcb->ss.attr.bytes = c->ss_arbytes;
+
+    vmcb->fs.sel        = c->fs_sel;
+    vmcb->fs.limit      = c->fs_limit;
+    vmcb->fs.base       = c->fs_base;
+    vmcb->fs.attr.bytes = c->fs_arbytes;
+
+    vmcb->gs.sel        = c->gs_sel;
+    vmcb->gs.limit      = c->gs_limit;
+    vmcb->gs.base       = c->gs_base;
+    vmcb->gs.attr.bytes = c->gs_arbytes;
+
+    vmcb->tr.sel        = c->tr_sel;
+    vmcb->tr.limit      = c->tr_limit;
+    vmcb->tr.base       = c->tr_base;
+    vmcb->tr.attr.bytes = c->tr_arbytes;
+
+    vmcb->ldtr.sel        = c->ldtr_sel;
+    vmcb->ldtr.limit      = c->ldtr_limit;
+    vmcb->ldtr.base       = c->ldtr_base;
+    vmcb->ldtr.attr.bytes = c->ldtr_arbytes;
+
+    vmcb->sysenter_cs =  c->sysenter_cs;
+    vmcb->sysenter_esp = c->sysenter_esp;
+    vmcb->sysenter_eip = c->sysenter_eip;
+
+    shadow_update_paging_modes(v);
+    return 0;
+ 
+ bad_cr3:
+    gdprintk(XENLOG_ERR, "Invalid CR3 value=0x%"PRIx64"", c->cr3);
+    return -EINVAL;
+}
+
+        
+void svm_save_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
+{
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+    data->shadow_gs = vmcb->kerngsbase;
+    /* MSR_LSTAR, MSR_STAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_EFER */    
+    data->msr_items[0] = vmcb->lstar;
+    data->msr_items[1] = vmcb->star;
+    data->msr_items[2] = vmcb->cstar;
+    data->msr_items[3] = vmcb->sfmask;
+    data->msr_items[4] = vmcb->efer;
+
+    data->tsc = hvm_get_guest_time(v);
+
+    // dump_msr_state(guest_state);
+}
+
+
+void svm_load_cpu_state(struct vcpu *v, struct hvm_hw_cpu *data)
+{
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+
+    /* MSR_LSTAR, MSR_STAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_EFER */
+    vmcb->lstar  = data->msr_items[0];
+    vmcb->star   = data->msr_items[1];
+    vmcb->cstar  = data->msr_items[2];
+    vmcb->sfmask = data->msr_items[3];
+    vmcb->efer   = data->msr_items[4];
+
+    hvm_set_guest_time(v, data->tsc);
+
+    // dump_msr_state(guest_state);
+}
+
+void svm_save_vmcb_ctxt(hvm_domain_context_t *h, void *opaque)
+{
+    struct vcpu *v = opaque;
+    struct hvm_hw_cpu ctxt;
+
+    svm_save_cpu_state(v, &ctxt);
+
+    svm_vmcs_save(v, &ctxt);
+
+    hvm_put_struct(h, &ctxt);
+}
+
+int svm_load_vmcb_ctxt(hvm_domain_context_t *h, void *opaque, int version)
+{
+    struct vcpu *v = opaque;
+    struct hvm_hw_cpu ctxt;
+
+    if (version != 1)
+        return -EINVAL;
+
+    hvm_get_struct(h, &ctxt);
+    svm_load_cpu_state(v, &ctxt);
+    if (svm_vmcb_restore(v, &ctxt)) {
+        printk("svm_vmcb restore failed!\n");
+        domain_crash(v->domain);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+
 static inline void svm_restore_dr(struct vcpu *v)
 {
     if ( unlikely(v->arch.guest_context.debugreg[7] & 0xFF) )
@@ -772,6 +1046,9 @@ int start_svm(void)
 
     hvm_funcs.store_cpu_guest_regs = svm_store_cpu_guest_regs;
     hvm_funcs.load_cpu_guest_regs = svm_load_cpu_guest_regs;
+
+    hvm_funcs.save_cpu_ctxt = svm_save_vmcb_ctxt;
+    hvm_funcs.load_cpu_ctxt = svm_load_vmcb_ctxt;
 
     hvm_funcs.paging_enabled = svm_paging_enabled;
     hvm_funcs.long_mode_enabled = svm_long_mode_enabled;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.