[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH RFC 11/15] xen/arm: generate a simple device tree for domUs



Hi Stefano,

On 13/06/18 23:15, Stefano Stabellini wrote:
Introduce functions to generate a basic domU device tree, similar to the
existing functions in tools/libxl/libxl_arm.c.

Rename existing prepare_dtb to prepare_dtb_dom0 to avoid confusion.

Ah this is were the rename is. It might have make sense to do that in patch #9. Also, you want to name it "hwdom" as this is the preferred name nowadays.


Signed-off-by: Stefano Stabellini <stefanos@xxxxxxxxxx>
---
  xen/arch/arm/domain_build.c | 195 +++++++++++++++++++++++++++++++++++++++++++-
  1 file changed, 193 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 02a7f94..b4f560f 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1360,7 +1360,194 @@ static int handle_node(struct domain *d, struct 
kernel_info *kinfo,
      return res;
  }
-static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
+static int make_gic_domU_node(const struct domain *d, void *fdt, int 
addrcells, int sizecells)
+{
+    int res = 0;
+    int reg_size = addrcells + sizecells;
+    int nr_cells = reg_size * 2;
+    __be32 reg[nr_cells]; > +    __be32 *cells;
+
+    res = fdt_begin_node(fdt, "interrupt-controller");

Per the DT spec, node name should contain @unit-address when a "reg" property present. "unit-address" been the first address of the "reg" property.

Per the DT spec, node should have @base when a "regs" property is present.

+    if ( res )
+        return res;
+
+    res = fdt_property_cell(fdt, "#address-cells", 0);
+    if ( res )
+        return res;
+
+    res = fdt_property_cell(fdt, "#interrupt-cells", 3);
+    if ( res )
+        return res;
+
+    res = fdt_property(fdt, "interrupt-controller", NULL, 0);
+    if ( res )
+        return res;
+
+    if (gic_hw_version() == GIC_V3)

Could we use a switch please? This would allow to catch easily new hardware version.

+    {
+        const uint64_t gicd_base = GUEST_GICV3_GICD_BASE;
+        const uint64_t gicd_size = GUEST_GICV3_GICD_SIZE;
+        const uint64_t gicr0_base = GUEST_GICV3_GICR0_BASE;
+        const uint64_t gicr0_size = GUEST_GICV3_GICR0_SIZE;
+
+        res = fdt_property_string(fdt, "compatible", "arm,gic-v3");
+        if ( res )
+            return res;
+
+        cells = &reg[0];
+        dt_child_set_range(&cells, addrcells, sizecells, gicd_base, gicd_size);
+        dt_child_set_range(&cells, addrcells, sizecells, gicr0_base, 
gicr0_size);
+        res = fdt_property(fdt, "reg", reg, sizeof(reg));
+    }
+    else if (gic_hw_version() == GIC_V3)

I think this should be GIC_V2 here.

+    {
+        const uint64_t gicd_base = GUEST_GICD_BASE;
+        const uint64_t gicd_size = GUEST_GICD_SIZE;
+        const uint64_t gicc_base = GUEST_GICC_BASE;
+        const uint64_t gicc_size = GUEST_GICC_SIZE;
+
+        res = fdt_property_string(fdt, "compatible", "arm,cortex-a15-gic");

I know that we use that property in libxl. But this is a bit weird to use it for Arm64 guest :). It would be better to use arm,gic-400 here.

+        if ( res )
+            return res;
+
+        cells = &reg[0];
+        dt_child_set_range(&cells, addrcells, sizecells, gicd_base, gicd_size);
+        dt_child_set_range(&cells, addrcells, sizecells, gicc_base, gicc_size);
+    }
+
+    res = fdt_property(fdt, "reg", reg, sizeof(reg));
+    if (res)
+        return res;
+
+    res = fdt_property_cell(fdt, "linux,phandle", PHANDLE_GIC);
+    if (res)
+        return res;
+
+    res = fdt_property_cell(fdt, "phandle", PHANDLE_GIC);
+    if (res)
+        return res;
+
+    res = fdt_end_node(fdt);
+
+    return res;
+}
+
+static int make_timer_domU_node(const struct domain *d, void *fdt)
+{
+    int res;
+    gic_interrupt_t intrs[3];
+
+    res = fdt_begin_node(fdt, "timer");
+    if ( res )
+        return res;
+
+    if (!is_64bit_domain(d))
+    {
+        res = fdt_property_string(fdt, "compatible", "arm,armv7-timer");
+        if ( res )
+            return res;
+    } else {
+        res = fdt_property_string(fdt, "compatible", "arm,armv8-timer");
+        if ( res )
+            return res;
+    }
+
+    set_interrupt_ppi(intrs[0], GUEST_TIMER_PHYS_S_PPI, 0xf, 
DT_IRQ_TYPE_LEVEL_LOW);
+    set_interrupt_ppi(intrs[1], GUEST_TIMER_PHYS_NS_PPI, 0xf, 
DT_IRQ_TYPE_LEVEL_LOW);
+    set_interrupt_ppi(intrs[2], GUEST_TIMER_VIRT_PPI, 0xf, 
DT_IRQ_TYPE_LEVEL_LOW);
+
+    res = fdt_property(fdt, "interrupts", intrs, sizeof (intrs[0]) * 3);
+    if ( res )
+        return res;
+
+    res = fdt_property_cell(fdt, "interrupt-parent",
+                            PHANDLE_GIC);
+    if (res)
+        return res;
+
+    res = fdt_end_node(fdt);
+    return res;
+}
+
+#define DOMU_DTB_SIZE 4096

Is this going to be enough? Per the documentation, the maximum size of a DT is 2MB.

+static int prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo)
+{
+    int addrcells, sizecells;
+    int ret;
+
+    addrcells = dt_child_n_addr_cells(dt_host);
+    sizecells = dt_child_n_size_cells(dt_host);
+
+    kinfo->fdt = xmalloc_bytes(DOMU_DTB_SIZE);
+    if ( kinfo->fdt == NULL )
+        return -ENOMEM;
+
+    ret = fdt_create(kinfo->fdt, DOMU_DTB_SIZE);
+    if ( ret < 0 )
+        goto err;
+
+    ret = fdt_finish_reservemap(kinfo->fdt);
+    if ( ret < 0 )
+        goto err;
+
+    ret = fdt_begin_node(kinfo->fdt, "/");
+    if ( ret < 0 )
+        goto err;
+
+    ret = fdt_property_cell(kinfo->fdt, "#address-cells", addrcells);
+    if ( ret )
+        goto err;
+
+    ret = fdt_property_cell(kinfo->fdt, "#size-cells", sizecells);
+    if ( ret )
+        goto err;
+
+    ret = make_chosen_node(kinfo);
+    if ( ret )
+        goto err;
+
+    ret = make_hypervisor_node(d, kinfo, addrcells, sizecells);

make_hypervisor_node() will allocate an PPIfor the event channel based on what's available. However, the PPI for the guests is static and the timer is allocated afterwards.

So you probably want to rework make_hypervisor_node to pass the interrupt in parameter.

+    if ( ret )
+        goto err;
+
+    ret = make_psci_node(kinfo->fdt, NULL);
+    if ( ret )
+        goto err;
+
+    ret = make_cpus_node(d, kinfo->fdt, NULL);
+    if ( ret )
+        goto err;
+
+    ret = make_memory_node(d, kinfo->fdt, addrcells, sizecells, kinfo);
+    if ( ret )
+        goto err;
+
+    ret = make_gic_domU_node(d, kinfo->fdt, addrcells, sizecells);
+    if ( ret )
+        goto err;
+
+    ret = make_timer_domU_node(d, kinfo->fdt);
+    if ( ret )
+        goto err;
+
+    ret = fdt_end_node(kinfo->fdt);
+    if ( ret < 0 )
+        goto err;
+
+    ret = fdt_finish(kinfo->fdt);
+    if ( ret < 0 )
+        goto err;
+
+    return 0;
+
+  err:
+    printk("Device tree generation failed (%d).\n", ret);
+    xfree(kinfo->fdt);
+    return -EINVAL;
+}
+
+static int prepare_dtb_dom0(struct domain *d, struct kernel_info *kinfo)
  {
      const p2m_type_t default_p2mt = p2m_mmio_direct_c;
      const void *fdt;
@@ -2221,6 +2408,10 @@ int __init construct_domU(struct domain *d, struct 
dt_device_node *node)
      d->arch.type = kinfo.type;
      allocate_memory(d, &kinfo);
+ rc = prepare_dtb_domU(d, &kinfo);
+    if ( rc < 0 )
+        return rc;
+
      return __construct_domain(d, &kinfo);
  }
@@ -2270,7 +2461,7 @@ int __init construct_dom0(struct domain *d)
      d->arch.type = kinfo.type;
if ( acpi_disabled )
-        rc = prepare_dtb(d, &kinfo);
+        rc = prepare_dtb_dom0(d, &kinfo);
      else
          rc = prepare_acpi(d, &kinfo);

Cheers,

--
Julien Grall

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.