]> xenbits.xensource.com Git - xen.git/commitdiff
x86: introduce alloc_vcpu_guest_context()
authorJan Beulich <jbeulich@novell.com>
Tue, 5 Apr 2011 12:03:29 +0000 (13:03 +0100)
committerJan Beulich <jbeulich@novell.com>
Tue, 5 Apr 2011 12:03:29 +0000 (13:03 +0100)
This is necessary because on x86-64 struct vcpu_guest_context is
larger than PAGE_SIZE, and hence not suitable for a general purpose
runtime allocation. On x86-32, FIX_PAE_HIGHMEM_* fixmap entries are
being re-used, whiule on x86-64 new per-CPU fixmap entries get
introduced.  The implication of using per-CPU fixmaps is that these
allocations have to happen from non-preemptable hypercall context
(which they all do).

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/domain.c
xen/common/domain.c
xen/common/domctl.c
xen/include/asm-ia64/domain.h
xen/include/asm-x86/fixmap.h
xen/include/xen/domain.h

index 10844570a360173c799890aece3e2b3ee242ff1d..8d24dbccdcc135d3b5142447b40e80635d27528c 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/mpspec.h>
 #include <asm/ldt.h>
 #include <asm/hypercall.h>
+#include <asm/fixmap.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
 #include <asm/debugreg.h>
@@ -221,6 +222,53 @@ void free_vcpu_struct(struct vcpu *v)
     free_xenheap_page(v);
 }
 
+static DEFINE_PER_CPU(struct page_info *[
+    PFN_UP(sizeof(struct vcpu_guest_context))], vgc_pages);
+
+struct vcpu_guest_context *alloc_vcpu_guest_context(void)
+{
+    unsigned int i, cpu = smp_processor_id();
+    enum fixed_addresses idx = FIX_VGC_BEGIN -
+        cpu * PFN_UP(sizeof(struct vcpu_guest_context));
+
+#ifdef __i386__
+    BUILD_BUG_ON(sizeof(struct vcpu_guest_context) > PAGE_SIZE);
+#endif
+    BUG_ON(per_cpu(vgc_pages[0], cpu) != NULL);
+
+    for ( i = 0; i < PFN_UP(sizeof(struct vcpu_guest_context)); ++i )
+    {
+        struct page_info *pg = alloc_domheap_page(NULL, 0);
+
+        if ( unlikely(pg == NULL) )
+        {
+            free_vcpu_guest_context(NULL);
+            return NULL;
+        }
+        __set_fixmap(idx - i, page_to_mfn(pg), __PAGE_HYPERVISOR);
+        per_cpu(vgc_pages[i], cpu) = pg;
+    }
+    return (void *)fix_to_virt(idx);
+}
+
+void free_vcpu_guest_context(struct vcpu_guest_context *vgc)
+{
+    unsigned int i, cpu = smp_processor_id();
+    enum fixed_addresses idx = FIX_VGC_BEGIN -
+        cpu * PFN_UP(sizeof(struct vcpu_guest_context));
+
+    BUG_ON(vgc && vgc != (void *)fix_to_virt(idx));
+
+    for ( i = 0; i < PFN_UP(sizeof(struct vcpu_guest_context)); ++i )
+    {
+        if ( !per_cpu(vgc_pages[i], cpu) )
+            continue;
+        __set_fixmap(idx - i, 0, 0);
+        free_domheap_page(per_cpu(vgc_pages[i], cpu));
+        per_cpu(vgc_pages[i], cpu) = NULL;
+    }
+}
+
 #ifdef __x86_64__
 
 static int setup_compat_l4(struct vcpu *v)
index 1290f655fecc10ba1a5b1c0db37b4e95f1e59ef8..852c968bba0d15854a34319acc7db4463bf570f7 100644 (file)
@@ -832,12 +832,12 @@ long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
         if ( v->vcpu_info == &dummy_vcpu_info )
             return -EINVAL;
 
