[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v5 04/12] x86/hyperlaunch: Add helpers to locate multiboot modules
Hyperlaunch mandates either a reg or module-index DT prop on nodes that contain `multiboot,module" under their "compatible" prop. This patch introduces a helper to generically find such index, appending the module to the list of modules if it wasn't already (i.e: because it's given via the "reg" prop). Signed-off-by: Jason Andryuk <jason.andryuk@xxxxxxx> Signed-off-by: Alejandro Vallejo <agarciav@xxxxxxx> --- v5: * s/read_fdt_prop_as_reg/fdt_prop_as_reg/ * Move the _u32() prop helper to fdt.c --- xen/common/domain-builder/fdt.c | 172 +++++++++++++++++++++++++++++++ xen/common/domain-builder/fdt.h | 1 + xen/include/xen/domain-builder.h | 4 + 3 files changed, 177 insertions(+) diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index c1ccba39a2..11f0436e85 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -13,6 +13,178 @@ #include "fdt.h" +static int __init fdt_prop_as_u32(const struct fdt_property *prop, + uint32_t *val) +{ + if ( !prop || fdt32_to_cpu(prop->len) < sizeof(u32) ) + return -EINVAL; + + *val = fdt32_to_cpu(*(const fdt32_t *)prop->data); + return 0; +} + +/* + * Unpacks a "reg" property into its address and size constituents. + * + * @param prop Pointer to an FDT "reg" property. + * @param address_cells Number of 4-octet cells that make up an "address". + * @param size_cells Number of 4-octet cells that make up a "size". + * @param p_addr[out] Address encoded in the property. + * @param p_size[out] Size encoded in the property. + * @returns -EINVAL on malformed property, 0 otherwise. + */ +static int __init fdt_prop_as_reg(const struct fdt_property *prop, + int address_cells, int size_cells, + uint64_t *p_addr, uint64_t *p_size) +{ + const fdt32_t *cell = (const fdt32_t *)prop->data; + uint64_t addr, size; + + if ( fdt32_to_cpu(prop->len) != + (address_cells + size_cells) * sizeof(*cell) ) + { + printk(XENLOG_ERR " cannot read reg %lu+%lu from prop len %u\n", + address_cells * sizeof(*cell), size_cells * sizeof(*cell), + fdt32_to_cpu(prop->len)); + return -EINVAL; + } + + switch ( address_cells ) + { + case 1: + addr = fdt32_to_cpu(*cell); + break; + case 2: + addr = fdt64_to_cpu(*(const fdt64_t *)cell); + break; + default: + printk(XENLOG_ERR " unsupported address_cells=%d\n", address_cells); + return -EINVAL; + } + + cell += address_cells; + switch ( size_cells ) + { + case 1: + size = fdt32_to_cpu(*cell); + break; + case 2: + size = fdt64_to_cpu(*(const fdt64_t *)cell); + break; + default: + printk(XENLOG_ERR " unsupported size_cells=%d\n", size_cells); + return -EINVAL; + } + + *p_addr = addr; + *p_size = size; + + return 0; +} + +/* + * Locate a multiboot module given its node offset in the FDT. + * + * The module location may be given via either FDT property: + * * reg = <address, size> + * * Mutates `bi` to append the module. + * * module-index = <idx> + * * Leaves `bi` unchanged. + * + * @param fdt Pointer to the full FDT. + * @param node Offset for the module node. + * @param address_cells Number of 4-octet cells that make up an "address". + * @param size_cells Number of 4-octet cells that make up a "size". + * @param bi[inout] Xen's representation of the boot parameters. + * @return -EINVAL on malformed nodes, otherwise + * index inside `bi->mods` + */ +int __init fdt_read_multiboot_module(const void *fdt, int node, + int address_cells, int size_cells, + struct boot_info *bi) +{ + const struct fdt_property *prop; + uint64_t addr, size; + int ret; + uint32_t idx; + + if ( fdt_node_check_compatible(fdt, node, "multiboot,module") ) + { + printk(XENLOG_ERR " bad module. multiboot,module not found"); + return -ENODATA; + } + + /* Location given as a `module-index` property. */ + if ( (prop = fdt_get_property(fdt, node, "module-index", NULL)) ) + { + if ( fdt_get_property(fdt, node, "reg", NULL) ) + { + printk(XENLOG_ERR " found both reg and module-index for module\n"); + return -EINVAL; + } + if ( (ret = fdt_prop_as_u32(prop, &idx)) ) + { + printk(XENLOG_ERR " bad module-index prop\n"); + return ret; + } + if ( idx >= MAX_NR_BOOTMODS ) + { + printk(XENLOG_ERR " module-index overflow. %s=%u\n", + STR(MAX_NR_BOOTMODS), MAX_NR_BOOTMODS); + return -EINVAL; + } + + return idx; + } + + /* Otherwise location given as a `reg` property. */ + if ( !(prop = fdt_get_property(fdt, node, "reg", NULL)) ) + { + printk(XENLOG_ERR " no location for multiboot,module\n"); + return -EINVAL; + } + if ( fdt_get_property(fdt, node, "module-index", NULL) ) + { + printk(XENLOG_ERR " found both reg and module-index for module\n"); + return -EINVAL; + } + + ret = fdt_prop_as_reg(prop, address_cells, size_cells, &addr, &size); + if ( ret < 0 ) + { + printk(XENLOG_ERR " failed reading reg for multiboot,module\n"); + return -EINVAL; + } + + idx = bi->nr_modules; + if ( idx > MAX_NR_BOOTMODS ) + { + /* + * MAX_NR_BOOTMODS must fit in 31 bits so it's representable in the + * positive side of an int; for the return value. + */ + BUILD_BUG_ON(MAX_NR_BOOTMODS > (uint64_t)INT_MAX); + printk(XENLOG_ERR " idx=%u exceeds len=%u\n", idx, MAX_NR_BOOTMODS); + return -EINVAL; + } + + /* + * Append new module to the existing list + * + * Note that bi->nr_modules points to Xen itself, so we must shift it first + */ + bi->nr_modules++; + bi->mods[bi->nr_modules] = bi->mods[idx]; + bi->mods[idx] = (struct boot_module){ + .start = addr, + .size = size, + }; + + printk(XENLOG_INFO " module[%u]: addr %lx size %lx\n", idx, addr, size); + + return idx; +} + static int __init find_hyperlaunch_node(const void *fdt) { int hv_node = fdt_path_offset(fdt, "/chosen/hypervisor"); diff --git a/xen/common/domain-builder/fdt.h b/xen/common/domain-builder/fdt.h index 826c0f01e5..f48456acd2 100644 --- a/xen/common/domain-builder/fdt.h +++ b/xen/common/domain-builder/fdt.h @@ -3,6 +3,7 @@ #define __XEN_DOMAIN_BUILDER_FDT_H__ #include <xen/domain-builder.h> +#include <xen/libfdt/libfdt-xen.h> struct boot_info; diff --git a/xen/include/xen/domain-builder.h b/xen/include/xen/domain-builder.h index cbb3cbea7c..3ac3a0ab84 100644 --- a/xen/include/xen/domain-builder.h +++ b/xen/include/xen/domain-builder.h @@ -28,4 +28,8 @@ static inline enum fdt_kind builder_init(struct boot_info *bi) } #endif /* !IS_ENABLED(CONFIG_DOMAIN_BUILDER) */ +int fdt_read_multiboot_module(const void *fdt, int node, + int address_cells, int size_cells, + struct boot_info *bi) + #endif /* __XEN_DOMAIN_BUILDER_H__ */ -- 2.43.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |