[XEN] Support VCPU reset via DOMCTL_setvcpucontext.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 19 Jan 2007 17:55:29 +0000 (17:55 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 19 Jan 2007 17:55:29 +0000 (17:55 +0000)
Signed-off-by: Andrei Petrov <andrei.petrov@xensource.com>
tools/libxc/xc_domain.c
xen/arch/x86/domain.c
xen/common/domain.c
xen/include/xen/compat.h
xen/include/xen/domain.h

index 98e909d0a3d4102e13a7c3f4c3b810e5b2dec416..995b877ac02f27357ace117febe3df4f796098c8 100644 (file)
@@ -602,12 +602,13 @@ int xc_vcpu_setcontext(int xc_handle,
     domctl.u.vcpucontext.vcpu = vcpu;
     set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt);
 
-    if ( (rc = lock_pages(ctxt, sizeof(*ctxt))) != 0 )
+    if ( (ctxt != NULL) && ((rc = lock_pages(ctxt, sizeof(*ctxt))) != 0) )
         return rc;
 
     rc = do_domctl(xc_handle, &domctl);
 
-    unlock_pages(ctxt, sizeof(*ctxt));
+    if ( ctxt != NULL )
+        unlock_pages(ctxt, sizeof(*ctxt));
 
     return rc;
 
index e23c85bbaa90a2905ef860a20eb2210caca9c8bd..5d3899df648c23da7c09e3d6c2e58d6525a7af74 100644 (file)
@@ -50,6 +50,8 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
 static void paravirt_ctxt_switch_from(struct vcpu *v);
 static void paravirt_ctxt_switch_to(struct vcpu *v);
 
+static void vcpu_destroy_pagetables(struct vcpu *v);
+
 static void continue_idle_domain(struct vcpu *v)
 {
     reset_stack_and_jump(idle_loop);
@@ -658,6 +660,13 @@ int arch_set_info_guest(
 #undef c
 }
 
+int arch_vcpu_reset(struct vcpu *v)
+{
+    destroy_gdt(v);
+    vcpu_destroy_pagetables(v);
+    return 0;
+}
+
 long
 arch_do_vcpu_op(
     int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg)
@@ -1380,63 +1389,73 @@ static void relinquish_memory(struct domain *d, struct list_head *list)
     spin_unlock_recursive(&d->page_alloc_lock);
 }
 
-void domain_relinquish_resources(struct domain *d)
+static void vcpu_destroy_pagetables(struct vcpu *v)
 {
-    struct vcpu *v;
+    struct domain *d = v->domain;
     unsigned long pfn;
 
-    BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
-
-    /* Drop the in-use references to page-table bases. */
-    for_each_vcpu ( d, v )
-    {
-        /* Drop ref to guest_table (from new_guest_cr3(), svm/vmx cr3 handling,
-         * or sh_update_paging_modes()) */
 #ifdef CONFIG_COMPAT
-        if ( IS_COMPAT(d) )
-        {
-            if ( is_hvm_vcpu(v) )
-                pfn = pagetable_get_pfn(v->arch.guest_table);
-            else
-                pfn = l4e_get_pfn(*(l4_pgentry_t *)__va(pagetable_get_paddr(v->arch.guest_table)));
+    if ( IS_COMPAT(d) )
+    {
+        if ( is_hvm_vcpu(v) )
+            pfn = pagetable_get_pfn(v->arch.guest_table);
+        else
+            pfn = l4e_get_pfn(*(l4_pgentry_t *)
+                              __va(pagetable_get_paddr(v->arch.guest_table)));
 
-            if ( pfn != 0 )
-            {
-                if ( shadow_mode_refcounts(d) )
-                    put_page(mfn_to_page(pfn));
-                else
-                    put_page_and_type(mfn_to_page(pfn));
-            }
-            continue;
-        }
-#endif
-        pfn = pagetable_get_pfn(v->arch.guest_table);
         if ( pfn != 0 )
         {
             if ( shadow_mode_refcounts(d) )
                 put_page(mfn_to_page(pfn));
             else
                 put_page_and_type(mfn_to_page(pfn));
-#ifdef __x86_64__
-            if ( pfn == pagetable_get_pfn(v->arch.guest_table_user) )
-                v->arch.guest_table_user = pagetable_null();
-#endif
-            v->arch.guest_table = pagetable_null();
         }
 
+        v->arch.guest_table = pagetable_null();
+        v->arch.cr3 = 0;
+        return;
+    }
+#endif
+
+    pfn = pagetable_get_pfn(v->arch.guest_table);
+    if ( pfn != 0 )
+    {
+        if ( shadow_mode_refcounts(d) )
+            put_page(mfn_to_page(pfn));
+        else
+            put_page_and_type(mfn_to_page(pfn));
 #ifdef __x86_64__
-        /* Drop ref to guest_table_user (from MMUEXT_NEW_USER_BASEPTR) */
-        pfn = pagetable_get_pfn(v->arch.guest_table_user);
-        if ( pfn != 0 )
-        {
-            if ( shadow_mode_refcounts(d) )
-                put_page(mfn_to_page(pfn));
-            else
-                put_page_and_type(mfn_to_page(pfn));
+        if ( pfn == pagetable_get_pfn(v->arch.guest_table_user) )
             v->arch.guest_table_user = pagetable_null();
-        }
 #endif
+        v->arch.guest_table = pagetable_null();
+    }
+
+#ifdef __x86_64__
+    /* Drop ref to guest_table_user (from MMUEXT_NEW_USER_BASEPTR) */
+    pfn = pagetable_get_pfn(v->arch.guest_table_user);
+    if ( pfn != 0 )
+    {
+        if ( shadow_mode_refcounts(d) )
+            put_page(mfn_to_page(pfn));
+        else
+            put_page_and_type(mfn_to_page(pfn));
+        v->arch.guest_table_user = pagetable_null();
     }
+#endif
+
+    v->arch.cr3 = 0;
+}
+
+void domain_relinquish_resources(struct domain *d)
+{
+    struct vcpu *v;
+
+    BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
+
+    /* Drop the in-use references to page-table bases. */
+    for_each_vcpu ( d, v )
+        vcpu_destroy_pagetables(v);
 
     /* Tear down shadow mode stuff. */
     shadow_teardown(d);
index aa232585c8a24b467dd092d25e556cc7b2605423..9203e837a7ef47b54658b486a7ceba0e1846374f 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <xen/config.h>
+#include <xen/compat.h>
 #include <xen/init.h>
 #include <xen/lib.h>
 #include <xen/errno.h>
@@ -467,7 +468,12 @@ int set_info_guest(struct domain *d,
 
     if ( (vcpu >= MAX_VIRT_CPUS) || ((v = d->vcpu[vcpu]) == NULL) )
         return -EINVAL;
-    
+
+    if ( IS_COMPAT(v->domain)
+         ? compat_handle_is_null(vcpucontext.cmp->ctxt)
+         : guest_handle_is_null(vcpucontext.nat->ctxt) )
+        return vcpu_reset(v);
+
 #ifdef CONFIG_COMPAT
     BUILD_BUG_ON(sizeof(struct vcpu_guest_context)
                  < sizeof(struct compat_vcpu_guest_context));
@@ -521,6 +527,36 @@ int boot_vcpu(struct domain *d, int vcpuid, vcpu_guest_context_u ctxt)
     return arch_set_info_guest(v, ctxt);
 }
 
+int vcpu_reset(struct vcpu *v)
+{
+    struct domain *d = v->domain;
+    int rc;
+
+    domain_pause(d);
+    LOCK_BIGLOCK(d);
+
+    rc = arch_vcpu_reset(v);
+    if ( rc != 0 )
+        goto out;
+
+    set_bit(_VCPUF_down, &v->vcpu_flags);
+
+    clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
+    clear_bit(_VCPUF_fpu_dirtied, &v->vcpu_flags);
+    clear_bit(_VCPUF_blocked, &v->vcpu_flags);
+    clear_bit(_VCPUF_initialised, &v->vcpu_flags);
+    clear_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
+    clear_bit(_VCPUF_nmi_masked, &v->vcpu_flags);
+    clear_bit(_VCPUF_polling, &v->vcpu_flags);
+
+ out:
+    UNLOCK_BIGLOCK(v->domain);
+    domain_unpause(d);
+
+    return rc;
+}
+
+
 long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
 {
     struct domain *d = current->domain;
index 06771a1c23cbace76b6f437b6b503af9c373fc23..ba992e526a227b4f4a05b5d77e617b30ea8d7fbd 100644 (file)
@@ -173,6 +173,8 @@ int switch_native(struct domain *);
 
 #else
 
+#define compat_handle_is_null(hnd) 0
+
 #define BITS_PER_GUEST_LONG(d) BITS_PER_LONG
 
 #endif
index 26b2047f5a041fef67c29e7bd2eb0a8d00c0fbac..9c7c203eb070169a5037780971c319ef16fc0d7a 100644 (file)
@@ -12,6 +12,7 @@ struct vcpu *alloc_vcpu(
 int boot_vcpu(
     struct domain *d, int vcpuid, vcpu_guest_context_u ctxt);
 struct vcpu *alloc_idle_vcpu(unsigned int cpu_id);
+int vcpu_reset(struct vcpu *v);
 
 struct domain *alloc_domain(domid_t domid);
 void free_domain(struct domain *d);
@@ -56,4 +57,6 @@ void arch_dump_vcpu_info(struct vcpu *v);
 
 void arch_dump_domain_info(struct domain *d);
 
+int arch_vcpu_reset(struct vcpu *v);
+
 #endif /* __XEN_DOMAIN_H__ */