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

[Xen-changelog] [xen-unstable] Add HVM hardware feature suspend/resume.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1184170989 -3600
# Node ID ad11f74d298c3afe7a5778b9fcf4f8a000a9d0eb
# Parent  24379dde8ac4b58389121c38ee56d46e7ea84b17
Add HVM hardware feature suspend/resume.
Signed-off-by: Ke Yu <ke.yu@xxxxxxxxx>
Signed-off-by: Kevin Tian <kevin.tian@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/acpi/power.c          |   33 ++++++++----
 xen/arch/x86/hvm/hvm.c             |    3 -
 xen/arch/x86/hvm/svm/svm.c         |    7 +-
 xen/arch/x86/hvm/vmx/vmcs.c        |  101 +++++++++++++++++++++++++++++--------
 xen/arch/x86/hvm/vmx/vmx.c         |   14 +----
 xen/include/asm-x86/hvm/hvm.h      |   20 +++++--
 xen/include/asm-x86/hvm/vmx/vmcs.h |    3 +
 7 files changed, 129 insertions(+), 52 deletions(-)

diff -r 24379dde8ac4 -r ad11f74d298c xen/arch/x86/acpi/power.c
--- a/xen/arch/x86/acpi/power.c Wed Jul 11 15:47:14 2007 +0100
+++ b/xen/arch/x86/acpi/power.c Wed Jul 11 17:23:09 2007 +0100
@@ -82,10 +82,27 @@ static void device_power_up(void)
     console_resume();
 }
 
+static void freeze_domains(void)
+{
+    struct domain *d;
+
+    for_each_domain(d)
+        if (d->domain_id != 0)
+            domain_pause(d);
+}
+
+static void thaw_domains(void)
+{
+    struct domain *d;
+
+    for_each_domain(d)
+        if (d->domain_id != 0)
+            domain_unpause(d);
+}
+
 /* Main interface to do xen specific suspend/resume */
 int enter_state(u32 state)
 {
-    struct domain *d;
     unsigned long flags;
     int error;
 
@@ -99,9 +116,9 @@ int enter_state(u32 state)
     if (!spin_trylock(&pm_lock))
         return -EBUSY;
     
-    for_each_domain(d)
-        if (d->domain_id != 0)
-            domain_pause(d);
+    freeze_domains();
+
+    hvm_suspend_cpu();
 
     pmprintk(XENLOG_INFO, "PM: Preparing system for %s sleep\n",
         acpi_states[state]);
@@ -135,13 +152,11 @@ int enter_state(u32 state)
  Done:
     local_irq_restore(flags);
 
-    for_each_domain(d)
-       if (d->domain_id!=0)
-           domain_unpause(d);
-
+    hvm_resume_cpu();
+
+    thaw_domains();
     spin_unlock(&pm_lock);
     return error;
-
 }
 
 /*
diff -r 24379dde8ac4 -r ad11f74d298c xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Jul 11 15:47:14 2007 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Wed Jul 11 17:23:09 2007 +0100
@@ -78,8 +78,7 @@ void hvm_enable(struct hvm_function_tabl
 
 void hvm_disable(void)
 {
-    if ( hvm_enabled )
-        hvm_funcs.disable();
+    hvm_suspend_cpu();
 }
 
 void hvm_stts(struct vcpu *v)
diff -r 24379dde8ac4 -r ad11f74d298c xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Jul 11 15:47:14 2007 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed Jul 11 17:23:09 2007 +0100
@@ -94,9 +94,8 @@ static void svm_inject_exception(struct 
     vmcb->eventinj = event;
 }
 
-static void stop_svm(void)
-{
-    /* We turn off the EFER_SVME bit. */
+static void svm_suspend_cpu(void)
+{
     write_efer(read_efer() & ~EFER_SVME);
 }
 
@@ -974,7 +973,7 @@ static int svm_event_injection_faulted(s
 
 static struct hvm_function_table svm_function_table = {
     .name                 = "SVM",
-    .disable              = stop_svm,
+    .suspend_cpu          = svm_suspend_cpu,
     .domain_initialise    = svm_domain_initialise,
     .domain_destroy       = svm_domain_destroy,
     .vcpu_initialise      = svm_vcpu_initialise,
diff -r 24379dde8ac4 -r ad11f74d298c xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c       Wed Jul 11 15:47:14 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmcs.c       Wed Jul 11 17:23:09 2007 +0100
@@ -45,7 +45,9 @@ u32 vmx_vmentry_control __read_mostly;
 u32 vmx_vmentry_control __read_mostly;
 bool_t cpu_has_vmx_ins_outs_instr_info __read_mostly;
 
+static DEFINE_PER_CPU(struct vmcs_struct *, host_vmcs);
 static DEFINE_PER_CPU(struct vmcs_struct *, current_vmcs);
+static DEFINE_PER_CPU(struct list_head, active_vmcs_list);
 
 static u32 vmcs_revision_id __read_mostly;
 
@@ -185,34 +187,81 @@ static void __vmx_clear_vmcs(void *info)
 static void __vmx_clear_vmcs(void *info)
 {
     struct vcpu *v = info;
-
-    __vmpclear(virt_to_maddr(v->arch.hvm_vmx.vmcs));
-
-    v->arch.hvm_vmx.active_cpu = -1;
-    v->arch.hvm_vmx.launched   = 0;
-
-    if ( v->arch.hvm_vmx.vmcs == this_cpu(current_vmcs) )
-        this_cpu(current_vmcs) = NULL;
+    struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
+
+    /* Otherwise we can nest (vmx_suspend_cpu() vs. vmx_clear_vmcs()). */
+    ASSERT(!local_irq_is_enabled());
+
+    if ( arch_vmx->active_cpu == smp_processor_id() )
+    {
+        __vmpclear(virt_to_maddr(arch_vmx->vmcs));
+
+        arch_vmx->active_cpu = -1;
+        arch_vmx->launched   = 0;
+
+        list_del(&arch_vmx->active_list);
+
+        if ( arch_vmx->vmcs == this_cpu(current_vmcs) )
+            this_cpu(current_vmcs) = NULL;
+    }
 }
 
 static void vmx_clear_vmcs(struct vcpu *v)
 {
     int cpu = v->arch.hvm_vmx.active_cpu;
 
-    if ( cpu == -1 )
-        return;
-
-    if ( cpu == smp_processor_id() )
-        return __vmx_clear_vmcs(v);
-
-    on_selected_cpus(cpumask_of_cpu(cpu), __vmx_clear_vmcs, v, 1, 1);
+    if ( cpu != -1 )
+        on_selected_cpus(cpumask_of_cpu(cpu), __vmx_clear_vmcs, v, 1, 1);
 }
 
 static void vmx_load_vmcs(struct vcpu *v)
 {
+    unsigned long flags;
+
+    local_irq_save(flags);
+
+    if ( v->arch.hvm_vmx.active_cpu == -1 )
+    {
+        list_add(&v->arch.hvm_vmx.active_list, &this_cpu(active_vmcs_list));
+        v->arch.hvm_vmx.active_cpu = smp_processor_id();
+    }
+
+    ASSERT(v->arch.hvm_vmx.active_cpu == smp_processor_id());
+
     __vmptrld(virt_to_maddr(v->arch.hvm_vmx.vmcs));
-    v->arch.hvm_vmx.active_cpu = smp_processor_id();
     this_cpu(current_vmcs) = v->arch.hvm_vmx.vmcs;
+
+    local_irq_restore(flags);
+}
+
+void vmx_suspend_cpu(void)
+{
+    struct list_head *active_vmcs_list = &this_cpu(active_vmcs_list);
+    unsigned long flags;
+
+    local_irq_save(flags);
+
+    while ( !list_empty(active_vmcs_list) )
+        __vmx_clear_vmcs(list_entry(active_vmcs_list->next,
+                                    struct vcpu, arch.hvm_vmx.active_list));
+
+    if ( read_cr4() & X86_CR4_VMXE )
+    {
+        __vmxoff();
+        clear_in_cr4(X86_CR4_VMXE);
+    }
+
+    local_irq_restore(flags);
+}
+
+void vmx_resume_cpu(void)
+{
+    if ( !read_cr4() & X86_CR4_VMXE )
+    {
+        set_in_cr4(X86_CR4_VMXE);
+        if ( __vmxon(virt_to_maddr(this_cpu(host_vmcs))) )
+            BUG();
+    }
 }
 
 void vmx_vmcs_enter(struct vcpu *v)
@@ -247,12 +296,17 @@ void vmx_vmcs_exit(struct vcpu *v)
 
 struct vmcs_struct *vmx_alloc_host_vmcs(void)
 {
-    return vmx_alloc_vmcs();
+    ASSERT(this_cpu(host_vmcs) == NULL);
+    this_cpu(host_vmcs) = vmx_alloc_vmcs();
+    INIT_LIST_HEAD(&this_cpu(active_vmcs_list));
+    return this_cpu(host_vmcs);
 }
 
 void vmx_free_host_vmcs(struct vmcs_struct *vmcs)
 {
+    ASSERT(vmcs == this_cpu(host_vmcs));
     vmx_free_vmcs(vmcs);
+    this_cpu(host_vmcs) = NULL;
 }
 
 struct xgt_desc {
@@ -451,12 +505,17 @@ static void construct_vmcs(struct vcpu *
 
 int vmx_create_vmcs(struct vcpu *v)
 {
-    if ( v->arch.hvm_vmx.vmcs == NULL )
-    {
-        if ( (v->arch.hvm_vmx.vmcs = vmx_alloc_vmcs()) == NULL )
+    struct arch_vmx_struct *arch_vmx = &v->arch.hvm_vmx;
+
+    if ( arch_vmx->vmcs == NULL )
+    {
+        if ( (arch_vmx->vmcs = vmx_alloc_vmcs()) == NULL )
             return -ENOMEM;
 
-        __vmx_clear_vmcs(v);
+        INIT_LIST_HEAD(&arch_vmx->active_list);
+        __vmpclear(virt_to_maddr(arch_vmx->vmcs));
+        arch_vmx->active_cpu = -1;
+        arch_vmx->launched   = 0;
     }
 
     construct_vmcs(v);
diff -r 24379dde8ac4 -r ad11f74d298c xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Wed Jul 11 15:47:14 2007 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Wed Jul 11 17:23:09 2007 +0100
@@ -907,15 +907,6 @@ static void vmx_ctxt_switch_to(struct vc
     vmx_restore_dr(v);
 }
 
-static void stop_vmx(void)
-{
-    if ( !(read_cr4() & X86_CR4_VMXE) )
-        return;
-
-    __vmxoff();
-    clear_in_cr4(X86_CR4_VMXE);
-}
-
 static void vmx_store_cpu_guest_regs(
     struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs)
 {
@@ -1244,7 +1235,6 @@ static void disable_intercept_for_msr(u3
 
 static struct hvm_function_table vmx_function_table = {
     .name                 = "VMX",
-    .disable              = stop_vmx,
     .domain_initialise    = vmx_domain_initialise,
     .domain_destroy       = vmx_domain_destroy,
     .vcpu_initialise      = vmx_vcpu_initialise,
@@ -1271,7 +1261,9 @@ static struct hvm_function_table vmx_fun
     .inject_exception     = vmx_inject_exception,
     .init_ap_context      = vmx_init_ap_context,
     .init_hypercall_page  = vmx_init_hypercall_page,
-    .event_injection_faulted = vmx_event_injection_faulted
+    .event_injection_faulted = vmx_event_injection_faulted,
+    .suspend_cpu          = vmx_suspend_cpu,
+    .resume_cpu           = vmx_resume_cpu,
 };
 
 int start_vmx(void)
diff -r 24379dde8ac4 -r ad11f74d298c xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h     Wed Jul 11 15:47:14 2007 +0100
+++ b/xen/include/asm-x86/hvm/hvm.h     Wed Jul 11 17:23:09 2007 +0100
@@ -72,11 +72,6 @@ struct hvm_function_table {
     char *name;
 
     /*
-     *  Disable HVM functionality
-     */
-    void (*disable)(void);
-
-    /*
      * Initialise/destroy HVM domain/vcpu resources
      */
     int  (*domain_initialise)(struct domain *d);
@@ -160,6 +155,9 @@ struct hvm_function_table {
     void (*init_hypercall_page)(struct domain *d, void *hypercall_page);
 
     int  (*event_injection_faulted)(struct vcpu *v);
+
+    void (*suspend_cpu)(void);
+    void (*resume_cpu)(void);
 };
 
 extern struct hvm_function_table hvm_funcs;
@@ -316,4 +314,16 @@ static inline int hvm_event_injection_fa
 /* These exceptions must always be intercepted. */
 #define HVM_TRAP_MASK (1U << TRAP_machine_check)
 
+static inline void hvm_suspend_cpu(void)
+{
+    if ( hvm_funcs.suspend_cpu )
+        hvm_funcs.suspend_cpu();
+}
+
+static inline void hvm_resume_cpu(void)
+{
+    if ( hvm_funcs.resume_cpu )
+        hvm_funcs.resume_cpu();
+}
+
 #endif /* __ASM_X86_HVM_HVM_H__ */
diff -r 24379dde8ac4 -r ad11f74d298c xen/include/asm-x86/hvm/vmx/vmcs.h
--- a/xen/include/asm-x86/hvm/vmx/vmcs.h        Wed Jul 11 15:47:14 2007 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmcs.h        Wed Jul 11 17:23:09 2007 +0100
@@ -28,6 +28,8 @@ extern void vmcs_dump_vcpu(void);
 extern void vmcs_dump_vcpu(void);
 extern void vmx_init_vmcs_config(void);
 extern void setup_vmcs_dump(void);
+extern void vmx_suspend_cpu(void);
+extern void vmx_resume_cpu(void);
 
 struct vmcs_struct {
     u32 vmcs_revision_id;
@@ -59,6 +61,7 @@ struct arch_vmx_struct {
      *  - Activated on a CPU by VMPTRLD. Deactivated by VMCLEAR.
      *  - Launched on active CPU by VMLAUNCH when current VMCS.
      */
+    struct list_head     active_list;
     int                  active_cpu;
     int                  launched;
 

_______________________________________________
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®.