---
CC: Wei Liu <wei.l...@citrix.com>
CC: Stefano Stabellini <sstabell...@kernel.org>
CC: Julien Grall <julien.gr...@arm.com>
v3:
* Fix 4092/4096 typo
* Fix build in NEW_VGIC case
v4:
* Move the min() into ARM's common arch_sanitise_domain_config()
implementation. Simplfy the min() expression code by making MAX_VIRT_CPUS
be an unsigned constant.
v5:
* s/max/min
---
xen/arch/arm/domain.c | 18 ++++++++++++++++++
xen/arch/arm/vgic-v2.c | 1 -
xen/arch/arm/vgic-v3.c | 5 -----
xen/arch/arm/vgic.c | 16 ++++++++++++++--
xen/arch/arm/vgic/vgic-init.c | 3 ---
xen/arch/arm/vgic/vgic.c | 16 ++++++----------
xen/arch/x86/domain.c | 10 ++++++++++
xen/common/domain.c | 33 ++++++++++++++++++++-------------
xen/include/asm-arm/config.h | 4 ++--
xen/include/asm-arm/domain.h | 6 ------
xen/include/asm-arm/vgic.h | 5 ++---
xen/include/asm-x86/domain.h | 2 --
12 files changed, 72 insertions(+), 47 deletions(-)
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 71ad1f9..1d926dc 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -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;
}
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index bf77899..64b141f 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -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)
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index c14bcd8..519cc72 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -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)
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 5a4f082..f2608b0 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -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;
+ }
}
/*
diff --git a/xen/arch/arm/vgic/vgic-init.c b/xen/arch/arm/vgic/vgic-init.c
index bfd3d09..62ae553 100644
--- a/xen/arch/arm/vgic/vgic-init.c
+++ b/xen/arch/arm/vgic/vgic-init.c
@@ -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;
diff --git a/xen/arch/arm/vgic/vgic.c b/xen/arch/arm/vgic/vgic.c
index 7c3cfc5..e2844dc 100644
--- a/xen/arch/arm/vgic/vgic.c
+++ b/xen/arch/arm/vgic/vgic.c
@@ -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
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 272fd84..295b10c 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -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;
}
diff --git a/xen/common/domain.c b/xen/common/domain.c
index f69f405..78cc524 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -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;
diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h
index cdae8f6..bc89e84 100644
--- a/xen/include/asm-arm/config.h
+++ b/xen/include/asm-arm/config.h
@@ -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
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index d682307..175de44 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -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
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index 56ed5fe..447d24e 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -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);
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 643e69a..277f99f 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -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));