[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v4 05/13] 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> --- v4: * Remove stray reg prop parser in libfdt-xen.h. * Remove fdt32_as_uX accessors. * Brough fdt_prop_as_u32() accesor from later patches. * So it can be used in place of a hardcoded fdt32_as_u32(). * Limited MAX_NR_BOOTMODS to INT_MAX. * Preserved BOOTMOD_XEN on module append logic. * Add missing bounds check to module-index parsed in multiboot module helper. * Converted idx variable to uint32_t for better bounds checking. * Braces from switch statement to conform to coding style. * Added missing XENLOG_X. * Print address_cells and size_cells on error parsing reg properties. * Added (transient) missing declaration for extern helper. * becomes static on the next patch. --- xen/common/domain-builder/fdt.c | 162 ++++++++++++++++++++++++++++ xen/common/domain-builder/fdt.h | 2 + xen/include/xen/domain-builder.h | 3 + xen/include/xen/libfdt/libfdt-xen.h | 11 ++ 4 files changed, 178 insertions(+) diff --git a/xen/common/domain-builder/fdt.c b/xen/common/domain-builder/fdt.c index b5ff8220da..d73536fed6 100644 --- a/xen/common/domain-builder/fdt.c +++ b/xen/common/domain-builder/fdt.c @@ -13,6 +13,168 @@ #include "fdt.h" +/* + * 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 read_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 = read_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 955aead497..8c98a256eb 100644 --- a/xen/common/domain-builder/fdt.h +++ b/xen/common/domain-builder/fdt.h @@ -2,6 +2,8 @@ #ifndef __XEN_DOMAIN_BUILDER_FDT_H__ #define __XEN_DOMAIN_BUILDER_FDT_H__ +#include <xen/libfdt/libfdt-xen.h> + struct boot_info; /* hyperlaunch fdt is required to be module 0 */ diff --git a/xen/include/xen/domain-builder.h b/xen/include/xen/domain-builder.h index ac2b84775d..ace6b6875b 100644 --- a/xen/include/xen/domain-builder.h +++ b/xen/include/xen/domain-builder.h @@ -5,5 +5,8 @@ struct boot_info; void builder_init(struct boot_info *bi); +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__ */ diff --git a/xen/include/xen/libfdt/libfdt-xen.h b/xen/include/xen/libfdt/libfdt-xen.h index a5340bc9f4..deafb25d98 100644 --- a/xen/include/xen/libfdt/libfdt-xen.h +++ b/xen/include/xen/libfdt/libfdt-xen.h @@ -12,6 +12,17 @@ #define LIBFDT_XEN_H #include <xen/libfdt/libfdt.h> +#include <xen/errno.h> + +static inline 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; +} static inline int fdt_get_mem_rsv_paddr(const void *fdt, int n, paddr_t *address, -- 2.43.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |