[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 21/24] tools/(lib)xl: Add partial device tree support for ARM
On Tue, 13 Jan 2015, Julien Grall wrote: > 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 */ > } > }; It would be nice to have an example of this under tools/examples. > 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; > +} strnlen? > +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; Are we sure that the string returned by fdt_get_name is NULL terminated? > + 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 |