[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 21/24] tools/(lib)xl: Add partial device tree support for ARM
Let the user to pass additional nodes to the guest device tree. For this purpose, everything in the node /passthrough from the partial device tree will be copied into the guest device tree. The node /aliases will be also copied to allow the user to define aliases which can be used by the guest kernel. A simple partial device tree will look like: /dts-v1/; / { #address-cells = <2>; #size-cells = <2>; passthrough { compatible = "simple-bus"; ranges; #address-cells = <2>; #size-cells = <2>; /* List of your nodes */ } }; Note that: * The interrupt-parent proporties will be added by the toolstack in the root node * The properties compatible, ranges, #address-cells and #size-cells in /passthrough are mandatory. Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx> Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> Cc: Wei Liu <wei.liu2@xxxxxxxxxx> --- Changes in v3: - Patch added --- docs/man/xl.cfg.pod.5 | 7 ++ tools/libxl/libxl_arm.c | 253 ++++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_types.idl | 1 + tools/libxl/xl_cmdimpl.c | 1 + 4 files changed, 262 insertions(+) diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index e2f91fc..225b782 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -398,6 +398,13 @@ not emulated. Specify that this domain is a driver domain. This enables certain features needed in order to run a driver domain. +=item B<device_tree=PATH> + +Specify a partial device tree (compiled via the Device Tree Compiler). +Everything under the node "/passthrough" will be copied into the guest +device tree. For convenience, the node "/aliases" is also copied to allow +the user to defined aliases which can be used by the guest kernel. + =back =head2 Devices diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c index 53177eb..619458b 100644 --- a/tools/libxl/libxl_arm.c +++ b/tools/libxl/libxl_arm.c @@ -540,6 +540,238 @@ out: } } +static bool check_overrun(uint64_t a, uint64_t b, uint32_t max) +{ + return ((a + b) > UINT_MAX || (a + b) > max); +} + +/* Only FDT v17 is supported */ +#define FDT_REQUIRED_VERSION 0x11 + +static int check_partial_fdt(libxl__gc *gc, void *fdt, size_t size) +{ + int r; + + if (size < FDT_V17_SIZE) { + LOG(ERROR, "Partial FDT is too small"); + return ERROR_FAIL; + } + + if (fdt_magic(fdt) != FDT_MAGIC) { + LOG(ERROR, "Partial FDT is not a valid Flat Device Tree"); + return ERROR_FAIL; + } + + if (fdt_version(fdt) != FDT_REQUIRED_VERSION) { + LOG(ERROR, "Partial FDT version not supported. Required 0x%x got 0x%x", + FDT_REQUIRED_VERSION, fdt_version(fdt)); + return ERROR_FAIL; + } + + r = fdt_check_header(fdt); + if (r) { + LOG(ERROR, "Failed to check the partial FDT (%d)", r); + return ERROR_FAIL; + } + + /* Check if the *size and off* fields doesn't overrun the totalsize + * of the partial FDT. + */ + if (fdt_totalsize(fdt) > size) { + LOG(ERROR, "Partial FDT totalsize is too big"); + return ERROR_FAIL; + } + + size = fdt_totalsize(fdt); + if (fdt_off_dt_struct(fdt) > size || + fdt_off_dt_strings(fdt) > size || + check_overrun(fdt_off_dt_struct(fdt), fdt_size_dt_struct(fdt), size) || + check_overrun(fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt), size)) { + LOG(ERROR, "Failed to validate the header of the partial FDT"); + return ERROR_FAIL; + } + + return 0; +} + +/* + * Check if a string stored the strings block section is correctly + * nul-terminated. + * off_dt_strings and size_dt_strings fields have been validity-check + * earlier, so it's safe to use them here. + */ +static bool check_string(void *fdt, int nameoffset) +{ + const char *str = fdt_string(fdt, nameoffset); + + for (; nameoffset < fdt_size_dt_strings(fdt); nameoffset++, str++) { + if (*str == '\0') + return true; + } + + return false; +} + +static int copy_properties(libxl__gc *gc, void *fdt, void *pfdt, + int nodeoff) +{ + int propoff, nameoff, r; + const struct fdt_property *prop; + + for (propoff = fdt_first_property_offset(pfdt, nodeoff); + propoff >= 0; + propoff = fdt_next_property_offset(pfdt, propoff)) { + + if (!(prop = fdt_get_property_by_offset(pfdt, propoff, NULL))) { + return -FDT_ERR_INTERNAL; + } + + /* + * Libfdt doesn't perform any check on the validity of a string + * stored in the strings block section. As the property name is + * stored there, check it. + */ + nameoff = fdt32_to_cpu(prop->nameoff); + if (!check_string(pfdt, nameoff)) { + LOG(ERROR, "The strings block section of the partial FDT is malformed"); + return -FDT_ERR_BADSTRUCTURE; + } + + r = fdt_property(fdt, fdt_string(pfdt, nameoff), + prop->data, fdt32_to_cpu(prop->len)); + if (r) return r; + } + + /* FDT_ERR_NOTFOUND => There is no more properties for this node */ + return (propoff != -FDT_ERR_NOTFOUND)? propoff : 0; +} + +/* + * Based on fdt_first_subnode and fdt_next_subnode. + * We can't use the one helpers provided by libfdt because: + * - It has been introduced in 2013 => Doesn't work on wheezy + * - The prototypes exist but the functions are not exported. Don't + * ask why... + * - There is no version in the header (might be better to use + * configure for this purpose?) + */ +static int _fdt_first_subnode(const void *fdt, int offset) +{ + int depth = 0; + + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth != 1) + return -FDT_ERR_NOTFOUND; + + return offset; +} + +static int _fdt_next_subnode(const void *fdt, int offset) +{ + int depth = 1; + + /* + * With respect to the parent, the depth of the next subnode will be + * the same as the last. + */ + do { + offset = fdt_next_node(fdt, offset, &depth); + if (offset < 0 || depth < 1) + return -FDT_ERR_NOTFOUND; + } while (depth > 1); + + return offset; +} + +/* Limit the maxixum depth of a node because of the recursion */ +#define MAX_DEPTH 8 + +/* Copy a node from the partial device tree to the guest device tree */ +static int copy_node(libxl__gc *gc, void *fdt, void *pfdt, + int nodeoff, int depth) +{ + int r; + + if (depth >= MAX_DEPTH) { + LOG(ERROR, "Partial FDT contains a too depth node"); + return -FDT_ERR_INTERNAL; + } + + r = fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL)); + if (r) return r; + + r = copy_properties(gc, fdt, pfdt, nodeoff); + if (r) return r; + + for (nodeoff = _fdt_first_subnode(pfdt, nodeoff); + nodeoff >= 0; + nodeoff = _fdt_next_subnode(pfdt, nodeoff)) { + r = copy_node(gc, fdt, pfdt, nodeoff, depth + 1); + if (r) return r; + } + + if (nodeoff != -FDT_ERR_NOTFOUND) + return nodeoff; + + r = fdt_end_node(fdt); + if (r) return r; + + return 0; +} + +static int copy_node_by_path(libxl__gc *gc, const char *path, + void *fdt, void *pfdt) +{ + int nodeoff, r; + const char *name = strrchr(path, '/'); + + if (!name) + return -FDT_ERR_INTERNAL; + + name++; + + /* The FDT function to look at node doesn't take into account the + * unit (i.e anything after @) when search by name. Check if the + * name exactly match. + */ + nodeoff = fdt_path_offset(pfdt, path); + if (nodeoff < 0) + return nodeoff; + + if (strcmp(fdt_get_name(pfdt, nodeoff, NULL), name)) + return -FDT_ERR_NOTFOUND; + + r = copy_node(gc, fdt, pfdt, nodeoff, 0); + if (r) return r; + + return 0; +} + +/* + * The partial device tree is not copied entirely. Only the relevant bits are + * copied to the guest device tree: + * - /passthrough node + * - /aliases node + */ +static int copy_partial_fdt(libxl__gc *gc, void *fdt, void *pfdt) +{ + int r; + + r = copy_node_by_path(gc, "/passthrough", fdt, pfdt); + if (r < 0) { + LOG(ERROR, "Can't copy the node \"/passthrough\" from the partial FDT"); + return r; + } + + r = copy_node_by_path(gc, "/aliases", fdt, pfdt); + if (r < 0 && r != -FDT_ERR_NOTFOUND) { + LOG(ERROR, "Can't copy the node \"/aliases\" from the partial FDT"); + return r; + } + + return 0; +} + #define FDT_MAX_SIZE (1<<20) int libxl__arch_domain_init_hw_description(libxl__gc *gc, @@ -548,8 +780,10 @@ int libxl__arch_domain_init_hw_description(libxl__gc *gc, struct xc_dom_image *dom) { void *fdt = NULL; + void *pfdt = NULL; int rc, res; size_t fdt_size = 0; + int pfdt_size = 0; const libxl_version_info *vers; const struct arch_info *ainfo; @@ -569,6 +803,22 @@ int libxl__arch_domain_init_hw_description(libxl__gc *gc, vers->xen_version_major, vers->xen_version_minor); LOG(DEBUG, " - vGIC version: %s\n", gicv_to_string(xc_config->gic_version)); + if (info->device_tree) { + LOG(DEBUG, " - Partial device tree provided: %s", info->device_tree); + + rc = libxl_read_file_contents(CTX, info->device_tree, + &pfdt, &pfdt_size); + if (rc) { + LOGEV(ERROR, rc, "failed to read the partial device file %s", + info->device_tree); + return ERROR_FAIL; + } + libxl__ptr_add(gc, pfdt); + + if (check_partial_fdt(gc, pfdt, pfdt_size)) + return ERROR_FAIL; + } + /* * Call "call" handling FDT_ERR_*. Will either: * - loop back to retry_resize @@ -635,6 +885,9 @@ next_resize: FDT( make_timer_node(gc, fdt, ainfo) ); FDT( make_hypervisor_node(gc, fdt, vers) ); + if (pfdt) + FDT( copy_partial_fdt(gc, fdt, pfdt) ); + FDT( fdt_end_node(fdt) ); FDT( fdt_finish(fdt) ); diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 1214d2e..5651110 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -399,6 +399,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("kernel", string), ("cmdline", string), ("ramdisk", string), + ("device_tree", string), ("u", KeyedUnion(None, libxl_domain_type, "type", [("hvm", Struct(None, [("firmware", string), ("bios", libxl_bios_type), diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 0b02a6c..31e89e8 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -1184,6 +1184,7 @@ static void parse_config_data(const char *config_source, xlu_cfg_replace_string (config, "kernel", &b_info->kernel, 0); xlu_cfg_replace_string (config, "ramdisk", &b_info->ramdisk, 0); + xlu_cfg_replace_string (config, "device_tree", &b_info->device_tree, 0); b_info->cmdline = parse_cmdline(config); xlu_cfg_get_defbool(config, "driver_domain", &c_info->driver_domain, 0); -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |