xen/domain: Allocate d->vcpu[] earlier during domain_create()
authorAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 2 Oct 2018 14:02:55 +0000 (14:02 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 15 Nov 2018 11:11:30 +0000 (11:11 +0000)
The ARM code has a chicken-and-egg problem.  One of the vGICv3 emulations
wants to know d->max_vcpus to be able to size itself appropriately, but the
current order of initialisation requires the vGIC to be set up before the
requested number of vcpus can be checked.

Move the range checking of config->max_vcpus into sanitise_domain_config()
path, which allows for the allocation of d->vcpu[] and d->max_vcpus to happen
earlier during create, and in particular, before the call to
arch_domain_create().

The x86 side is fairly easy, and implements the logical equivalent of
domain_max_vcpus() but using XEN_DOMCTL_CDF_hvm_guest rather than
is_hvm_domain().

For the ARM side, re-purpose vgic_max_vcpus() to take a domctl vGIC version,
and return the maximum number of supported vCPUs, reusing 0 for "version not
supported".  To avoid exporting the vgic_ops structures (which are in the
process of being replaced), hard code the upper limits.

This allows for the removal of the domain_max_vcpus() infrastructure, which is
done to prevent it being reused incorrectly in the future.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Julien Grall <julien.grall@arm.com>
12 files changed:
xen/arch/arm/domain.c
xen/arch/arm/vgic-v2.c
xen/arch/arm/vgic-v3.c
xen/arch/arm/vgic.c
xen/arch/arm/vgic/vgic-init.c
xen/arch/arm/vgic/vgic.c
xen/arch/x86/domain.c
xen/common/domain.c
xen/include/asm-arm/config.h
xen/include/asm-arm/domain.h
xen/include/asm-arm/vgic.h
xen/include/asm-x86/domain.h

index 71ad1f965398e9d5e7dcf98fa8e3e3fd0df2ce98..1d926dcb297ed16f7b1b4e2aeace57f43c4bc6e7 100644 (file)
@@ -601,6 +601,8 @@ void vcpu_switch_to_aarch64_mode(struct vcpu *v)
 
 int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
 {
+    unsigned int max_vcpus;
+
     if ( config->flags != (XEN_DOMCTL_CDF_hvm_guest | XEN_DOMCTL_CDF_hap) )
     {
         dprintk(XENLOG_INFO, "Unsupported configuration %#x\n", config->flags);
@@ -626,6 +628,22 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         }
     }
 
+    /* max_vcpus depends on the GIC version, and Xen's compiled limit. */
+    max_vcpus = min(vgic_max_vcpus(config->arch.gic_version), MAX_VIRT_CPUS);
+
+    if ( max_vcpus == 0 )
+    {
+        dprintk(XENLOG_INFO, "Unsupported GIC version\n");
+        return -EINVAL;
+    }
+
+    if ( config->max_vcpus > max_vcpus )
+    {
+        dprintk(XENLOG_INFO, "Requested vCPUs (%u) exceeds max (%u)\n",
+                config->max_vcpus, max_vcpus);
+        return -EINVAL;
+    }
+
     return 0;
 }
 
index bf77899dbafffea122d5663a4c6cd39e8361052c..64b141fea58602a504f83ad955b8dde69b98e220 100644 (file)
@@ -725,7 +725,6 @@ static const struct vgic_ops vgic_v2_ops = {
     .domain_free = vgic_v2_domain_free,
     .lpi_to_pending = vgic_v2_lpi_to_pending,
     .lpi_get_priority = vgic_v2_lpi_get_priority,
-    .max_vcpus = 8,
 };
 
 int vgic_v2_init(struct domain *d, int *mmio_count)
index c14bcd87b1ff95db738e5c468c781b25fd0270c0..519cc728ab2f37f990b552a77330898ab81bb567 100644 (file)
@@ -1822,11 +1822,6 @@ static const struct vgic_ops v3_ops = {
     .emulate_reg  = vgic_v3_emulate_reg,
     .lpi_to_pending = vgic_v3_lpi_to_pending,
     .lpi_get_priority = vgic_v3_lpi_get_priority,
-    /*
-     * We use both AFF1 and AFF0 in (v)MPIDR. Thus, the max number of CPU
-     * that can be supported is up to 4096(==256*16) in theory.
-     */
-    .max_vcpus = 4096,
 };
 
 int vgic_v3_init(struct domain *d, int *mmio_count)
index 5a4f082c1666bc3c216237ff7ea208e91446abbd..f2608b042dabe99ab249ec304f0b3179d483ae53 100644 (file)
@@ -667,9 +667,21 @@ void vgic_free_virq(struct domain *d, unsigned int virq)
     clear_bit(virq, d->arch.vgic.allocated_irqs);
 }
 
-unsigned int vgic_max_vcpus(const struct domain *d)
+unsigned int vgic_max_vcpus(unsigned int domctl_vgic_version)
 {
-    return min_t(unsigned int, MAX_VIRT_CPUS, d->arch.vgic.handler->max_vcpus);
+    switch ( domctl_vgic_version )
+    {
+    case XEN_DOMCTL_CONFIG_GIC_V2:
+        return 8;
+
+#ifdef CONFIG_GICV3
+    case XEN_DOMCTL_CONFIG_GIC_V3:
+        return 4096;
+#endif
+
+    default:
+        return 0;
+    }
 }
 
 /*
index bfd3d09edbb09e43bacb191d2531e3570e121ec2..62ae5536997be5d0be7eae2cbc9e89be63d81185 100644 (file)
@@ -112,9 +112,6 @@ int domain_vgic_register(struct domain *d, int *mmio_count)
         BUG();
     }
 
-    if ( d->max_vcpus > domain_max_vcpus(d) )
-        return -E2BIG;
-
     d->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
     d->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
     d->arch.vgic.vgic_redist_base = VGIC_ADDR_UNDEF;
index 7c3cfc51824378a4dd474f8b2927a4f93c13ce6b..e2844dcc207191a1b3f691e63d46cbce94026d70 100644 (file)
@@ -949,20 +949,16 @@ void vgic_sync_hardware_irq(struct domain *d,
     spin_unlock_irqrestore(&desc->lock, flags);
 }
 
-unsigned int vgic_max_vcpus(const struct domain *d)
+unsigned int vgic_max_vcpus(unsigned int domctl_vgic_version)
 {
-    unsigned int vgic_vcpu_limit;
-
-    switch ( d->arch.vgic.version )
+    switch ( domctl_vgic_version )
     {
-    case GIC_V2:
-        vgic_vcpu_limit = VGIC_V2_MAX_CPUS;
-        break;
+    case XEN_DOMCTL_CONFIG_GIC_V2:
+        return VGIC_V2_MAX_CPUS;
+
     default:
-        BUG();
+        return 0;
     }
-
-    return min_t(unsigned int, MAX_VIRT_CPUS, vgic_vcpu_limit);
 }
 
 #ifdef CONFIG_GICV3
index 272fd84a3c632596acc8a85fe194c3b9e54721d1..295b10c48c75611b9a58f94a62b1e8d2c7d5c58c 100644 (file)
@@ -421,6 +421,7 @@ void arch_vcpu_destroy(struct vcpu *v)
 int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
 {
     bool hvm = config->flags & XEN_DOMCTL_CDF_hvm_guest;
+    unsigned int max_vcpus;
 
     if ( hvm ? !hvm_enabled : !IS_ENABLED(CONFIG_PV) )
     {
@@ -428,6 +429,15 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
+    max_vcpus = hvm ? HVM_MAX_VCPUS : MAX_VIRT_CPUS;
+
+    if ( config->max_vcpus > max_vcpus )
+    {
+        dprintk(XENLOG_INFO, "Requested vCPUs (%u) exceeds max (%u)\n",
+                config->max_vcpus, max_vcpus);
+        return -EINVAL;
+    }
+
     return 0;
 }
 
index f69f4055cd77dd98a0903609336fe019ba4edf4e..78cc5249e8d6667fd273b23f83cd8c9a8167c80a 100644 (file)
@@ -300,6 +300,12 @@ static int sanitise_domain_config(struct xen_domctl_createdomain *config)
         return -EINVAL;
     }
 
+    if ( config->max_vcpus < 1 )
+    {
+        dprintk(XENLOG_INFO, "No vCPUS\n");
+        return -EINVAL;
+    }
+
     return arch_sanitise_domain_config(config);
 }
 
@@ -345,6 +351,20 @@ struct domain *domain_create(domid_t domid,
 
     TRACE_1D(TRC_DOM0_DOM_ADD, d->domain_id);
 
+    /*
+     * Allocate d->vcpu[] and set ->max_vcpus up early.  Various per-domain
+     * resources want to be sized based on max_vcpus.
+     */
+    if ( !is_system_domain(d) )
+    {
+        err = -ENOMEM;
+        d->vcpu = xzalloc_array(struct vcpu *, config->max_vcpus);
+        if ( !d->vcpu )
+            goto fail;
+
+        d->max_vcpus = config->max_vcpus;
+    }
+
     lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain");
 
     if ( (err = xsm_alloc_security_domain(d)) != 0 )
