|
[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 |