diff --git a/xen/common/device-tree/dom0less-build.c b/xen/common/device-tree/dom0less-build.c index 840d14419d..9787ee2649 100644 --- a/xen/common/device-tree/dom0less-build.c +++ b/xen/common/device-tree/dom0less-build.c @@ -389,6 +389,24 @@ static int __init domain_handle_dtb_boot_module(struct domain *d, if ( res < 0 ) goto out; + /* + * Find the highest phandle in the partial FDT so next_phandle starts + * above it, avoiding collisions with pfdt's own phandle assignments. + */ + res = fdt_generate_phandle(pfdt, &kinfo->next_phandle); + if ( res ) + { + res = (res == -FDT_ERR_NOPHANDLES) ? -EOVERFLOW : -EINVAL; + goto out; + } + + if ( kinfo->next_phandle >= GUEST_PHANDLE_GIC ) + { + dprintk(XENLOG_ERR, "Phandle allocation overlaps Xen reserved range\n"); + res = -EOVERFLOW; + goto out; + } + for ( node_next = fdt_first_subnode(pfdt, 0); node_next > 0; node_next = fdt_next_subnode(pfdt, node_next) ) @@ -459,6 +477,7 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) BUILD_BUG_ON(DOMU_DTB_SIZE > SZ_2M); kinfo->phandle_intc = GUEST_PHANDLE_GIC; + kinfo->next_phandle = 1; #ifdef CONFIG_GRANT_TABLE kinfo->gnttab_start = GUEST_GNTTAB_BASE; @@ -499,6 +518,18 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) if ( ret ) goto err; + /* + * domain_handle_dtb_boot_module() must be called before the rest of the + * device tree is generated because it sets phandle_intc and next_phandle, + * which subsequent node generation depends on. + */ + if ( kinfo->dtb ) + { + ret = domain_handle_dtb_boot_module(d, kinfo); + if ( ret ) + goto err; + } + ret = make_chosen_node(kinfo); if ( ret ) goto err; @@ -516,18 +547,6 @@ static int __init prepare_dtb_domU(struct domain *d, struct kernel_info *kinfo) if ( ret ) goto err; - /* - * domain_handle_dtb_boot_module has to be called before the rest of - * the device tree is generated because it depends on the value of - * the field phandle_intc. - */ - if ( kinfo->dtb ) - { - ret = domain_handle_dtb_boot_module(d, kinfo); - if ( ret ) - goto err; - } - ret = make_intc_domU_node(kinfo); if ( ret ) goto err; diff --git a/xen/include/xen/fdt-domain-build.h b/xen/include/xen/fdt-domain-build.h index 886a853816..fd2ba01ff0 100644 --- a/xen/include/xen/fdt-domain-build.h +++ b/xen/include/xen/fdt-domain-build.h @@ -63,6 +63,12 @@ int find_unallocated_memory(const struct kernel_info *kinfo, unsigned long e_gfn, void *data)); +/* Return 0 (invalid phandle) if the Xen-reserved range has been reached */ +static inline uint32_t alloc_phandle(struct kernel_info *kinfo) +{ + return kinfo->next_phandle >= GUEST_PHANDLE_GIC ? 0 : kinfo->next_phandle++; +} + #endif /* __XEN_FDT_DOMAIN_BUILD_H__ */ /* diff --git a/xen/include/xen/fdt-kernel.h b/xen/include/xen/fdt-kernel.h index 33a60597bb..4d0467bb39 100644 --- a/xen/include/xen/fdt-kernel.h +++ b/xen/include/xen/fdt-kernel.h @@ -44,6 +44,12 @@ struct kernel_info { /* Interrupt controller phandle */ uint32_t phandle_intc; + /* + * Next free phandle for guest device nodes; do not access directly, use + * alloc_phandle(). + */ + uint32_t next_phandle; + /* loader to use for this kernel */ void (*load)(struct kernel_info *info);