---
v2 changes:
- remove redistributor accessor
- introduce new helper "is_domain_use_host_layout()"
- comment fix
---
v3 changes:
- the comment on top of 'buf' to explain how 38 was found
- fix res getting overwritten
- drop 'cells += (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS)'
- free 'reg' right way
- fix comment
- rename 'is_domain_use_host_layout()' to 'domain_use_host_layout()'
---
xen/arch/arm/domain_build.c | 37 +++++++++++++++++++++++++++---------
xen/arch/arm/vgic-v3.c | 29 ++++++++++++++++------------
xen/include/asm-arm/domain.h | 7 +++++++
3 files changed, 52 insertions(+), 21 deletions(-)
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 24f3edf069..61fd374c5d 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2284,10 +2284,16 @@ static int __init make_gicv3_domU_node(struct
kernel_info *kinfo)
{
void *fdt = kinfo->fdt;
int res = 0;
- __be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2];
- __be32 *cells;
+ __be32 *reg;
+ const struct domain *d = kinfo->d;
+ /* Placeholder for interrupt-controller@ + a 64-bit number + \0 */
+ char buf[38];
+ unsigned int i, len = 0;
- res = fdt_begin_node(fdt, "interrupt-controller@"__stringify(GUEST_GICV3_GICD_BASE));
+ snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
+ vgic_dist_base(&d->arch.vgic));
+
+ res = fdt_begin_node(fdt, buf);
if ( res )
return res;
@@ -2307,13 +2313,26 @@ static int __init make_gicv3_domU_node(struct kernel_info *kinfo)
if ( res )
return res;
- cells = ®[0];
- dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
- GUEST_GICV3_GICD_BASE, GUEST_GICV3_GICD_SIZE);
- dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
- GUEST_GICV3_GICR0_BASE, GUEST_GICV3_GICR0_SIZE);
+ /* reg specifies all re-distributors and Distributor. */
+ len = (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
+ (d->arch.vgic.nr_regions + 1) * sizeof(__be32);
+ reg = xmalloc_bytes(len);
+ if ( reg == NULL )
+ return -ENOMEM;
- res = fdt_property(fdt, "reg", reg, sizeof(reg));
+ dt_child_set_range(®, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+ vgic_dist_base(&d->arch.vgic), GUEST_GICV3_GICD_SIZE);
+
+ for ( i = 0; i < d->arch.vgic.nr_regions; i++)
+ {
+ dt_child_set_range(®,
+ GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+ d->arch.vgic.rdist_regions[i].base,
+ d->arch.vgic.rdist_regions[i].size);
+ }
+
+ res = fdt_property(fdt, "reg", reg, len);
+ xfree(reg);
if (res)
return res;
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 65bb7991a6..181b66513d 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1640,14 +1640,15 @@ static inline unsigned int
vgic_v3_max_rdist_count(struct domain *d)
* Normally there is only one GICv3 redistributor region.
* The GICv3 DT binding provisions for multiple regions, since there are
* platforms out there which need those (multi-socket systems).
- * For Dom0 we have to live with the MMIO layout the hardware provides,
- * so we have to copy the multiple regions - as the first region may not
- * provide enough space to hold all redistributors we need.
+ * For domain using the host memory layout, we have to live with the MMIO
+ * layout the hardware provides, so we have to copy the multiple regions
+ * - as the first region may not provide enough space to hold all
+ * redistributors we need.
* However DomU get a constructed memory map, so we can go with
* the architected single redistributor region.
*/
- return is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions :
- GUEST_GICV3_RDIST_REGIONS;
+ return domain_use_host_layout(d) ? vgic_v3_hw.nr_rdist_regions :
+ GUEST_GICV3_RDIST_REGIONS;
}
static int vgic_v3_domain_init(struct domain *d)
@@ -1669,10 +1670,14 @@ static int vgic_v3_domain_init(struct domain *d)
radix_tree_init(&d->arch.vgic.pend_lpi_tree);
/*
- * Domain 0 gets the hardware address.
- * Guests get the virtual platform layout.
+ * Since we map the whole GICv3 register memory map(64KB) for
+ * all domain, DOM0 and direct-map domain could be treated the
+ * same way here.
+ * For domain using the host memory layout, it gets the hardware
+ * address.
+ * Other domains get the virtual platform layout.
*/
- if ( is_hardware_domain(d) )
+ if ( domain_use_host_layout(d) )
{
unsigned int first_cpu = 0;
@@ -1695,10 +1700,10 @@ static int vgic_v3_domain_init(struct domain *d)
}
/*
- * The hardware domain may not use all the re-distributors
- * regions (e.g when the number of vCPUs does not match the
- * number of pCPUs). Update the number of regions to avoid
- * exposing unused region as they will not get emulated.
+ * For domain using the host memory layout, it may not use all
+ * the re-distributors regions (e.g when the number of vCPUs does
+ * not match the number of pCPUs). Update the number of regions to
+ * avoid exposing unused region as they will not get emulated.
*/
d->arch.vgic.nr_regions = i + 1;
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 4f2c3f09d4..0eff93197e 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -32,6 +32,13 @@ enum domain_type {
#define is_domain_direct_mapped(d) \
(d->options & XEN_DOMCTL_CDF_INTERNAL_directmap)
+/*
+ * For domain using the host memory layout, we have to live with the MMIO
+ * layout the hardware provides.
+ */