@@ -396,19 +416,6 @@ struct domain *domain_create(domid_t domid,
 
     if ( !is_idle_domain(d) )
     {
-        /* Check d->max_vcpus and allocate d->vcpu[]. */
-        err = -EINVAL;
-        if ( config->max_vcpus < 1 ||
-             config->max_vcpus > domain_max_vcpus(d) )
-            goto fail;
-
-        err = -ENOMEM;
-        d->vcpu = xzalloc_array(struct vcpu *, config->max_vcpus);
-        if ( !d->vcpu )
-            goto fail;
-
-        d->max_vcpus = config->max_vcpus;
-
         watchdog_domain_init(d);
         init_status |= INIT_watchdog;
 
index cdae8f64fff6060f6ddded3821a6295409130de9..bc89e84f4d67abf1e1dd37d72046bba2c36bc0ea 100644 (file)
@@ -41,9 +41,9 @@
 #define OPT_CONSOLE_STR "dtuart"
 
 #ifdef CONFIG_ARM_64
-#define MAX_VIRT_CPUS 128
+#define MAX_VIRT_CPUS 128u
 #else
-#define MAX_VIRT_CPUS 8
+#define MAX_VIRT_CPUS 8u
 #endif
 
 #define INVALID_VCPU_ID MAX_VIRT_CPUS
index d682307b27b0c013cf344142ad3c197e3e8d344b..175de449273de9ab5730f01934df1a08218fd9e9 100644 (file)
@@ -208,12 +208,6 @@ void vcpu_show_execution_state(struct vcpu *);
 void vcpu_show_registers(const struct vcpu *);
 void vcpu_switch_to_aarch64_mode(struct vcpu *);
 
-/* On ARM, the number of VCPUs is limited by the type of GIC emulated. */
-static inline unsigned int domain_max_vcpus(const struct domain *d)
-{
-    return vgic_max_vcpus(d);
-}
-
 /*
  * Due to the restriction of GICv3, the number of vCPUs in AFF0 is
  * limited to 16, thus only the first 4 bits of AFF0 are legal. We will
index 56ed5fe8fe25aaf1436961c4c1864b76ae2fdb94..447d24ea59b386f0a04de98f82242d227d1bcf83 100644 (file)
@@ -234,8 +234,6 @@ struct vgic_ops {
     /* lookup the struct pending_irq for a given LPI interrupt */
     struct pending_irq *(*lpi_to_pending)(struct domain *d, unsigned int vlpi);
     int (*lpi_get_priority)(struct domain *d, uint32_t vlpi);
-    /* Maximum number of vCPU supported */
-    const unsigned int max_vcpus;
 };
 
 /* Number of ranks of interrupt registers for a domain */
@@ -350,7 +348,8 @@ extern void vgic_clear_pending_irqs(struct vcpu *v);
 
 extern bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr);
 
-unsigned int vgic_max_vcpus(const struct domain *d);
+/* Maximum vCPUs for a specific vGIC version, or 0 for unsupported. */
+unsigned int vgic_max_vcpus(unsigned int domctl_vgic_version);
 
 void vgic_v2_setup_hw(paddr_t dbase, paddr_t cbase, paddr_t csize,
                       paddr_t vbase, uint32_t aliased_offset);
index 643e69acf95418a261c259443f3c73014bee0b1e..277f99f6330df87e56a611718dda3f627f691fb3 100644 (file)
@@ -664,8 +664,6 @@ unsigned long pv_guest_cr4_to_real_cr4(const struct vcpu *v);
              X86_CR4_OSXSAVE | X86_CR4_SMEP |               \
              X86_CR4_FSGSBASE | X86_CR4_SMAP | X86_CR4_PCIDE))
 
-#define domain_max_vcpus(d) (is_hvm_domain(d) ? HVM_MAX_VCPUS : MAX_VIRT_CPUS)
-
 static inline struct vcpu_guest_context *alloc_vcpu_guest_context(void)
 {
     return vmalloc(sizeof(struct vcpu_guest_context));