-        if ( (ctxt = xmalloc(struct vcpu_guest_context)) == NULL )
+        if ( (ctxt = alloc_vcpu_guest_context()) == NULL )
             return -ENOMEM;
 
         if ( copy_from_guest(ctxt, arg, 1) )
         {
-            xfree(ctxt);
+            free_vcpu_guest_context(ctxt);
             return -EFAULT;
         }
 
@@ -847,7 +847,7 @@ long do_vcpu_op(int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
             rc = boot_vcpu(d, vcpuid, ctxt);
         domain_unlock(d);
 
-        xfree(ctxt);
+        free_vcpu_guest_context(ctxt);
         break;
 
     case VCPUOP_up:
index 4d4f8ebe2a0070d9a3ff0d886c7573f5d1e5bed8..5e13094518aadc3b0e5d16981e077800e046bc75 100644 (file)
@@ -295,7 +295,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
                      < sizeof(struct compat_vcpu_guest_context));
 #endif
         ret = -ENOMEM;
-        if ( (c.nat = xmalloc(struct vcpu_guest_context)) == NULL )
+        if ( (c.nat = alloc_vcpu_guest_context()) == NULL )
             goto svc_out;
 
 #ifdef CONFIG_COMPAT
@@ -318,7 +318,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
         }
 
     svc_out:
-        xfree(c.nat);
+        free_vcpu_guest_context(c.nat);
         rcu_unlock_domain(d);
     }
     break;
index 14064ce2475a368b7f25debfcff84d59064d88f4..e5b71e00113434e7d3e2260e7cc6e9ada96765a7 100644 (file)
@@ -25,6 +25,9 @@ struct vcpu;
 extern void relinquish_vcpu_resources(struct vcpu *v);
 extern int vcpu_late_initialise(struct vcpu *v);
 
+#define alloc_vcpu_guest_context() xmalloc(struct vcpu_guest_context)
+#define free_vcpu_guest_context(vgc) xfree(vgc)
+
 /* given a current domain metaphysical address, return the physical address */
 extern unsigned long translate_domain_mpaddr(unsigned long mpaddr,
                                              struct p2m_entry* entry);
index 1815acdf1899c8904724410d3a2662812ffd7698..0614291b9d0e086c3eeefd500336924b0e71744c 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/apicdef.h>
 #include <asm/acpi.h>
 #include <asm/page.h>
+#include <xen/pfn.h>
 #include <xen/kexec.h>
 #include <xen/iommu.h>
 #include <asm/amd-iommu.h>
@@ -34,6 +35,12 @@ enum fixed_addresses {
 #ifdef __i386__
     FIX_PAE_HIGHMEM_0,
     FIX_PAE_HIGHMEM_END = FIX_PAE_HIGHMEM_0 + NR_CPUS-1,
+#define FIX_VGC_END FIX_PAE_HIGHMEM_0
+#define FIX_VGC_BEGIN FIX_PAE_HIGHMEM_END
+#else
+    FIX_VGC_END,
+    FIX_VGC_BEGIN = FIX_VGC_END
+      + PFN_UP(sizeof(struct vcpu_guest_context)) * NR_CPUS - 1,
 #endif
     FIX_APIC_BASE,
     FIX_IO_APIC_BASE_0,
index edffd1f46b6e8fbda69a21effec77167f02bbc23..ddebbe14a95c741c6c987db45e18580a033a0caa 100644 (file)
@@ -32,6 +32,12 @@ void free_domain_struct(struct domain *d);
 struct vcpu *alloc_vcpu_struct(void);
 void free_vcpu_struct(struct vcpu *v);
 
+/* Allocate/free a vcpu_guest_context structure. */
+#ifndef alloc_vcpu_guest_context
+struct vcpu_guest_context *alloc_vcpu_guest_context(void);
+void free_vcpu_guest_context(struct vcpu_guest_context *);
+#endif
+
 /*
  * Initialise/destroy arch-specific details of a VCPU.
  *  - vcpu_initialise() is called after the basic generic fields of the