diff --git a/Makefile b/Makefile index 6039720bfb..68fecb4bac 100644 --- a/Makefile +++ b/Makefile @@ -512,7 +512,7 @@ dt_h := include/generated/dt.h no-dot-config-targets := clean clobber mrproper distclean \ help %docs check% coccicheck \ - ubootversion backup tests check qcheck + ubootversion backup tests check qcheck tcheck config-targets := 0 mixed-targets := 0 @@ -2113,6 +2113,7 @@ help: @echo '' @echo ' check - Run all automated tests that use sandbox' @echo ' qcheck - Run quick automated tests that use sandbox' + @echo ' tcheck - Run quick automated tests on tools' @echo '' @echo 'Other generic targets:' @echo ' all - Build all necessary images depending on configuration' @@ -2158,6 +2159,9 @@ tests check: qcheck: $(srctree)/test/run quick +tcheck: + $(srctree)/test/run tools + # Documentation targets # --------------------------------------------------------------------------- DOC_TARGETS := xmldocs latexdocs pdfdocs htmldocs epubdocs cleandocs \ diff --git a/common/Makefile b/common/Makefile index 3471c47be5..2e7a090588 100644 --- a/common/Makefile +++ b/common/Makefile @@ -110,6 +110,7 @@ obj-y += image.o obj-$(CONFIG_ANDROID_AB) += android_ab.o obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o +obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o obj-$(CONFIG_$(SPL_TPL_)IMAGE_SIGN_INFO) += image-sig.o diff --git a/lib/libfdt/fdt_region.c b/common/fdt_region.c similarity index 99% rename from lib/libfdt/fdt_region.c rename to common/fdt_region.c index 7e9fa9272e..bf0a9be730 100644 --- a/lib/libfdt/fdt_region.c +++ b/common/fdt_region.c @@ -6,6 +6,7 @@ */ #include +#include #ifndef USE_HOSTCC #include diff --git a/common/image-fit-sig.c b/common/image-fit-sig.c index 490566ca90..3e73578594 100644 --- a/common/image-fit-sig.c +++ b/common/image-fit-sig.c @@ -11,6 +11,7 @@ #include DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ +#include #include #include #include diff --git a/common/log.c b/common/log.c index ffb3cd6933..c5b9b489ca 100644 --- a/common/log.c +++ b/common/log.c @@ -233,7 +233,7 @@ int log_add_filter(const char *drv_name, enum log_category_t cat_list[], ldev = log_device_find_by_name(drv_name); if (!ldev) return -ENOENT; - filt = (struct log_filter *)calloc(1, sizeof(*filt)); + filt = calloc(1, sizeof(*filt)); if (!filt) return -ENOMEM; diff --git a/include/fdt_region.h b/include/fdt_region.h new file mode 100644 index 0000000000..ff7a1ccb9a --- /dev/null +++ b/include/fdt_region.h @@ -0,0 +1,304 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _FDT_REGION_H +#define _FDT_REGION_H + +#ifndef SWIG /* Not available in Python */ +struct fdt_region { + int offset; + int size; +}; + +/* + * Flags for fdt_find_regions() + * + * Add a region for the string table (always the last region) + */ +#define FDT_REG_ADD_STRING_TAB (1 << 0) + +/* + * Add all supernodes of a matching node/property, useful for creating a + * valid subset tree + */ +#define FDT_REG_SUPERNODES (1 << 1) + +/* Add the FDT_BEGIN_NODE tags of subnodes, including their names */ +#define FDT_REG_DIRECT_SUBNODES (1 << 2) + +/* Add all subnodes of a matching node */ +#define FDT_REG_ALL_SUBNODES (1 << 3) + +/* Add a region for the mem_rsvmap table (always the first region) */ +#define FDT_REG_ADD_MEM_RSVMAP (1 << 4) + +/* Indicates what an fdt part is (node, property, value) */ +#define FDT_IS_NODE (1 << 0) +#define FDT_IS_PROP (1 << 1) +#define FDT_IS_VALUE (1 << 2) /* not supported */ +#define FDT_IS_COMPAT (1 << 3) /* used internally */ +#define FDT_NODE_HAS_PROP (1 << 4) /* node contains prop */ + +#define FDT_ANY_GLOBAL (FDT_IS_NODE | FDT_IS_PROP | FDT_IS_VALUE | \ + FDT_IS_COMPAT) +#define FDT_IS_ANY 0x1f /* all the above */ + +/* We set a reasonable limit on the number of nested nodes */ +#define FDT_MAX_DEPTH 32 + +/* Decribes what we want to include from the current tag */ +enum want_t { + WANT_NOTHING, + WANT_NODES_ONLY, /* No properties */ + WANT_NODES_AND_PROPS, /* Everything for one level */ + WANT_ALL_NODES_AND_PROPS /* Everything for all levels */ +}; + +/* Keeps track of the state at parent nodes */ +struct fdt_subnode_stack { + int offset; /* Offset of node */ + enum want_t want; /* The 'want' value here */ + int included; /* 1 if we included this node, 0 if not */ +}; + +struct fdt_region_ptrs { + int depth; /* Current tree depth */ + int done; /* What we have completed scanning */ + enum want_t want; /* What we are currently including */ + char *end; /* Pointer to end of full node path */ + int nextoffset; /* Next node offset to check */ +}; + +/* The state of our finding algortihm */ +struct fdt_region_state { + struct fdt_subnode_stack stack[FDT_MAX_DEPTH]; /* node stack */ + struct fdt_region *region; /* Contains list of regions found */ + int count; /* Numnber of regions found */ + const void *fdt; /* FDT blob */ + int max_regions; /* Maximum regions to find */ + int can_merge; /* 1 if we can merge with previous region */ + int start; /* Start position of current region */ + struct fdt_region_ptrs ptrs; /* Pointers for what we are up to */ +}; + +/** + * fdt_find_regions() - find regions in device tree + * + * Given a list of nodes to include and properties to exclude, find + * the regions of the device tree which describe those included parts. + * + * The intent is to get a list of regions which will be invariant provided + * those parts are invariant. For example, if you request a list of regions + * for all nodes but exclude the property "data", then you will get the + * same region contents regardless of any change to "data" properties. + * + * This function can be used to produce a byte-stream to send to a hashing + * function to verify that critical parts of the FDT have not changed. + * + * Nodes which are given in 'inc' are included in the region list, as + * are the names of the immediate subnodes nodes (but not the properties + * or subnodes of those subnodes). + * + * For eaxample "/" means to include the root node, all root properties + * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter + * ensures that we capture the names of the subnodes. In a hashing situation + * it prevents the root node from changing at all Any change to non-excluded + * properties, names of subnodes or number of subnodes would be detected. + * + * When used with FITs this provides the ability to hash and sign parts of + * the FIT based on different configurations in the FIT. Then it is + * impossible to change anything about that configuration (include images + * attached to the configuration), but it may be possible to add new + * configurations, new images or new signatures within the existing + * framework. + * + * Adding new properties to a device tree may result in the string table + * being extended (if the new property names are different from those + * already added). This function can optionally include a region for + * the string table so that this can be part of the hash too. + * + * The device tree header is not included in the list. + * + * @fdt: Device tree to check + * @inc: List of node paths to included + * @inc_count: Number of node paths in list + * @exc_prop: List of properties names to exclude + * @exc_prop_count: Number of properties in exclude list + * @region: Returns list of regions + * @max_region: Maximum length of region list + * @path: Pointer to a temporary string for the function to use for + * building path names + * @path_len: Length of path, must be large enough to hold the longest + * path in the tree + * @add_string_tab: 1 to add a region for the string table + * @return number of regions in list. If this is >max_regions then the + * region array was exhausted. You should increase max_regions and try + * the call again. + */ +int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, + char * const exc_prop[], int exc_prop_count, + struct fdt_region region[], int max_regions, + char *path, int path_len, int add_string_tab); + +/** + * fdt_first_region() - find regions in device tree + * + * Given a nodes and properties to include and properties to exclude, find + * the regions of the device tree which describe those included parts. + * + * The use for this function is twofold. Firstly it provides a convenient + * way of performing a structure-aware grep of the tree. For example it is + * possible to grep for a node and get all the properties associated with + * that node. Trees can be subsetted easily, by specifying the nodes that + * are required, and then writing out the regions returned by this function. + * This is useful for small resource-constrained systems, such as boot + * loaders, which want to use an FDT but do not need to know about all of + * it. + * + * Secondly it makes it easy to hash parts of the tree and detect changes. + * The intent is to get a list of regions which will be invariant provided + * those parts are invariant. For example, if you request a list of regions + * for all nodes but exclude the property "data", then you will get the + * same region contents regardless of any change to "data" properties. + * + * This function can be used to produce a byte-stream to send to a hashing + * function to verify that critical parts of the FDT have not changed. + * Note that semantically null changes in order could still cause false + * hash misses. Such reordering might happen if the tree is regenerated + * from source, and nodes are reordered (the bytes-stream will be emitted + * in a different order and many hash functions will detect this). However + * if an existing tree is modified using libfdt functions, such as + * fdt_add_subnode() and fdt_setprop(), then this problem is avoided. + * + * The nodes/properties to include/exclude are defined by a function + * provided by the caller. This function is called for each node and + * property, and must return: + * + * 0 - to exclude this part + * 1 - to include this part + * -1 - for FDT_IS_PROP only: no information is available, so include + * if its containing node is included + * + * The last case is only used to deal with properties. Often a property is + * included if its containing node is included - this is the case where + * -1 is returned.. However if the property is specifically required to be + * included/excluded, then 0 or 1 can be returned. Note that including a + * property when the FDT_REG_SUPERNODES flag is given will force its + * containing node to be included since it is not valid to have a property + * that is not in a node. + * + * Using the information provided, the inclusion of a node can be controlled + * either by a node name or its compatible string, or any other property + * that the function can determine. + * + * As an example, including node "/" means to include the root node and all + * root properties. A flag provides a way of also including supernodes (of + * which there is none for the root node), and another flag includes + * immediate subnodes, so in this case we would get the FDT_BEGIN_NODE and + * FDT_END_NODE of all subnodes of /. + * + * The subnode feature helps in a hashing situation since it prevents the + * root node from changing at all. Any change to non-excluded properties, + * names of subnodes or number of subnodes would be detected. + * + * When used with FITs this provides the ability to hash and sign parts of + * the FIT based on different configurations in the FIT. Then it is + * impossible to change anything about that configuration (include images + * attached to the configuration), but it may be possible to add new + * configurations, new images or new signatures within the existing + * framework. + * + * Adding new properties to a device tree may result in the string table + * being extended (if the new property names are different from those + * already added). This function can optionally include a region for + * the string table so that this can be part of the hash too. This is always + * the last region. + * + * The FDT also has a mem_rsvmap table which can also be included, and is + * always the first region if so. + * + * The device tree header is not included in the region list. Since the + * contents of the FDT are changing (shrinking, often), the caller will need + * to regenerate the header anyway. + * + * @fdt: Device tree to check + * @h_include: Function to call to determine whether to include a part or + * not: + * + * @priv: Private pointer as passed to fdt_find_regions() + * @fdt: Pointer to FDT blob + * @offset: Offset of this node / property + * @type: Type of this part, FDT_IS_... + * @data: Pointer to data (node name, property name, compatible + * string, value (not yet supported) + * @size: Size of data, or 0 if none + * @return 0 to exclude, 1 to include, -1 if no information is + * available + * @priv: Private pointer passed to h_include + * @region: Returns list of regions, sorted by offset + * @max_regions: Maximum length of region list + * @path: Pointer to a temporary string for the function to use for + * building path names + * @path_len: Length of path, must be large enough to hold the longest + * path in the tree + * @flags: Various flags that control the region algortihm, see + * FDT_REG_... + * @return number of regions in list. If this is >max_regions then the + * region array was exhausted. You should increase max_regions and try + * the call again. Only the first max_regions elements are available in the + * array. + * + * On error a -ve value is return, which can be: + * + * -FDT_ERR_BADSTRUCTURE (too deep or more END tags than BEGIN tags + * -FDT_ERR_BADLAYOUT + * -FDT_ERR_NOSPACE (path area is too small) + */ +int fdt_first_region(const void *fdt, + int (*h_include)(void *priv, const void *fdt, int offset, + int type, const char *data, int size), + void *priv, struct fdt_region *region, + char *path, int path_len, int flags, + struct fdt_region_state *info); + +/** fdt_next_region() - find next region + * + * See fdt_first_region() for full description. This function finds the + * next region according to the provided parameters, which must be the same + * as passed to fdt_first_region(). + * + * This function can additionally return -FDT_ERR_NOTFOUND when there are no + * more regions + */ +int fdt_next_region(const void *fdt, + int (*h_include)(void *priv, const void *fdt, int offset, + int type, const char *data, int size), + void *priv, struct fdt_region *region, + char *path, int path_len, int flags, + struct fdt_region_state *info); + +/** + * fdt_add_alias_regions() - find aliases that point to existing regions + * + * Once a device tree grep is complete some of the nodes will be present + * and some will have been dropped. This function checks all the alias nodes + * to figure out which points point to nodes which are still present. These + * aliases need to be kept, along with the nodes they reference. + * + * Given a list of regions function finds the aliases that still apply and + * adds more regions to the list for these. This function is called after + * fdt_next_region() has finished returning regions and requires the same + * state. + * + * @fdt: Device tree file to reference + * @region: List of regions that will be kept + * @count: Number of regions + * @max_regions: Number of entries that can fit in @region + * @info: Region state as returned from fdt_next_region() + * @return new number of regions in @region (i.e. count + the number added) + * or -FDT_ERR_NOSPACE if there was not enough space. + */ +int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count, + int max_regions, struct fdt_region_state *info); +#endif /* SWIG */ + +#endif /* _FDT_REGION_H */ diff --git a/include/linux/libfdt.h b/include/linux/libfdt.h index eeb2344971..39dbc88aa5 100644 --- a/include/linux/libfdt.h +++ b/include/linux/libfdt.h @@ -8,305 +8,6 @@ #include "../../scripts/dtc/libfdt/libfdt.h" /* U-Boot local hacks */ - -#ifndef SWIG /* Not available in Python */ -struct fdt_region { - int offset; - int size; -}; - -/* - * Flags for fdt_find_regions() - * - * Add a region for the string table (always the last region) - */ -#define FDT_REG_ADD_STRING_TAB (1 << 0) - -/* - * Add all supernodes of a matching node/property, useful for creating a - * valid subset tree - */ -#define FDT_REG_SUPERNODES (1 << 1) - -/* Add the FDT_BEGIN_NODE tags of subnodes, including their names */ -#define FDT_REG_DIRECT_SUBNODES (1 << 2) - -/* Add all subnodes of a matching node */ -#define FDT_REG_ALL_SUBNODES (1 << 3) - -/* Add a region for the mem_rsvmap table (always the first region) */ -#define FDT_REG_ADD_MEM_RSVMAP (1 << 4) - -/* Indicates what an fdt part is (node, property, value) */ -#define FDT_IS_NODE (1 << 0) -#define FDT_IS_PROP (1 << 1) -#define FDT_IS_VALUE (1 << 2) /* not supported */ -#define FDT_IS_COMPAT (1 << 3) /* used internally */ -#define FDT_NODE_HAS_PROP (1 << 4) /* node contains prop */ - -#define FDT_ANY_GLOBAL (FDT_IS_NODE | FDT_IS_PROP | FDT_IS_VALUE | \ - FDT_IS_COMPAT) -#define FDT_IS_ANY 0x1f /* all the above */ - -/* We set a reasonable limit on the number of nested nodes */ -#define FDT_MAX_DEPTH 32 - -/* Decribes what we want to include from the current tag */ -enum want_t { - WANT_NOTHING, - WANT_NODES_ONLY, /* No properties */ - WANT_NODES_AND_PROPS, /* Everything for one level */ - WANT_ALL_NODES_AND_PROPS /* Everything for all levels */ -}; - -/* Keeps track of the state at parent nodes */ -struct fdt_subnode_stack { - int offset; /* Offset of node */ - enum want_t want; /* The 'want' value here */ - int included; /* 1 if we included this node, 0 if not */ -}; - -struct fdt_region_ptrs { - int depth; /* Current tree depth */ - int done; /* What we have completed scanning */ - enum want_t want; /* What we are currently including */ - char *end; /* Pointer to end of full node path */ - int nextoffset; /* Next node offset to check */ -}; - -/* The state of our finding algortihm */ -struct fdt_region_state { - struct fdt_subnode_stack stack[FDT_MAX_DEPTH]; /* node stack */ - struct fdt_region *region; /* Contains list of regions found */ - int count; /* Numnber of regions found */ - const void *fdt; /* FDT blob */ - int max_regions; /* Maximum regions to find */ - int can_merge; /* 1 if we can merge with previous region */ - int start; /* Start position of current region */ - struct fdt_region_ptrs ptrs; /* Pointers for what we are up to */ -}; - -/** - * fdt_find_regions() - find regions in device tree - * - * Given a list of nodes to include and properties to exclude, find - * the regions of the device tree which describe those included parts. - * - * The intent is to get a list of regions which will be invariant provided - * those parts are invariant. For example, if you request a list of regions - * for all nodes but exclude the property "data", then you will get the - * same region contents regardless of any change to "data" properties. - * - * This function can be used to produce a byte-stream to send to a hashing - * function to verify that critical parts of the FDT have not changed. - * - * Nodes which are given in 'inc' are included in the region list, as - * are the names of the immediate subnodes nodes (but not the properties - * or subnodes of those subnodes). - * - * For eaxample "/" means to include the root node, all root properties - * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter - * ensures that we capture the names of the subnodes. In a hashing situation - * it prevents the root node from changing at all Any change to non-excluded - * properties, names of subnodes or number of subnodes would be detected. - * - * When used with FITs this provides the ability to hash and sign parts of - * the FIT based on different configurations in the FIT. Then it is - * impossible to change anything about that configuration (include images - * attached to the configuration), but it may be possible to add new - * configurations, new images or new signatures within the existing - * framework. - * - * Adding new properties to a device tree may result in the string table - * being extended (if the new property names are different from those - * already added). This function can optionally include a region for - * the string table so that this can be part of the hash too. - * - * The device tree header is not included in the list. - * - * @fdt: Device tree to check - * @inc: List of node paths to included - * @inc_count: Number of node paths in list - * @exc_prop: List of properties names to exclude - * @exc_prop_count: Number of properties in exclude list - * @region: Returns list of regions - * @max_region: Maximum length of region list - * @path: Pointer to a temporary string for the function to use for - * building path names - * @path_len: Length of path, must be large enough to hold the longest - * path in the tree - * @add_string_tab: 1 to add a region for the string table - * @return number of regions in list. If this is >max_regions then the - * region array was exhausted. You should increase max_regions and try - * the call again. - */ -int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, - char * const exc_prop[], int exc_prop_count, - struct fdt_region region[], int max_regions, - char *path, int path_len, int add_string_tab); - -/** - * fdt_first_region() - find regions in device tree - * - * Given a nodes and properties to include and properties to exclude, find - * the regions of the device tree which describe those included parts. - * - * The use for this function is twofold. Firstly it provides a convenient - * way of performing a structure-aware grep of the tree. For example it is - * possible to grep for a node and get all the properties associated with - * that node. Trees can be subsetted easily, by specifying the nodes that - * are required, and then writing out the regions returned by this function. - * This is useful for small resource-constrained systems, such as boot - * loaders, which want to use an FDT but do not need to know about all of - * it. - * - * Secondly it makes it easy to hash parts of the tree and detect changes. - * The intent is to get a list of regions which will be invariant provided - * those parts are invariant. For example, if you request a list of regions - * for all nodes but exclude the property "data", then you will get the - * same region contents regardless of any change to "data" properties. - * - * This function can be used to produce a byte-stream to send to a hashing - * function to verify that critical parts of the FDT have not changed. - * Note that semantically null changes in order could still cause false - * hash misses. Such reordering might happen if the tree is regenerated - * from source, and nodes are reordered (the bytes-stream will be emitted - * in a different order and many hash functions will detect this). However - * if an existing tree is modified using libfdt functions, such as - * fdt_add_subnode() and fdt_setprop(), then this problem is avoided. - * - * The nodes/properties to include/exclude are defined by a function - * provided by the caller. This function is called for each node and - * property, and must return: - * - * 0 - to exclude this part - * 1 - to include this part - * -1 - for FDT_IS_PROP only: no information is available, so include - * if its containing node is included - * - * The last case is only used to deal with properties. Often a property is - * included if its containing node is included - this is the case where - * -1 is returned.. However if the property is specifically required to be - * included/excluded, then 0 or 1 can be returned. Note that including a - * property when the FDT_REG_SUPERNODES flag is given will force its - * containing node to be included since it is not valid to have a property - * that is not in a node. - * - * Using the information provided, the inclusion of a node can be controlled - * either by a node name or its compatible string, or any other property - * that the function can determine. - * - * As an example, including node "/" means to include the root node and all - * root properties. A flag provides a way of also including supernodes (of - * which there is none for the root node), and another flag includes - * immediate subnodes, so in this case we would get the FDT_BEGIN_NODE and - * FDT_END_NODE of all subnodes of /. - * - * The subnode feature helps in a hashing situation since it prevents the - * root node from changing at all. Any change to non-excluded properties, - * names of subnodes or number of subnodes would be detected. - * - * When used with FITs this provides the ability to hash and sign parts of - * the FIT based on different configurations in the FIT. Then it is - * impossible to change anything about that configuration (include images - * attached to the configuration), but it may be possible to add new - * configurations, new images or new signatures within the existing - * framework. - * - * Adding new properties to a device tree may result in the string table - * being extended (if the new property names are different from those - * already added). This function can optionally include a region for - * the string table so that this can be part of the hash too. This is always - * the last region. - * - * The FDT also has a mem_rsvmap table which can also be included, and is - * always the first region if so. - * - * The device tree header is not included in the region list. Since the - * contents of the FDT are changing (shrinking, often), the caller will need - * to regenerate the header anyway. - * - * @fdt: Device tree to check - * @h_include: Function to call to determine whether to include a part or - * not: - * - * @priv: Private pointer as passed to fdt_find_regions() - * @fdt: Pointer to FDT blob - * @offset: Offset of this node / property - * @type: Type of this part, FDT_IS_... - * @data: Pointer to data (node name, property name, compatible - * string, value (not yet supported) - * @size: Size of data, or 0 if none - * @return 0 to exclude, 1 to include, -1 if no information is - * available - * @priv: Private pointer passed to h_include - * @region: Returns list of regions, sorted by offset - * @max_regions: Maximum length of region list - * @path: Pointer to a temporary string for the function to use for - * building path names - * @path_len: Length of path, must be large enough to hold the longest - * path in the tree - * @flags: Various flags that control the region algortihm, see - * FDT_REG_... - * @return number of regions in list. If this is >max_regions then the - * region array was exhausted. You should increase max_regions and try - * the call again. Only the first max_regions elements are available in the - * array. - * - * On error a -ve value is return, which can be: - * - * -FDT_ERR_BADSTRUCTURE (too deep or more END tags than BEGIN tags - * -FDT_ERR_BADLAYOUT - * -FDT_ERR_NOSPACE (path area is too small) - */ -int fdt_first_region(const void *fdt, - int (*h_include)(void *priv, const void *fdt, int offset, - int type, const char *data, int size), - void *priv, struct fdt_region *region, - char *path, int path_len, int flags, - struct fdt_region_state *info); - -/** fdt_next_region() - find next region - * - * See fdt_first_region() for full description. This function finds the - * next region according to the provided parameters, which must be the same - * as passed to fdt_first_region(). - * - * This function can additionally return -FDT_ERR_NOTFOUND when there are no - * more regions - */ -int fdt_next_region(const void *fdt, - int (*h_include)(void *priv, const void *fdt, int offset, - int type, const char *data, int size), - void *priv, struct fdt_region *region, - char *path, int path_len, int flags, - struct fdt_region_state *info); - -/** - * fdt_add_alias_regions() - find aliases that point to existing regions - * - * Once a device tree grep is complete some of the nodes will be present - * and some will have been dropped. This function checks all the alias nodes - * to figure out which points point to nodes which are still present. These - * aliases need to be kept, along with the nodes they reference. - * - * Given a list of regions function finds the aliases that still apply and - * adds more regions to the list for these. This function is called after - * fdt_next_region() has finished returning regions and requires the same - * state. - * - * @fdt: Device tree file to reference - * @region: List of regions that will be kept - * @count: Number of regions - * @max_regions: Number of entries that can fit in @region - * @info: Region state as returned from fdt_next_region() - * @return new number of regions in @region (i.e. count + the number added) - * or -FDT_ERR_NOSPACE if there was not enough space. - */ -int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count, - int max_regions, struct fdt_region_state *info); -#endif /* SWIG */ - extern struct fdt_header *working_fdt; /* Pointer to the working fdt */ #endif /* _INCLUDE_LIBFDT_H_ */ diff --git a/lib/libfdt/Makefile b/lib/libfdt/Makefile index 5d3ae4e2f1..1fe50ecbe5 100644 --- a/lib/libfdt/Makefile +++ b/lib/libfdt/Makefile @@ -3,9 +3,9 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. -# Use upstream code. obj-y += \ fdt.o \ + fdt_ro.o \ fdt_wip.o \ fdt_strerror.o \ fdt_sw.o \ @@ -15,12 +15,5 @@ obj-y += \ obj-$(CONFIG_OF_LIBFDT_OVERLAY) += fdt_overlay.o -# Locally modified for U-Boot. -# TODO: split out the local modifiction. -obj-y += fdt_ro.o - -# U-Boot own file -obj-y += fdt_region.o - ccflags-y := -I$(srctree)/scripts/dtc/libfdt \ -DFDT_ASSUME_MASK=$(CONFIG_$(SPL_TPL_)OF_LIBFDT_ASSUME_MASK) diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c index be03aea9eb..7ede074537 100644 --- a/lib/libfdt/fdt_ro.c +++ b/lib/libfdt/fdt_ro.c @@ -1,925 +1,2 @@ -// SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause -/* - * libfdt - Flat Device Tree manipulation - * Copyright (C) 2006 David Gibson, IBM Corporation. - */ #include - -#ifndef USE_HOSTCC -#include -#include -#else -#include "fdt_host.h" -#endif - -#include "libfdt_internal.h" - -static int fdt_nodename_eq_(const void *fdt, int offset, - const char *s, int len) -{ - int olen; - const char *p = fdt_get_name(fdt, offset, &olen); - - if (!p || (fdt_chk_extra() && olen < len)) - /* short match */ - return 0; - - if (memcmp(p, s, len) != 0) - return 0; - - if (p[len] == '\0') - return 1; - else if (!memchr(s, '@', len) && (p[len] == '@')) - return 1; - else - return 0; -} - -const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) -{ - int32_t totalsize; - uint32_t absoffset; - size_t len; - int err; - const char *s, *n; - - if (!fdt_chk_extra()) { - s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; - - if (lenp) - *lenp = strlen(s); - return s; - } - totalsize = fdt_ro_probe_(fdt); - err = totalsize; - if (totalsize < 0) - goto fail; - - err = -FDT_ERR_BADOFFSET; - absoffset = stroffset + fdt_off_dt_strings(fdt); - if (absoffset >= totalsize) - goto fail; - len = totalsize - absoffset; - - if (fdt_magic(fdt) == FDT_MAGIC) { - if (stroffset < 0) - goto fail; - if (!fdt_chk_version() || fdt_version(fdt) >= 17) { - if (stroffset >= fdt_size_dt_strings(fdt)) - goto fail; - if ((fdt_size_dt_strings(fdt) - stroffset) < len) - len = fdt_size_dt_strings(fdt) - stroffset; - } - } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - if ((stroffset >= 0) - || (stroffset < -fdt_size_dt_strings(fdt))) - goto fail; - if ((-stroffset) < len) - len = -stroffset; - } else { - err = -FDT_ERR_INTERNAL; - goto fail; - } - - s = (const char *)fdt + absoffset; - n = memchr(s, '\0', len); - if (!n) { - /* missing terminating NULL */ - err = -FDT_ERR_TRUNCATED; - goto fail; - } - - if (lenp) - *lenp = n - s; - return s; - -fail: - if (lenp) - *lenp = err; - return NULL; -} - -const char *fdt_string(const void *fdt, int stroffset) -{ - return fdt_get_string(fdt, stroffset, NULL); -} - -static int fdt_string_eq_(const void *fdt, int stroffset, - const char *s, int len) -{ - int slen; - const char *p = fdt_get_string(fdt, stroffset, &slen); - - return p && (slen == len) && (memcmp(p, s, len) == 0); -} - -int fdt_find_max_phandle(const void *fdt, uint32_t *phandle) -{ - uint32_t max = 0; - int offset = -1; - - while (true) { - uint32_t value; - - offset = fdt_next_node(fdt, offset, NULL); - if (offset < 0) { - if (offset == -FDT_ERR_NOTFOUND) - break; - - return offset; - } - - value = fdt_get_phandle(fdt, offset); - - if (value > max) - max = value; - } - - if (phandle) - *phandle = max; - - return 0; -} - -int fdt_generate_phandle(const void *fdt, uint32_t *phandle) -{ - uint32_t max; - int err; - - err = fdt_find_max_phandle(fdt, &max); - if (err < 0) - return err; - - if (max == FDT_MAX_PHANDLE) - return -FDT_ERR_NOPHANDLES; - - if (phandle) - *phandle = max + 1; - - return 0; -} - -static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) -{ - int offset = n * sizeof(struct fdt_reserve_entry); - int absoffset = fdt_off_mem_rsvmap(fdt) + offset; - - if (fdt_chk_extra()) { - if (absoffset < fdt_off_mem_rsvmap(fdt)) - return NULL; - if (absoffset > fdt_totalsize(fdt) - - sizeof(struct fdt_reserve_entry)) - return NULL; - } - return fdt_mem_rsv_(fdt, n); -} - -int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) -{ - const struct fdt_reserve_entry *re; - - FDT_RO_PROBE(fdt); - re = fdt_mem_rsv(fdt, n); - if (fdt_chk_extra() && !re) - return -FDT_ERR_BADOFFSET; - - *address = fdt64_to_cpu(re->address); - *size = fdt64_to_cpu(re->size); - return 0; -} - -int fdt_num_mem_rsv(const void *fdt) -{ - int i; - const struct fdt_reserve_entry *re; - - for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { - if (fdt64_to_cpu(re->size) == 0) - return i; - } - return -FDT_ERR_TRUNCATED; -} - -static int nextprop_(const void *fdt, int offset) -{ - uint32_t tag; - int nextoffset; - - do { - tag = fdt_next_tag(fdt, offset, &nextoffset); - - switch (tag) { - case FDT_END: - if (nextoffset >= 0) - return -FDT_ERR_BADSTRUCTURE; - else - return nextoffset; - - case FDT_PROP: - return offset; - } - offset = nextoffset; - } while (tag == FDT_NOP); - - return -FDT_ERR_NOTFOUND; -} - -int fdt_subnode_offset_namelen(const void *fdt, int offset, - const char *name, int namelen) -{ - int depth; - - FDT_RO_PROBE(fdt); - - for (depth = 0; - (offset >= 0) && (depth >= 0); - offset = fdt_next_node(fdt, offset, &depth)) - if ((depth == 1) - && fdt_nodename_eq_(fdt, offset, name, namelen)) - return offset; - - if (depth < 0) - return -FDT_ERR_NOTFOUND; - return offset; /* error */ -} - -int fdt_subnode_offset(const void *fdt, int parentoffset, - const char *name) -{ - return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); -} - -int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) -{ - const char *end = path + namelen; - const char *p = path; - int offset = 0; - - FDT_RO_PROBE(fdt); - - /* see if we have an alias */ - if (*path != '/') { - const char *q = memchr(path, '/', end - p); - - if (!q) - q = end; - - p = fdt_get_alias_namelen(fdt, p, q - p); - if (!p) - return -FDT_ERR_BADPATH; - offset = fdt_path_offset(fdt, p); - - p = q; - } - - while (p < end) { - const char *q; - - while (*p == '/') { - p++; - if (p == end) - return offset; - } - q = memchr(p, '/', end - p); - if (! q) - q = end; - - offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); - if (offset < 0) - return offset; - - p = q; - } - - return offset; -} - -int fdt_path_offset(const void *fdt, const char *path) -{ - return fdt_path_offset_namelen(fdt, path, strlen(path)); -} - -const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) -{ - const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); - const char *nameptr; - int err; - - if (fdt_chk_extra() && - (((err = fdt_ro_probe_(fdt)) < 0) - || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))) - goto fail; - - nameptr = nh->name; - - if (fdt_chk_version() && fdt_version(fdt) < 0x10) { - /* - * For old FDT versions, match the naming conventions of V16: - * give only the leaf name (after all /). The actual tree - * contents are loosely checked. - */ - const char *leaf; - leaf = strrchr(nameptr, '/'); - if (leaf == NULL) { - err = -FDT_ERR_BADSTRUCTURE; - goto fail; - } - nameptr = leaf+1; - } - - if (len) - *len = strlen(nameptr); - - return nameptr; - - fail: - if (len) - *len = err; - return NULL; -} - -int fdt_first_property_offset(const void *fdt, int nodeoffset) -{ - int offset; - - if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) - return offset; - - return nextprop_(fdt, offset); -} - -int fdt_next_property_offset(const void *fdt, int offset) -{ - if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) - return offset; - - return nextprop_(fdt, offset); -} - -static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, - int offset, - int *lenp) -{ - int err; - const struct fdt_property *prop; - - if (fdt_chk_basic() && (err = fdt_check_prop_offset_(fdt, offset)) < 0) { - if (lenp) - *lenp = err; - return NULL; - } - - prop = fdt_offset_ptr_(fdt, offset); - - if (lenp) - *lenp = fdt32_to_cpu(prop->len); - - return prop; -} - -const struct fdt_property *fdt_get_property_by_offset(const void *fdt, - int offset, - int *lenp) -{ - /* Prior to version 16, properties may need realignment - * and this API does not work. fdt_getprop_*() will, however. */ - - if (fdt_chk_version() && fdt_version(fdt) < 0x10) { - if (lenp) - *lenp = -FDT_ERR_BADVERSION; - return NULL; - } - - return fdt_get_property_by_offset_(fdt, offset, lenp); -} - -static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, - int offset, - const char *name, - int namelen, - int *lenp, - int *poffset) -{ - for (offset = fdt_first_property_offset(fdt, offset); - (offset >= 0); - (offset = fdt_next_property_offset(fdt, offset))) { - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset_(fdt, offset, lenp); - if (fdt_chk_extra() && !prop) { - offset = -FDT_ERR_INTERNAL; - break; - } - if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), - name, namelen)) { - if (poffset) - *poffset = offset; - return prop; - } - } - - if (lenp) - *lenp = offset; - return NULL; -} - - -const struct fdt_property *fdt_get_property_namelen(const void *fdt, - int offset, - const char *name, - int namelen, int *lenp) -{ - /* Prior to version 16, properties may need realignment - * and this API does not work. fdt_getprop_*() will, however. */ - if (fdt_chk_version() && fdt_version(fdt) < 0x10) { - if (lenp) - *lenp = -FDT_ERR_BADVERSION; - return NULL; - } - - return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, - NULL); -} - - -const struct fdt_property *fdt_get_property(const void *fdt, - int nodeoffset, - const char *name, int *lenp) -{ - return fdt_get_property_namelen(fdt, nodeoffset, name, - strlen(name), lenp); -} - -const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, - const char *name, int namelen, int *lenp) -{ - int poffset; - const struct fdt_property *prop; - - prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, - &poffset); - if (!prop) - return NULL; - - /* Handle realignment */ - if (fdt_chk_version() && fdt_version(fdt) < 0x10 && - (poffset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8) - return prop->data + 4; - return prop->data; -} - -const void *fdt_getprop_by_offset(const void *fdt, int offset, - const char **namep, int *lenp) -{ - const struct fdt_property *prop; - - prop = fdt_get_property_by_offset_(fdt, offset, lenp); - if (!prop) - return NULL; - if (namep) { - const char *name; - int namelen; - - if (fdt_chk_extra()) { - name = fdt_get_string(fdt, fdt32_to_cpu(prop->nameoff), - &namelen); - if (!name) { - if (lenp) - *lenp = namelen; - return NULL; - } - *namep = name; - } else { - *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); - } - } - - /* Handle realignment */ - if (fdt_chk_version() && fdt_version(fdt) < 0x10 && - (offset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8) - return prop->data + 4; - return prop->data; -} - -const void *fdt_getprop(const void *fdt, int nodeoffset, - const char *name, int *lenp) -{ - return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); -} - -uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) -{ - const fdt32_t *php; - int len; - - /* FIXME: This is a bit sub-optimal, since we potentially scan - * over all the properties twice. */ - php = fdt_getprop(fdt, nodeoffset, "phandle", &len); - if (!php || (len != sizeof(*php))) { - php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); - if (!php || (len != sizeof(*php))) - return 0; - } - - return fdt32_to_cpu(*php); -} - -const char *fdt_get_alias_namelen(const void *fdt, - const char *name, int namelen) -{ - int aliasoffset; - - aliasoffset = fdt_path_offset(fdt, "/aliases"); - if (aliasoffset < 0) - return NULL; - - return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); -} - -const char *fdt_get_alias(const void *fdt, const char *name) -{ - return fdt_get_alias_namelen(fdt, name, strlen(name)); -} - -int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) -{ - int pdepth = 0, p = 0; - int offset, depth, namelen; - const char *name; - - FDT_RO_PROBE(fdt); - - if (buflen < 2) - return -FDT_ERR_NOSPACE; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - while (pdepth > depth) { - do { - p--; - } while (buf[p-1] != '/'); - pdepth--; - } - - if (pdepth >= depth) { - name = fdt_get_name(fdt, offset, &namelen); - if (!name) - return namelen; - if ((p + namelen + 1) <= buflen) { - memcpy(buf + p, name, namelen); - p += namelen; - buf[p++] = '/'; - pdepth++; - } - } - - if (offset == nodeoffset) { - if (pdepth < (depth + 1)) - return -FDT_ERR_NOSPACE; - - if (p > 1) /* special case so that root path is "/", not "" */ - p--; - buf[p] = '\0'; - return 0; - } - } - - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - - return offset; /* error from fdt_next_node() */ -} - -int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, - int supernodedepth, int *nodedepth) -{ - int offset, depth; - int supernodeoffset = -FDT_ERR_INTERNAL; - - FDT_RO_PROBE(fdt); - - if (supernodedepth < 0) - return -FDT_ERR_NOTFOUND; - - for (offset = 0, depth = 0; - (offset >= 0) && (offset <= nodeoffset); - offset = fdt_next_node(fdt, offset, &depth)) { - if (depth == supernodedepth) - supernodeoffset = offset; - - if (offset == nodeoffset) { - if (nodedepth) - *nodedepth = depth; - - if (supernodedepth > depth) - return -FDT_ERR_NOTFOUND; - else - return supernodeoffset; - } - } - - if (fdt_chk_extra()) { - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_depth(const void *fdt, int nodeoffset) -{ - int nodedepth; - int err; - - err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); - if (err) - return (!fdt_chk_extra() || err < 0) ? err : -FDT_ERR_INTERNAL; - return nodedepth; -} - -int fdt_parent_offset(const void *fdt, int nodeoffset) -{ - int nodedepth = fdt_node_depth(fdt, nodeoffset); - - if (nodedepth < 0) - return nodedepth; - return fdt_supernode_atdepth_offset(fdt, nodeoffset, - nodedepth - 1, NULL); -} - -int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, - const char *propname, - const void *propval, int proplen) -{ - int offset; - const void *val; - int len; - - FDT_RO_PROBE(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_getprop(), then if that didn't - * find what we want, we scan over them again making our way - * to the next node. Still it's the easiest to implement - * approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - val = fdt_getprop(fdt, offset, propname, &len); - if (val && (len == proplen) - && (memcmp(val, propval, len) == 0)) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) -{ - int offset; - - if ((phandle == 0) || (phandle == -1)) - return -FDT_ERR_BADPHANDLE; - - FDT_RO_PROBE(fdt); - - /* FIXME: The algorithm here is pretty horrible: we - * potentially scan each property of a node in - * fdt_get_phandle(), then if that didn't find what - * we want, we scan over them again making our way to the next - * node. Still it's the easiest to implement approach; - * performance can come later. */ - for (offset = fdt_next_node(fdt, -1, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - if (fdt_get_phandle(fdt, offset) == phandle) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) -{ - int len = strlen(str); - const char *p; - - while (listlen >= len) { - if (memcmp(str, strlist, len+1) == 0) - return 1; - p = memchr(strlist, '\0', listlen); - if (!p) - return 0; /* malformed strlist.. */ - listlen -= (p-strlist) + 1; - strlist = p + 1; - } - return 0; -} - -int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) -{ - const char *list, *end; - int length, count = 0; - - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) - return length; - - end = list + length; - - while (list < end) { - length = strnlen(list, end - list) + 1; - - /* Abort if the last string isn't properly NUL-terminated. */ - if (list + length > end) - return -FDT_ERR_BADVALUE; - - list += length; - count++; - } - - return count; -} - -int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, - const char *string) -{ - int length, len, idx = 0; - const char *list, *end; - - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) - return length; - - len = strlen(string) + 1; - end = list + length; - - while (list < end) { - length = strnlen(list, end - list) + 1; - - /* Abort if the last string isn't properly NUL-terminated. */ - if (list + length > end) - return -FDT_ERR_BADVALUE; - - if (length == len && memcmp(list, string, length) == 0) - return idx; - - list += length; - idx++; - } - - return -FDT_ERR_NOTFOUND; -} - -const char *fdt_stringlist_get(const void *fdt, int nodeoffset, - const char *property, int idx, - int *lenp) -{ - const char *list, *end; - int length; - - list = fdt_getprop(fdt, nodeoffset, property, &length); - if (!list) { - if (lenp) - *lenp = length; - - return NULL; - } - - end = list + length; - - while (list < end) { - length = strnlen(list, end - list) + 1; - - /* Abort if the last string isn't properly NUL-terminated. */ - if (list + length > end) { - if (lenp) - *lenp = -FDT_ERR_BADVALUE; - - return NULL; - } - - if (idx == 0) { - if (lenp) - *lenp = length - 1; - - return list; - } - - list += length; - idx--; - } - - if (lenp) - *lenp = -FDT_ERR_NOTFOUND; - - return NULL; -} - -int fdt_node_check_compatible(const void *fdt, int nodeoffset, - const char *compatible) -{ - const void *prop; - int len; - - prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); - if (!prop) - return len; - - return !fdt_stringlist_contains(prop, len, compatible); -} - -int fdt_node_offset_by_compatible(const void *fdt, int startoffset, - const char *compatible) -{ - int offset, err; - - FDT_RO_PROBE(fdt); - - /* FIXME: The algorithm here is pretty horrible: we scan each - * property of a node in fdt_node_check_compatible(), then if - * that didn't find what we want, we scan over them again - * making our way to the next node. Still it's the easiest to - * implement approach; performance can come later. */ - for (offset = fdt_next_node(fdt, startoffset, NULL); - offset >= 0; - offset = fdt_next_node(fdt, offset, NULL)) { - err = fdt_node_check_compatible(fdt, offset, compatible); - if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) - return err; - else if (err == 0) - return offset; - } - - return offset; /* error from fdt_next_node() */ -} - -#if !defined(CHECK_LEVEL) || CHECK_LEVEL > 0 -int fdt_check_full(const void *fdt, size_t bufsize) -{ - int err; - int num_memrsv; - int offset, nextoffset = 0; - uint32_t tag; - unsigned depth = 0; - const void *prop; - const char *propname; - - if (bufsize < FDT_V1_SIZE) - return -FDT_ERR_TRUNCATED; - err = fdt_check_header(fdt); - if (err != 0) - return err; - if (bufsize < fdt_totalsize(fdt)) - return -FDT_ERR_TRUNCATED; - - num_memrsv = fdt_num_mem_rsv(fdt); - if (num_memrsv < 0) - return num_memrsv; - - while (1) { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - if (nextoffset < 0) - return nextoffset; - - switch (tag) { - case FDT_NOP: - break; - - case FDT_END: - if (depth != 0) - return -FDT_ERR_BADSTRUCTURE; - return 0; - - case FDT_BEGIN_NODE: - depth++; - if (depth > INT_MAX) - return -FDT_ERR_BADSTRUCTURE; - break; - - case FDT_END_NODE: - if (depth == 0) - return -FDT_ERR_BADSTRUCTURE; - depth--; - break; - - case FDT_PROP: - prop = fdt_getprop_by_offset(fdt, offset, &propname, - &err); - if (!prop) - return err; - break; - - default: - return -FDT_ERR_INTERNAL; - } - } -} -#endif +#include "../../scripts/dtc/libfdt/fdt_ro.c" diff --git a/test/run b/test/run index d635622c10..27331a8e40 100755 --- a/test/run +++ b/test/run @@ -15,22 +15,29 @@ run_test() { # SKip slow tests if requested [ "$1" == "quick" ] && mark_expr="not slow" +[ "$1" == "quick" ] && skip=--skip-net-tests +[ "$1" == "tools" ] && tools_only=y failures=0 -# Run all tests that the standard sandbox build can support -run_test "sandbox" ./test/py/test.py --bd sandbox --build -m "${mark_expr}" +if [ -z "$tools_only" ]; then + # Run all tests that the standard sandbox build can support + run_test "sandbox" ./test/py/test.py --bd sandbox --build \ + -m "${mark_expr}" +fi # Run tests which require sandbox_spl run_test "sandbox_spl" ./test/py/test.py --bd sandbox_spl --build \ - -k 'test_ofplatdata or test_handoff' + -k 'test_ofplatdata or test_handoff' -# Run tests for the flat-device-tree version of sandbox. This is a special -# build which does not enable CONFIG_OF_LIVE for the live device tree, so we can -# check that functionality is the same. The standard sandbox build (above) uses -# CONFIG_OF_LIVE. -run_test "sandbox_flattree" ./test/py/test.py --bd sandbox_flattree --build \ - -k test_ut +if [ -z "$tools_only" ]; then + # Run tests for the flat-device-tree version of sandbox. This is a special + # build which does not enable CONFIG_OF_LIVE for the live device tree, so we can + # check that functionality is the same. The standard sandbox build (above) uses + # CONFIG_OF_LIVE. + run_test "sandbox_flattree" ./test/py/test.py --bd sandbox_flattree \ + --build -k test_ut +fi # Set up a path to dtc (device-tree compiler) and libfdt.py, a library it # provides and which is built by the sandbox_spl config. Also set up the path @@ -43,7 +50,6 @@ TOOLS_DIR=build-sandbox_spl/tools run_test "binman" ./tools/binman/binman --toolpath ${TOOLS_DIR} test run_test "patman" ./tools/patman/patman --test -[ "$1" == "quick" ] && skip=--skip-net-tests run_test "buildman" ./tools/buildman/buildman -t ${skip} run_test "fdt" ./tools/dtoc/test_fdt -t run_test "dtoc" ./tools/dtoc/dtoc -t diff --git a/tools/Makefile b/tools/Makefile index c2b2634004..1f9144f028 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -63,14 +63,8 @@ FIT_CIPHER_OBJS-$(CONFIG_FIT_CIPHER) := common/image-cipher.o # The following files are synced with upstream DTC. # Use synced versions from scripts/dtc/libfdt/. -LIBFDT_SRCS_SYNCED := fdt.c fdt_wip.c fdt_sw.c fdt_rw.c \ - fdt_strerror.c fdt_empty_tree.c fdt_addresses.c fdt_overlay.c -# The following files are locally modified for U-Boot (unfotunately). -# Use U-Boot own versions from lib/libfdt/. -LIBFDT_SRCS_UNSYNCED := fdt_ro.c fdt_region.c - -LIBFDT_OBJS := $(addprefix libfdt/, $(patsubst %.c, %.o, $(LIBFDT_SRCS_SYNCED))) \ - $(addprefix lib/libfdt/, $(patsubst %.c, %.o, $(LIBFDT_SRCS_UNSYNCED))) +LIBFDT_OBJS := $(addprefix libfdt/, fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o \ + fdt_strerror.o fdt_empty_tree.o fdt_addresses.o fdt_overlay.o) RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \ rsa-sign.o rsa-verify.o rsa-checksum.o \ @@ -87,6 +81,7 @@ dumpimage-mkimage-objs := aisimage.o \ $(FIT_OBJS-y) \ $(FIT_SIG_OBJS-y) \ $(FIT_CIPHER_OBJS-y) \ + common/fdt_region.o \ common/bootm.o \ lib/crc32.o \ default_image.o \ @@ -211,7 +206,7 @@ hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela hostprogs-$(CONFIG_RISCV) += prelink-riscv hostprogs-y += fdtgrep -fdtgrep-objs += $(LIBFDT_OBJS) fdtgrep.o +fdtgrep-objs += $(LIBFDT_OBJS) common/fdt_region.o fdtgrep.o ifneq ($(TOOLS_ONLY),y) hostprogs-y += spl_size_limit diff --git a/tools/binman/binman b/tools/binman/binman index 979b7e4d4b..11a5d8e18a 120000 --- a/tools/binman/binman +++ b/tools/binman/binman @@ -1 +1 @@ -binman.py \ No newline at end of file +main.py \ No newline at end of file diff --git a/tools/binman/cbfs_util.py b/tools/binman/cbfs_util.py index 99d77878c9..39973371b9 100644 --- a/tools/binman/cbfs_util.py +++ b/tools/binman/cbfs_util.py @@ -15,16 +15,14 @@ Currently supported: raw and stage types with compression, padding empty areas with empty files, fixed-offset files """ -from __future__ import print_function - from collections import OrderedDict import io import struct import sys -import command -import elf -import tools +from binman import elf +from patman import command +from patman import tools # Set to True to enable printing output while working DEBUG = False diff --git a/tools/binman/cbfs_util_test.py b/tools/binman/cbfs_util_test.py index ddc2e09e35..2c62c8a0f8 100755 --- a/tools/binman/cbfs_util_test.py +++ b/tools/binman/cbfs_util_test.py @@ -9,8 +9,6 @@ These create and read various CBFSs and compare the results with expected values and with cbfstool """ -from __future__ import print_function - import io import os import shutil @@ -18,11 +16,11 @@ import struct import tempfile import unittest -import cbfs_util -from cbfs_util import CbfsWriter -import elf -import test_util -import tools +from binman import cbfs_util +from binman.cbfs_util import CbfsWriter +from binman import elf +from patman import test_util +from patman import tools U_BOOT_DATA = b'1234' U_BOOT_DTB_DATA = b'udtb' diff --git a/tools/binman/control.py b/tools/binman/control.py index 68ad5fc2c0..dc1dd2a7dc 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -5,17 +5,15 @@ # Creates binary images from input files controlled by a description # -from __future__ import print_function - from collections import OrderedDict import os import sys -import tools +from patman import tools -import cbfs_util -import command -import elf -import tout +from binman import cbfs_util +from binman import elf +from patman import command +from patman import tout # List of images we plan to create # Make this global so that it can be referenced from tests @@ -62,7 +60,7 @@ def WriteEntryDocs(modules, test_missing=None): to show as missing even if it is present. Should be set to None in normal use. """ - from entry import Entry + from binman.entry import Entry Entry.WriteDocs(modules, test_missing) @@ -336,8 +334,8 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt): """ # Import these here in case libfdt.py is not available, in which case # the above help option still works. - import fdt - import fdt_util + from dtoc import fdt + from dtoc import fdt_util global images # Get the device tree ready by compiling it and copying the compiled @@ -475,7 +473,7 @@ def Binman(args): # Put these here so that we can import this module without libfdt from image import Image - import state + from binman import state if args.cmd in ['ls', 'extract', 'replace']: try: diff --git a/tools/binman/elf.py b/tools/binman/elf.py index de1ce73f2a..f88031c2bf 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -5,10 +5,7 @@ # Handle various things related to ELF images # -from __future__ import print_function - from collections import namedtuple, OrderedDict -import command import io import os import re @@ -16,8 +13,9 @@ import shutil import struct import tempfile -import tools -import tout +from patman import command +from patman import tools +from patman import tout ELF_TOOLS = True try: diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index ac26fd51e4..37e1b423cf 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -10,11 +10,11 @@ import sys import tempfile import unittest -import command -import elf -import test_util -import tools -import tout +from binman import elf +from patman import command +from patman import test_util +from patman import tools +from patman import tout binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) diff --git a/tools/binman/entry.py b/tools/binman/entry.py index b6f1b2c93f..90ffd27617 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -4,17 +4,15 @@ # Base class for all entries # -from __future__ import print_function - from collections import namedtuple import importlib import os import sys -import fdt_util -import tools -from tools import ToHex, ToHexSize -import tout +from dtoc import fdt_util +from patman import tools +from patman.tools import ToHex, ToHexSize +from patman import tout modules = {} @@ -65,7 +63,7 @@ class Entry(object): def __init__(self, section, etype, node, name_prefix=''): # Put this here to allow entry-docs and help to work without libfdt global state - import state + from binman import state self.section = section self.etype = etype @@ -110,15 +108,11 @@ class Entry(object): # Import the module if we have not already done so. if not module: - old_path = sys.path - sys.path.insert(0, os.path.join(our_path, 'etype')) try: - module = importlib.import_module(module_name) + module = importlib.import_module('binman.etype.' + module_name) except ImportError as e: raise ValueError("Unknown entry type '%s' in node '%s' (expected etype/%s.py, error '%s'" % (etype, node_path, module_name, e)) - finally: - sys.path = old_path modules[module_name] = module # Look up the expected class name @@ -592,9 +586,7 @@ features to produce new behaviours. modules.remove('_testing') missing = [] for name in modules: - if name.startswith('__'): - continue - module = Entry.Lookup(name, name) + module = Entry.Lookup('WriteDocs', name) docs = getattr(module, '__doc__') if test_missing == name: docs = None diff --git a/tools/binman/entry_test.py b/tools/binman/entry_test.py index 277e10b585..80802f33de 100644 --- a/tools/binman/entry_test.py +++ b/tools/binman/entry_test.py @@ -9,10 +9,10 @@ import os import sys import unittest -import entry -import fdt -import fdt_util -import tools +from binman import entry +from dtoc import fdt +from dtoc import fdt_util +from patman import tools class TestEntry(unittest.TestCase): def setUp(self): @@ -37,11 +37,11 @@ class TestEntry(unittest.TestCase): else: reload(entry) else: - import entry + from binman import entry def testEntryContents(self): """Test the Entry bass class""" - import entry + from binman import entry base_entry = entry.Entry(None, None, None) self.assertEqual(True, base_entry.ObtainContents()) diff --git a/tools/binman/etype/__init__.py b/tools/binman/etype/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py index 25a6206bf3..ed718eed14 100644 --- a/tools/binman/etype/_testing.py +++ b/tools/binman/etype/_testing.py @@ -7,9 +7,9 @@ from collections import OrderedDict -from entry import Entry, EntryArg -import fdt_util -import tools +from binman.entry import Entry, EntryArg +from dtoc import fdt_util +from patman import tools class Entry__testing(Entry): diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py index d34c7b51bf..ede7a7a68c 100644 --- a/tools/binman/etype/blob.py +++ b/tools/binman/etype/blob.py @@ -5,10 +5,10 @@ # Entry-type module for blobs, which are binary objects read from files # -from entry import Entry -import fdt_util -import tools -import tout +from binman.entry import Entry +from dtoc import fdt_util +from patman import tools +from patman import tout class Entry_blob(Entry): """Entry containing an arbitrary binary blob diff --git a/tools/binman/etype/blob_dtb.py b/tools/binman/etype/blob_dtb.py index b2afa064c1..6c06943763 100644 --- a/tools/binman/etype/blob_dtb.py +++ b/tools/binman/etype/blob_dtb.py @@ -5,8 +5,8 @@ # Entry-type module for U-Boot device tree files # -from entry import Entry -from blob import Entry_blob +from binman.entry import Entry +from binman.etype.blob import Entry_blob class Entry_blob_dtb(Entry_blob): """A blob that holds a device tree @@ -18,7 +18,7 @@ class Entry_blob_dtb(Entry_blob): def __init__(self, section, etype, node): # Put this here to allow entry-docs and help to work without libfdt global state - import state + from binman import state Entry_blob.__init__(self, section, etype, node) diff --git a/tools/binman/etype/blob_named_by_arg.py b/tools/binman/etype/blob_named_by_arg.py index 344112bc42..3b4593f071 100644 --- a/tools/binman/etype/blob_named_by_arg.py +++ b/tools/binman/etype/blob_named_by_arg.py @@ -8,8 +8,8 @@ from collections import OrderedDict -from blob import Entry_blob -from entry import EntryArg +from binman.etype.blob import Entry_blob +from binman.entry import EntryArg class Entry_blob_named_by_arg(Entry_blob): diff --git a/tools/binman/etype/cbfs.py b/tools/binman/etype/cbfs.py index 35b78370b2..e9aed8310c 100644 --- a/tools/binman/etype/cbfs.py +++ b/tools/binman/etype/cbfs.py @@ -7,10 +7,10 @@ from collections import OrderedDict -import cbfs_util -from cbfs_util import CbfsWriter -from entry import Entry -import fdt_util +from binman import cbfs_util +from binman.cbfs_util import CbfsWriter +from binman.entry import Entry +from dtoc import fdt_util class Entry_cbfs(Entry): """Entry containing a Coreboot Filesystem (CBFS) @@ -165,7 +165,7 @@ class Entry_cbfs(Entry): def __init__(self, section, etype, node): # Put this here to allow entry-docs and help to work without libfdt global state - import state + from binman import state Entry.__init__(self, section, etype, node) self._cbfs_arg = fdt_util.GetString(node, 'cbfs-arch', 'x86') diff --git a/tools/binman/etype/cros_ec_rw.py b/tools/binman/etype/cros_ec_rw.py index 261f8657a6..0dbe14b342 100644 --- a/tools/binman/etype/cros_ec_rw.py +++ b/tools/binman/etype/cros_ec_rw.py @@ -5,7 +5,7 @@ # Entry-type module for a Chromium OS EC image (read-write section) # -from blob_named_by_arg import Entry_blob_named_by_arg +from binman.etype.blob_named_by_arg import Entry_blob_named_by_arg class Entry_cros_ec_rw(Entry_blob_named_by_arg): diff --git a/tools/binman/etype/fdtmap.py b/tools/binman/etype/fdtmap.py index 5dc08b8289..aa8807990b 100644 --- a/tools/binman/etype/fdtmap.py +++ b/tools/binman/etype/fdtmap.py @@ -8,9 +8,9 @@ This handles putting an FDT into the image with just the information about the image. """ -from entry import Entry -import tools -import tout +from binman.entry import Entry +from patman import tools +from patman import tout FDTMAP_MAGIC = b'_FDTMAP_' FDTMAP_HDR_LEN = 16 @@ -82,8 +82,8 @@ class Entry_fdtmap(Entry): global Fdt import libfdt - import state - from fdt import Fdt + from binman import state + from dtoc.fdt import Fdt Entry.__init__(self, section, etype, node) diff --git a/tools/binman/etype/files.py b/tools/binman/etype/files.py index 3473a2b1ef..10ab585f0e 100644 --- a/tools/binman/etype/files.py +++ b/tools/binman/etype/files.py @@ -9,9 +9,9 @@ import glob import os -from section import Entry_section -import fdt_util -import tools +from binman.etype.section import Entry_section +from dtoc import fdt_util +from patman import tools class Entry_files(Entry_section): @@ -30,7 +30,7 @@ class Entry_files(Entry_section): def __init__(self, section, etype, node): # Put this here to allow entry-docs and help to work without libfdt global state - import state + from binman import state Entry_section.__init__(self, section, etype, node) self._pattern = fdt_util.GetString(self._node, 'pattern') diff --git a/tools/binman/etype/fill.py b/tools/binman/etype/fill.py index 623b7f4e95..860410ed6e 100644 --- a/tools/binman/etype/fill.py +++ b/tools/binman/etype/fill.py @@ -3,9 +3,9 @@ # Written by Simon Glass # -from entry import Entry -import fdt_util -import tools +from binman.entry import Entry +from dtoc import fdt_util +from patman import tools class Entry_fill(Entry): """An entry which is filled to a particular byte value diff --git a/tools/binman/etype/fmap.py b/tools/binman/etype/fmap.py index 835ba5012e..a43fac38de 100644 --- a/tools/binman/etype/fmap.py +++ b/tools/binman/etype/fmap.py @@ -5,11 +5,11 @@ # Entry-type module for a Flash map, as used by the flashrom SPI flash tool # -from entry import Entry -import fmap_util -import tools -from tools import ToHexSize -import tout +from binman.entry import Entry +from binman import fmap_util +from patman import tools +from patman.tools import ToHexSize +from patman import tout class Entry_fmap(Entry): diff --git a/tools/binman/etype/gbb.py b/tools/binman/etype/gbb.py index a94c0fca9d..dd10599717 100644 --- a/tools/binman/etype/gbb.py +++ b/tools/binman/etype/gbb.py @@ -8,11 +8,11 @@ from collections import OrderedDict -import command -from entry import Entry, EntryArg +from patman import command +from binman.entry import Entry, EntryArg -import fdt_util -import tools +from dtoc import fdt_util +from patman import tools # Build GBB flags. # (src/platform/vboot_reference/firmware/include/gbb_header.h) diff --git a/tools/binman/etype/image_header.py b/tools/binman/etype/image_header.py index b9327dd799..176bdeb29b 100644 --- a/tools/binman/etype/image_header.py +++ b/tools/binman/etype/image_header.py @@ -11,8 +11,8 @@ image. import struct -from entry import Entry -import fdt_util +from binman.entry import Entry +from dtoc import fdt_util IMAGE_HEADER_MAGIC = b'BinM' IMAGE_HEADER_LEN = 8 diff --git a/tools/binman/etype/intel_cmc.py b/tools/binman/etype/intel_cmc.py index fa6f7793c6..5e6edbe4df 100644 --- a/tools/binman/etype/intel_cmc.py +++ b/tools/binman/etype/intel_cmc.py @@ -5,8 +5,8 @@ # Entry-type module for Intel Chip Microcode binary blob # -from entry import Entry -from blob import Entry_blob +from binman.entry import Entry +from binman.etype.blob import Entry_blob class Entry_intel_cmc(Entry_blob): """Entry containing an Intel Chipset Micro Code (CMC) file diff --git a/tools/binman/etype/intel_descriptor.py b/tools/binman/etype/intel_descriptor.py index b6477931d6..d4d7a26901 100644 --- a/tools/binman/etype/intel_descriptor.py +++ b/tools/binman/etype/intel_descriptor.py @@ -7,8 +7,8 @@ import struct -from entry import Entry -from blob import Entry_blob +from binman.entry import Entry +from binman.etype.blob import Entry_blob FD_SIGNATURE = struct.pack(' 0) def testEntryDocsMissing(self): """Test handling of missing entry documentation""" with self.assertRaises(ValueError) as e: with test_util.capture_sys_output() as (stdout, stderr): - control.WriteEntryDocs(binman.GetEntryModules(), 'u_boot') + control.WriteEntryDocs(main.GetEntryModules(), 'u_boot') self.assertIn('Documentation is missing for modules: u_boot', str(e.exception)) diff --git a/tools/binman/image.py b/tools/binman/image.py index 2beab7fd4d..523b274c31 100644 --- a/tools/binman/image.py +++ b/tools/binman/image.py @@ -5,8 +5,6 @@ # Class for an image, the output of binman # -from __future__ import print_function - from collections import OrderedDict import fnmatch from operator import attrgetter @@ -14,14 +12,14 @@ import os import re import sys -from entry import Entry -from etype import fdtmap -from etype import image_header -from etype import section -import fdt -import fdt_util -import tools -import tout +from binman.entry import Entry +from binman.etype import fdtmap +from binman.etype import image_header +from binman.etype import section +from dtoc import fdt +from dtoc import fdt_util +from patman import tools +from patman import tout class Image(section.Entry_section): """A Image, representing an output from binman diff --git a/tools/binman/image_test.py b/tools/binman/image_test.py index 10f85d1081..f85c3c51c0 100644 --- a/tools/binman/image_test.py +++ b/tools/binman/image_test.py @@ -7,7 +7,7 @@ import unittest from image import Image -from test_util import capture_sys_output +from patman.test_util import capture_sys_output class TestImage(unittest.TestCase): def testInvalidFormat(self): diff --git a/tools/binman/binman.py b/tools/binman/main.py similarity index 54% rename from tools/binman/binman.py rename to tools/binman/main.py index 9e6fd72117..efa7fa8386 100755 --- a/tools/binman/binman.py +++ b/tools/binman/main.py @@ -9,11 +9,8 @@ """See README for more information""" -from __future__ import print_function - from distutils.sysconfig import get_python_lib import glob -import multiprocessing import os import site import sys @@ -23,8 +20,9 @@ import unittest # Bring in the patman and dtoc libraries (but don't override the first path # in PYTHONPATH) our_path = os.path.dirname(os.path.realpath(__file__)) -for dirname in ['../patman', '../dtoc', '..', '../concurrencytest']: - sys.path.insert(2, os.path.join(our_path, dirname)) +sys.path.insert(2, os.path.join(our_path, '..')) + +from patman import test_util # Bring in the libfdt module sys.path.insert(2, 'scripts/dtc/pylibfdt') @@ -37,15 +35,9 @@ sys.path.insert(2, os.path.join(our_path, # that is not available in a virtualenv. sys.path.append(get_python_lib()) -import cmdline -import command -use_concurrent = True -try: - from concurrencytest import ConcurrentTestSuite, fork_for_tests -except: - use_concurrent = False -import control -import test_util +from binman import cmdline +from binman import control +from patman import test_util def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath): """Run the functional tests and any embedded doctests @@ -63,83 +55,27 @@ def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath): name to execute (as in 'binman test testSections', for example) toolpath: List of paths to use for tools """ - import cbfs_util_test - import elf_test - import entry_test - import fdt_test - import ftest - import image_test - import test + from binman import cbfs_util_test + from binman import elf_test + from binman import entry_test + from binman import fdt_test + from binman import ftest + from binman import image_test + from binman import test import doctest result = unittest.TestResult() - for module in []: - suite = doctest.DocTestSuite(module) - suite.run(result) - - sys.argv = [sys.argv[0]] - if debug: - sys.argv.append('-D') - if verbosity: - sys.argv.append('-v%d' % verbosity) - if toolpath: - for path in toolpath: - sys.argv += ['--toolpath', path] + test_name = args and args[0] or None # Run the entry tests first ,since these need to be the first to import the # 'entry' module. - test_name = args and args[0] or None - suite = unittest.TestSuite() - loader = unittest.TestLoader() - for module in (entry_test.TestEntry, ftest.TestFunctional, fdt_test.TestFdt, - elf_test.TestElf, image_test.TestImage, - cbfs_util_test.TestCbfs): - # Test the test module about our arguments, if it is interested - if hasattr(module, 'setup_test_args'): - setup_test_args = getattr(module, 'setup_test_args') - setup_test_args(preserve_indir=test_preserve_dirs, - preserve_outdirs=test_preserve_dirs and test_name is not None, - toolpath=toolpath, verbosity=verbosity) - if test_name: - try: - suite.addTests(loader.loadTestsFromName(test_name, module)) - except AttributeError: - continue - else: - suite.addTests(loader.loadTestsFromTestCase(module)) - if use_concurrent and processes != 1: - concurrent_suite = ConcurrentTestSuite(suite, - fork_for_tests(processes or multiprocessing.cpu_count())) - concurrent_suite.run(result) - else: - suite.run(result) + test_util.RunTestSuites( + result, debug, verbosity, test_preserve_dirs, processes, test_name, + toolpath, + [entry_test.TestEntry, ftest.TestFunctional, fdt_test.TestFdt, + elf_test.TestElf, image_test.TestImage, cbfs_util_test.TestCbfs]) - # Remove errors which just indicate a missing test. Since Python v3.5 If an - # ImportError or AttributeError occurs while traversing name then a - # synthetic test that raises that error when run will be returned. These - # errors are included in the errors accumulated by result.errors. - if test_name: - errors = [] - for test, err in result.errors: - if ("has no attribute '%s'" % test_name) not in err: - errors.append((test, err)) - result.testsRun -= 1 - result.errors = errors - - print(result) - for test, err in result.errors: - print(test.id(), err) - for test, err in result.failures: - print(err, result.failures) - if result.skipped: - print('%d binman test%s SKIPPED:' % - (len(result.skipped), 's' if len(result.skipped) > 1 else '')) - for skip_info in result.skipped: - print('%s: %s' % (skip_info[0], skip_info[1])) - if result.errors or result.failures: - print('binman tests FAILED') - return 1 - return 0 + return test_util.ReportResult('binman', test_name, result) def GetEntryModules(include_testing=True): """Get a set of entry class implementations @@ -157,8 +93,8 @@ def RunTestCoverage(): glob_list = GetEntryModules(False) all_set = set([os.path.splitext(os.path.basename(item))[0] for item in glob_list if '_testing' not in item]) - test_util.RunTestCoverage('tools/binman/binman.py', None, - ['*test*', '*binman.py', 'tools/patman/*', 'tools/dtoc/*'], + test_util.RunTestCoverage('tools/binman/binman', None, + ['*test*', '*main.py', 'tools/patman/*', 'tools/dtoc/*'], args.build_dir, all_set) def RunBinman(args): diff --git a/tools/binman/state.py b/tools/binman/state.py index d704ed2c7c..36bc513535 100644 --- a/tools/binman/state.py +++ b/tools/binman/state.py @@ -8,10 +8,10 @@ import hashlib import re -import fdt +from dtoc import fdt import os -import tools -import tout +from patman import tools +from patman import tout # Records the device-tree files known to binman, keyed by entry type (e.g. # 'u-boot-spl-dtb'). These are the output FDT files, which can be updated by @@ -167,8 +167,8 @@ def Prepare(images, dtb): global output_fdt_info, main_dtb, fdt_path_prefix # Import these here in case libfdt.py is not available, in which case # the above help option still works. - import fdt - import fdt_util + from dtoc import fdt + from dtoc import fdt_util # If we are updating the DTBs we need to put these updated versions # where Entry_blob_dtb can find them. We can ignore 'u-boot.dtb' diff --git a/tools/buildman/README b/tools/buildman/README index f3a0dc7288..b2f983c715 100644 --- a/tools/buildman/README +++ b/tools/buildman/README @@ -1091,7 +1091,8 @@ the -w option, for example: buildman -o /tmp/build --board sandbox -w -This will write the full build into /tmp/build including object files. +This will write the full build into /tmp/build including object files. You must +specify the output directory with -o when using -w. Other options diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py index 30ebe1d820..f8e71de427 100644 --- a/tools/buildman/builder.py +++ b/tools/buildman/builder.py @@ -17,12 +17,12 @@ import sys import threading import time -import builderthread -import command -import gitutil -import terminal -from terminal import Print -import toolchain +from buildman import builderthread +from buildman import toolchain +from patman import command +from patman import gitutil +from patman import terminal +from patman.terminal import Print """ Theory of Operation @@ -479,6 +479,9 @@ class Builder: Args: commit_upto: Commit number to use (0..self.count-1) """ + if self.work_in_output: + return self._working_dir + commit_dir = None if self.commits: commit = self.commits[commit_upto] @@ -502,6 +505,8 @@ class Builder: target: Target name """ output_dir = self._GetOutputDir(commit_upto) + if self.work_in_output: + return output_dir return os.path.join(output_dir, target) def GetDoneFile(self, commit_upto, target): diff --git a/tools/buildman/builderthread.py b/tools/buildman/builderthread.py index fc6e1ab25d..48fcd6cf7e 100644 --- a/tools/buildman/builderthread.py +++ b/tools/buildman/builderthread.py @@ -9,8 +9,8 @@ import shutil import sys import threading -import command -import gitutil +from patman import command +from patman import gitutil RETURN_CODE_RETRY = -1 @@ -280,8 +280,6 @@ class BuilderThread(threading.Thread): work_in_output: Use the output directory as the work directory and don't write to a separate output directory. """ - if work_in_output: - return # Fatal error if result.return_code < 0: return @@ -333,7 +331,7 @@ class BuilderThread(threading.Thread): # Write out the image and function size information and an objdump env = result.toolchain.MakeEnvironment(self.builder.full_path) - with open(os.path.join(build_dir, 'env'), 'w') as fd: + with open(os.path.join(build_dir, 'out-env'), 'w') as fd: for var in sorted(env.keys()): print('%s="%s"' % (var, env[var]), file=fd) lines = [] @@ -379,7 +377,8 @@ class BuilderThread(threading.Thread): capture_stderr=True, cwd=result.out_dir, raise_on_error=False, env=env) ubootenv = os.path.join(result.out_dir, 'uboot.env') - self.CopyFiles(result.out_dir, build_dir, '', ['uboot.env']) + if not work_in_output: + self.CopyFiles(result.out_dir, build_dir, '', ['uboot.env']) # Write out the image sizes file. This is similar to the output # of binutil's 'size' utility, but it omits the header line and @@ -391,17 +390,21 @@ class BuilderThread(threading.Thread): with open(sizes, 'w') as fd: print('\n'.join(lines), file=fd) - # Write out the configuration files, with a special case for SPL - for dirname in ['', 'spl', 'tpl']: - self.CopyFiles(result.out_dir, build_dir, dirname, ['u-boot.cfg', - 'spl/u-boot-spl.cfg', 'tpl/u-boot-tpl.cfg', '.config', - 'include/autoconf.mk', 'include/generated/autoconf.h']) + if not work_in_output: + # Write out the configuration files, with a special case for SPL + for dirname in ['', 'spl', 'tpl']: + self.CopyFiles( + result.out_dir, build_dir, dirname, + ['u-boot.cfg', 'spl/u-boot-spl.cfg', 'tpl/u-boot-tpl.cfg', + '.config', 'include/autoconf.mk', + 'include/generated/autoconf.h']) - # Now write the actual build output - if keep_outputs: - self.CopyFiles(result.out_dir, build_dir, '', ['u-boot*', '*.bin', - '*.map', '*.img', 'MLO', 'SPL', 'include/autoconf.mk', - 'spl/u-boot-spl*']) + # Now write the actual build output + if keep_outputs: + self.CopyFiles( + result.out_dir, build_dir, '', + ['u-boot*', '*.bin', '*.map', '*.img', 'MLO', 'SPL', + 'include/autoconf.mk', 'spl/u-boot-spl*']) def CopyFiles(self, out_dir, build_dir, dirname, patterns): """Copy files from the build directory to the output. diff --git a/tools/buildman/buildman b/tools/buildman/buildman index e4fba2d4b0..11a5d8e18a 120000 --- a/tools/buildman/buildman +++ b/tools/buildman/buildman @@ -1 +1 @@ -buildman.py \ No newline at end of file +main.py \ No newline at end of file diff --git a/tools/buildman/cmdline.py b/tools/buildman/cmdline.py index 1377b9d2be..680c072d66 100644 --- a/tools/buildman/cmdline.py +++ b/tools/buildman/cmdline.py @@ -76,8 +76,7 @@ def ParseArgs(): default=False, help="Do a dry run (describe actions, but do nothing)") parser.add_option('-N', '--no-subdirs', action='store_true', dest='no_subdirs', default=False, help="Don't create subdirectories when building current source for a single board") - parser.add_option('-o', '--output-dir', type='string', - dest='output_dir', default='..', + parser.add_option('-o', '--output-dir', type='string', dest='output_dir', help='Directory where all builds happen and buildman has its workspace (default is ../)') parser.add_option('-O', '--override-toolchain', type='string', help="Override host toochain to use for sandbox (e.g. 'clang-7')") diff --git a/tools/buildman/control.py b/tools/buildman/control.py index 30c030fd16..071c2613ec 100644 --- a/tools/buildman/control.py +++ b/tools/buildman/control.py @@ -5,18 +5,18 @@ import multiprocessing import os import shutil +import subprocess import sys -import board -import bsettings -from builder import Builder -import gitutil -import patchstream -import terminal -from terminal import Print -import toolchain -import command -import subprocess +from buildman import board +from buildman import bsettings +from buildman import toolchain +from buildman.builder import Builder +from patman import command +from patman import gitutil +from patman import patchstream +from patman import terminal +from patman.terminal import Print def GetPlural(count): """Returns a plural 's' if count is not 1""" @@ -175,6 +175,10 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, if options.incremental: print(col.Color(col.RED, 'Warning: -I has been removed. See documentation')) + if not options.output_dir: + if options.work_in_output: + sys.exit(col.Color(col.RED, '-w requires that you specify -o')) + options.output_dir = '..' # Work out what subset of the boards we are building if not boards: @@ -207,7 +211,7 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None, sys.exit(col.Color(col.RED, 'No matching boards found')) if options.print_prefix: - err = ShowToolchainInfo(boards, toolchains) + err = ShowToolchainPrefix(boards, toolchains) if err: sys.exit(col.Color(col.RED, err)) return 0 diff --git a/tools/buildman/func_test.py b/tools/buildman/func_test.py index 1fbc6f6b00..418677f9cc 100644 --- a/tools/buildman/func_test.py +++ b/tools/buildman/func_test.py @@ -8,15 +8,15 @@ import sys import tempfile import unittest -import board -import bsettings -import cmdline -import command -import control -import gitutil -import terminal -import toolchain -import tools +from buildman import board +from buildman import bsettings +from buildman import cmdline +from buildman import control +from buildman import toolchain +from patman import command +from patman import gitutil +from patman import terminal +from patman import tools settings_data = ''' # Buildman settings file @@ -546,6 +546,13 @@ class TestFunctional(unittest.TestCase): self.assertEqual(self._builder.count, self._total_builds) self.assertEqual(self._builder.fail, 0) + def testEnvironment(self): + """Test that the done and environment files are written to out-env""" + self._RunControl('-o', self._output_dir) + board0_dir = os.path.join(self._output_dir, 'current', 'board0') + self.assertTrue(os.path.exists(os.path.join(board0_dir, 'done'))) + self.assertTrue(os.path.exists(os.path.join(board0_dir, 'out-env'))) + def testWorkInOutput(self): """Test the -w option which should write directly to the output dir""" board_list = board.Boards() @@ -554,6 +561,10 @@ class TestFunctional(unittest.TestCase): boards=board_list) self.assertTrue( os.path.exists(os.path.join(self._output_dir, 'u-boot'))) + self.assertTrue( + os.path.exists(os.path.join(self._output_dir, 'done'))) + self.assertTrue( + os.path.exists(os.path.join(self._output_dir, 'out-env'))) def testWorkInOutputFail(self): """Test the -w option failures""" @@ -569,3 +580,9 @@ class TestFunctional(unittest.TestCase): self._RunControl('-b', self._test_branch, '-o', self._output_dir, '-w', clean_dir=False, boards=board_list) self.assertIn("single commit", str(e.exception)) + + board_list = board.Boards() + board_list.AddBoard(board.Board(*boards[0])) + with self.assertRaises(SystemExit) as e: + self._RunControl('-w', clean_dir=False) + self.assertIn("specify -o", str(e.exception)) diff --git a/tools/buildman/buildman.py b/tools/buildman/main.py similarity index 76% rename from tools/buildman/buildman.py rename to tools/buildman/main.py index 30a8690f93..2b714739a2 100755 --- a/tools/buildman/buildman.py +++ b/tools/buildman/main.py @@ -6,8 +6,7 @@ """See README for more information""" -from __future__ import print_function - +import doctest import multiprocessing import os import re @@ -16,20 +15,18 @@ import unittest # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) -sys.path.insert(1, os.path.join(our_path, '../patman')) +sys.path.insert(1, os.path.join(our_path, '..')) # Our modules -import board -import bsettings -import builder -import checkpatch -import cmdline -import control -import doctest -import gitutil -import patchstream -import terminal -import toolchain +from buildman import board +from buildman import bsettings +from buildman import builder +from buildman import cmdline +from buildman import control +from buildman import toolchain +from patman import patchstream +from patman import gitutil +from patman import terminal def RunTests(skip_net_tests): import func_test @@ -37,7 +34,7 @@ def RunTests(skip_net_tests): import doctest result = unittest.TestResult() - for module in ['toolchain', 'gitutil']: + for module in ['buildman.toolchain', 'patman.gitutil']: suite = doctest.DocTestSuite(module) suite.run(result) diff --git a/tools/buildman/test.py b/tools/buildman/test.py index d32b22653f..40811ba9f9 100644 --- a/tools/buildman/test.py +++ b/tools/buildman/test.py @@ -11,18 +11,17 @@ import unittest # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(our_path, '../patman')) -import board -import bsettings -import builder -import control -import command -import commit -import terminal -import test_util -import toolchain -import tools +from buildman import board +from buildman import bsettings +from buildman import builder +from buildman import control +from buildman import toolchain +from patman import commit +from patman import command +from patman import terminal +from patman import test_util +from patman import tools use_network = True @@ -583,7 +582,7 @@ class TestBuild(unittest.TestCase): url = self.toolchains.LocateArchUrl('arm') self.assertRegexpMatches(url, 'https://www.kernel.org/pub/tools/' 'crosstool/files/bin/x86_64/.*/' - 'x86_64-gcc-.*-nolibc_arm-.*linux-gnueabi.tar.xz') + 'x86_64-gcc-.*-nolibc[-_]arm-.*linux-gnueabi.tar.xz') def testGetEnvArgs(self): """Test the GetEnvArgs() function""" diff --git a/tools/buildman/toolchain.py b/tools/buildman/toolchain.py index 4456a805c7..acb5a29c8f 100644 --- a/tools/buildman/toolchain.py +++ b/tools/buildman/toolchain.py @@ -10,10 +10,10 @@ import sys import tempfile import urllib.request, urllib.error, urllib.parse -import bsettings -import command -import terminal -import tools +from buildman import bsettings +from patman import command +from patman import terminal +from patman import tools (PRIORITY_FULL_PREFIX, PRIORITY_PREFIX_GCC, PRIORITY_PREFIX_GCC_PATH, PRIORITY_CALC) = list(range(4)) diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py index 90a9e1a626..ecfe0624d1 100644 --- a/tools/dtoc/dtb_platdata.py +++ b/tools/dtoc/dtb_platdata.py @@ -15,9 +15,9 @@ import collections import copy import sys -import fdt -import fdt_util -import tools +from dtoc import fdt +from dtoc import fdt_util +from patman import tools # When we see these properties we ignore them - i.e. do not create a structure member PROP_IGNORE_LIST = [ diff --git a/tools/dtoc/dtoc b/tools/dtoc/dtoc index 896ca44e62..11a5d8e18a 120000 --- a/tools/dtoc/dtoc +++ b/tools/dtoc/dtoc @@ -1 +1 @@ -dtoc.py \ No newline at end of file +main.py \ No newline at end of file diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 1b7b730359..188490b728 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -8,10 +8,10 @@ import struct import sys -import fdt_util +from dtoc import fdt_util import libfdt from libfdt import QUIET_NOTFOUND -import tools +from patman import tools # This deals with a device tree, presenting it as an assortment of Node and # Prop objects, representing nodes and properties, respectively. This file diff --git a/tools/dtoc/fdt_util.py b/tools/dtoc/fdt_util.py index b105faec74..b040793772 100644 --- a/tools/dtoc/fdt_util.py +++ b/tools/dtoc/fdt_util.py @@ -13,8 +13,8 @@ import struct import sys import tempfile -import command -import tools +from patman import command +from patman import tools def fdt32_to_cpu(val): """Convert a device tree cell to an integer diff --git a/tools/dtoc/dtoc.py b/tools/dtoc/main.py similarity index 94% rename from tools/dtoc/dtoc.py rename to tools/dtoc/main.py index f31cba900e..b94d9c301f 100755 --- a/tools/dtoc/dtoc.py +++ b/tools/dtoc/main.py @@ -25,8 +25,6 @@ options. For more information about the use of this options and tool please see doc/driver-model/of-plat.rst """ -from __future__ import print_function - from optparse import OptionParser import os import sys @@ -34,15 +32,15 @@ import unittest # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(our_path, '../patman')) +sys.path.append(os.path.join(our_path, '..')) # Bring in the libfdt module sys.path.insert(0, 'scripts/dtc/pylibfdt') sys.path.insert(0, os.path.join(our_path, '../../build-sandbox_spl/scripts/dtc/pylibfdt')) -import dtb_platdata -import test_util +from dtoc import dtb_platdata +from patman import test_util def run_tests(args): """Run all the test we have for dtoc @@ -79,7 +77,7 @@ def run_tests(args): def RunTestCoverage(): """Run the tests and check that we get 100% coverage""" sys.argv = [sys.argv[0]] - test_util.RunTestCoverage('tools/dtoc/dtoc.py', '/dtoc.py', + test_util.RunTestCoverage('tools/dtoc/dtoc', '/main.py', ['tools/patman/*.py', '*/fdt*', '*test*'], options.build_dir) diff --git a/tools/dtoc/test_dtoc.py b/tools/dtoc/test_dtoc.py index d733b70655..8498e8303c 100755 --- a/tools/dtoc/test_dtoc.py +++ b/tools/dtoc/test_dtoc.py @@ -9,22 +9,20 @@ This includes unit tests for some functions and functional tests for the dtoc tool. """ -from __future__ import print_function - import collections import os import struct import unittest -import dtb_platdata +from dtoc import dtb_platdata from dtb_platdata import conv_name_to_c from dtb_platdata import get_compat_name from dtb_platdata import get_value from dtb_platdata import tab_to -import fdt -import fdt_util -import test_util -import tools +from dtoc import fdt +from dtoc import fdt_util +from patman import test_util +from patman import tools our_path = os.path.dirname(os.path.realpath(__file__)) diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py index 3316757e61..375e906424 100755 --- a/tools/dtoc/test_fdt.py +++ b/tools/dtoc/test_fdt.py @@ -4,8 +4,6 @@ # Written by Simon Glass # -from __future__ import print_function - from optparse import OptionParser import glob import os @@ -16,17 +14,16 @@ import unittest # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) -for dirname in ['../patman', '..']: - sys.path.insert(0, os.path.join(our_path, dirname)) +sys.path.insert(1, os.path.join(our_path, '..')) -import command -import fdt +from dtoc import fdt +from dtoc import fdt_util +from dtoc.fdt_util import fdt32_to_cpu from fdt import TYPE_BYTE, TYPE_INT, TYPE_STRING, TYPE_BOOL, BytesToValue -import fdt_util -from fdt_util import fdt32_to_cpu import libfdt -import test_util -import tools +from patman import command +from patman import test_util +from patman import tools def _GetPropertyValue(dtb, node, prop_name): """Low-level function to get the property value based on its offset diff --git a/tools/fdtgrep.c b/tools/fdtgrep.c index 2a8058f57f..7e168a1e6b 100644 --- a/tools/fdtgrep.c +++ b/tools/fdtgrep.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "fdt_host.h" #include "libfdt_internal.h" diff --git a/tools/genboardscfg.py b/tools/genboardscfg.py index 4f6382bc7c..4ee7aa1f89 100755 --- a/tools/genboardscfg.py +++ b/tools/genboardscfg.py @@ -22,8 +22,7 @@ import sys import tempfile import time -sys.path.insert(1, os.path.join(os.path.dirname(__file__), 'buildman')) -import kconfiglib +from buildman import kconfiglib ### constant variables ### OUTPUT_FILE = 'boards.cfg' diff --git a/tools/image-host.c b/tools/image-host.c index 5bb68965e7..9a83b7f675 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -10,6 +10,7 @@ #include "mkimage.h" #include +#include #include #include diff --git a/tools/libfdt/fdt_ro.c b/tools/libfdt/fdt_ro.c new file mode 100644 index 0000000000..8a9735a48c --- /dev/null +++ b/tools/libfdt/fdt_ro.c @@ -0,0 +1,2 @@ +#include "fdt_host.h" +#include "../scripts/dtc/libfdt/fdt_ro.c" diff --git a/tools/moveconfig.py b/tools/moveconfig.py index d8bf7fd071..36361f9ed1 100755 --- a/tools/moveconfig.py +++ b/tools/moveconfig.py @@ -314,11 +314,9 @@ import tempfile import threading import time -sys.path.append(os.path.join(os.path.dirname(__file__), 'buildman')) -sys.path.append(os.path.join(os.path.dirname(__file__), 'patman')) -import bsettings -import kconfiglib -import toolchain +from buildman import bsettings +from buildman import kconfiglib +from buildman import toolchain SHOW_GNU_MAKE = 'scripts/show-gnu-make' SLEEP_TIME=0.03 diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py index d47ea438b7..795b519314 100644 --- a/tools/patman/checkpatch.py +++ b/tools/patman/checkpatch.py @@ -3,12 +3,14 @@ # import collections -import command -import gitutil import os import re import sys -import terminal + +from patman import command +from patman import gitutil +from patman import terminal +from patman import tools def FindCheckPatch(): top_level = gitutil.GetTopLevel() diff --git a/tools/patman/command.py b/tools/patman/command.py index 5fbd2c4a3e..e67ac159e5 100644 --- a/tools/patman/command.py +++ b/tools/patman/command.py @@ -3,8 +3,9 @@ # import os -import cros_subprocess -import tools + +from patman import cros_subprocess +from patman import tools """Shell command ease-ups for Python.""" diff --git a/tools/patman/func_test.py b/tools/patman/func_test.py index 76319fff37..b7e2825de8 100644 --- a/tools/patman/func_test.py +++ b/tools/patman/func_test.py @@ -12,15 +12,12 @@ import sys import tempfile import unittest -try: - from StringIO import StringIO -except ImportError: - from io import StringIO +from io import StringIO -import gitutil -import patchstream -import settings -import tools +from patman import gitutil +from patman import patchstream +from patman import settings +from patman import tools @contextlib.contextmanager diff --git a/tools/patman/get_maintainer.py b/tools/patman/get_maintainer.py index 0ffb55a821..473f0feebf 100644 --- a/tools/patman/get_maintainer.py +++ b/tools/patman/get_maintainer.py @@ -2,10 +2,11 @@ # Copyright (c) 2012 The Chromium OS Authors. # -import command -import gitutil import os +from patman import command +from patman import gitutil + def FindGetMaintainer(): """Look for the get_maintainer.pl script. diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py index a2a225c6b9..770a051014 100644 --- a/tools/patman/gitutil.py +++ b/tools/patman/gitutil.py @@ -2,17 +2,17 @@ # Copyright (c) 2011 The Chromium OS Authors. # -import command import re import os -import series import subprocess import sys -import terminal -import checkpatch -import settings -import tools +from patman import checkpatch +from patman import command +from patman import series +from patman import settings +from patman import terminal +from patman import tools # True to use --no-decorate - we check this in Setup() use_no_decorate = True diff --git a/tools/patman/patman.py b/tools/patman/main.py similarity index 93% rename from tools/patman/patman.py rename to tools/patman/main.py index 7f4ac9aef4..f3d9c0c434 100755 --- a/tools/patman/patman.py +++ b/tools/patman/main.py @@ -12,19 +12,20 @@ import re import sys import unittest +if __name__ == "__main__": + # Allow 'from patman import xxx to work' + our_path = os.path.dirname(os.path.realpath(__file__)) + sys.path.append(os.path.join(our_path, '..')) + # Our modules -try: - from patman import checkpatch, command, gitutil, patchstream, \ - project, settings, terminal, test -except ImportError: - import checkpatch - import command - import gitutil - import patchstream - import project - import settings - import terminal - import test +from patman import checkpatch +from patman import command +from patman import gitutil +from patman import patchstream +from patman import project +from patman import settings +from patman import terminal +from patman import test parser = OptionParser() @@ -85,7 +86,7 @@ if __name__ != "__main__": # Run our meagre tests elif options.test: import doctest - import func_test + from patman import func_test sys.argv = [sys.argv[0]] result = unittest.TestResult() diff --git a/tools/patman/patchstream.py b/tools/patman/patchstream.py index df3eb7483b..405297505c 100644 --- a/tools/patman/patchstream.py +++ b/tools/patman/patchstream.py @@ -9,10 +9,10 @@ import re import shutil import tempfile -import command -import commit -import gitutil -from series import Series +from patman import command +from patman import commit +from patman import gitutil +from patman.series import Series # Tags that we detect and remove re_remove = re.compile('^BUG=|^TEST=|^BRANCH=|^Review URL:' diff --git a/tools/patman/patman b/tools/patman/patman index 6cc3d7a56a..11a5d8e18a 120000 --- a/tools/patman/patman +++ b/tools/patman/patman @@ -1 +1 @@ -patman.py \ No newline at end of file +main.py \ No newline at end of file diff --git a/tools/patman/project.py b/tools/patman/project.py index 1d9cfc0625..2dfc303729 100644 --- a/tools/patman/project.py +++ b/tools/patman/project.py @@ -4,7 +4,7 @@ import os.path -import gitutil +from patman import gitutil def DetectProject(): """Autodetect the name of the current project. diff --git a/tools/patman/series.py b/tools/patman/series.py index 6d9d48b123..e5e28cebdf 100644 --- a/tools/patman/series.py +++ b/tools/patman/series.py @@ -2,16 +2,14 @@ # Copyright (c) 2011 The Chromium OS Authors. # -from __future__ import print_function - import itertools import os -import get_maintainer -import gitutil -import settings -import terminal -import tools +from patman import get_maintainer +from patman import gitutil +from patman import settings +from patman import terminal +from patman import tools # Series-xxx tags that we understand valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name', diff --git a/tools/patman/settings.py b/tools/patman/settings.py index 5dc83a8500..ca74fc611f 100644 --- a/tools/patman/settings.py +++ b/tools/patman/settings.py @@ -2,8 +2,6 @@ # Copyright (c) 2011 The Chromium OS Authors. # -from __future__ import print_function - try: import configparser as ConfigParser except: @@ -12,9 +10,9 @@ except: import os import re -import command -import gitutil -import tools +from patman import command +from patman import gitutil +from patman import tools """Default settings per-project. @@ -36,10 +34,7 @@ class _ProjectConfigParser(ConfigParser.SafeConfigParser): - Merge general default settings/aliases with project-specific ones. # Sample config used for tests below... - >>> try: - ... from StringIO import StringIO - ... except ImportError: - ... from io import StringIO + >>> from io import StringIO >>> sample_config = ''' ... [alias] ... me: Peter P. diff --git a/tools/patman/terminal.py b/tools/patman/terminal.py index 5c9e3eea20..c709438bdc 100644 --- a/tools/patman/terminal.py +++ b/tools/patman/terminal.py @@ -7,8 +7,6 @@ This module handles terminal interaction including ANSI color codes. """ -from __future__ import print_function - import os import re import shutil diff --git a/tools/patman/test.py b/tools/patman/test.py index 889e186606..e7f709e34c 100644 --- a/tools/patman/test.py +++ b/tools/patman/test.py @@ -8,11 +8,11 @@ import os import tempfile import unittest -import checkpatch -import gitutil -import patchstream -import series -import commit +from patman import checkpatch +from patman import gitutil +from patman import patchstream +from patman import series +from patman import commit class TestPatch(unittest.TestCase): diff --git a/tools/patman/test_util.py b/tools/patman/test_util.py index 09f258c26b..4d28d9fc92 100644 --- a/tools/patman/test_util.py +++ b/tools/patman/test_util.py @@ -3,21 +3,23 @@ # Copyright (c) 2016 Google, Inc # -from __future__ import print_function - from contextlib import contextmanager import glob +import multiprocessing import os import sys +import unittest -import command +from patman import command +from patman import test_util +from io import StringIO + +use_concurrent = True try: - from StringIO import StringIO -except ImportError: - from io import StringIO - -PYTHON = 'python%d' % sys.version_info[0] + from concurrencytest import ConcurrentTestSuite, fork_for_tests +except: + use_concurrent = False def RunTestCoverage(prog, filter_fname, exclude_list, build_dir, required=None): @@ -46,12 +48,15 @@ def RunTestCoverage(prog, filter_fname, exclude_list, build_dir, required=None): glob_list = [] glob_list += exclude_list glob_list += ['*libfdt.py', '*site-packages*', '*dist-packages*'] - test_cmd = 'test' if 'binman.py' in prog else '-t' - cmd = ('PYTHONPATH=$PYTHONPATH:%s/sandbox_spl/tools %s-coverage run ' - '--omit "%s" %s %s -P1' % (build_dir, PYTHON, ','.join(glob_list), + test_cmd = 'test' if 'binman' in prog else '-t' + prefix = '' + if build_dir: + prefix = 'PYTHONPATH=$PYTHONPATH:%s/sandbox_spl/tools ' % build_dir + cmd = ('%spython3-coverage run ' + '--omit "%s" %s %s -P1' % (prefix, ','.join(glob_list), prog, test_cmd)) os.system(cmd) - stdout = command.Output('%s-coverage' % PYTHON, 'report') + stdout = command.Output('python3-coverage', 'report') lines = stdout.splitlines() if required: # Convert '/path/to/name.py' just the module name 'name' @@ -70,8 +75,8 @@ def RunTestCoverage(prog, filter_fname, exclude_list, build_dir, required=None): print(coverage) if coverage != '100%': print(stdout) - print("Type '%s-coverage html' to get a report in " - 'htmlcov/index.html' % PYTHON) + print("Type 'python3-coverage html' to get a report in " + 'htmlcov/index.html') print('Coverage error: %s, but should be 100%%' % coverage) ok = False if not ok: @@ -90,3 +95,95 @@ def capture_sys_output(): yield capture_out, capture_err finally: sys.stdout, sys.stderr = old_out, old_err + + +def ReportResult(toolname:str, test_name: str, result: unittest.TestResult): + """Report the results from a suite of tests + + Args: + toolname: Name of the tool that ran the tests + test_name: Name of test that was run, or None for all + result: A unittest.TestResult object containing the results + """ + # Remove errors which just indicate a missing test. Since Python v3.5 If an + # ImportError or AttributeError occurs while traversing name then a + # synthetic test that raises that error when run will be returned. These + # errors are included in the errors accumulated by result.errors. + if test_name: + errors = [] + + for test, err in result.errors: + if ("has no attribute '%s'" % test_name) not in err: + errors.append((test, err)) + result.testsRun -= 1 + result.errors = errors + + print(result) + for test, err in result.errors: + print(test.id(), err) + for test, err in result.failures: + print(err, result.failures) + if result.skipped: + print('%d binman test%s SKIPPED:' % + (len(result.skipped), 's' if len(result.skipped) > 1 else '')) + for skip_info in result.skipped: + print('%s: %s' % (skip_info[0], skip_info[1])) + if result.errors or result.failures: + print('binman tests FAILED') + return 1 + return 0 + + +def RunTestSuites(result, debug, verbosity, test_preserve_dirs, processes, + test_name, toolpath, test_class_list): + """Run a series of test suites and collect the results + + Args: + result: A unittest.TestResult object to add the results to + debug: True to enable debugging, which shows a full stack trace on error + verbosity: Verbosity level to use (0-4) + test_preserve_dirs: True to preserve the input directory used by tests + so that it can be examined afterwards (only useful for debugging + tests). If a single test is selected (in args[0]) it also preserves + the output directory for this test. Both directories are displayed + on the command line. + processes: Number of processes to use to run tests (None=same as #CPUs) + test_name: Name of test to run, or None for all + toolpath: List of paths to use for tools + test_class_list: List of test classes to run + """ + for module in []: + suite = doctest.DocTestSuite(module) + suite.run(result) + + sys.argv = [sys.argv[0]] + if debug: + sys.argv.append('-D') + if verbosity: + sys.argv.append('-v%d' % verbosity) + if toolpath: + for path in toolpath: + sys.argv += ['--toolpath', path] + + suite = unittest.TestSuite() + loader = unittest.TestLoader() + for module in test_class_list: + # Test the test module about our arguments, if it is interested + if hasattr(module, 'setup_test_args'): + setup_test_args = getattr(module, 'setup_test_args') + setup_test_args(preserve_indir=test_preserve_dirs, + preserve_outdirs=test_preserve_dirs and test_name is not None, + toolpath=toolpath, verbosity=verbosity) + if test_name: + try: + suite.addTests(loader.loadTestsFromName(test_name, module)) + except AttributeError: + continue + else: + suite.addTests(loader.loadTestsFromTestCase(module)) + if use_concurrent and processes != 1: + concurrent_suite = ConcurrentTestSuite(suite, + fork_for_tests(processes or multiprocessing.cpu_count())) + concurrent_suite.run(result) + else: + suite.run(result) diff --git a/tools/patman/tools.py b/tools/patman/tools.py index 3feddb292f..b50370dfe8 100644 --- a/tools/patman/tools.py +++ b/tools/patman/tools.py @@ -3,9 +3,6 @@ # Copyright (c) 2016 Google, Inc # -from __future__ import print_function - -import command import glob import os import shutil @@ -13,7 +10,8 @@ import struct import sys import tempfile -import tout +from patman import command +from patman import tout # Output directly (generally this is temporary) outdir = None diff --git a/tools/patman/tout.py b/tools/patman/tout.py index 2a384851b0..c7e3272096 100644 --- a/tools/patman/tout.py +++ b/tools/patman/tout.py @@ -4,11 +4,9 @@ # Terminal output logging. # -from __future__ import print_function - import sys -import terminal +from patman import terminal # Output verbosity levels that we support ERROR, WARNING, NOTICE, INFO, DETAIL, DEBUG = range(6) diff --git a/tools/rmboard.py b/tools/rmboard.py index df4f04b01c..06c3562ad8 100755 --- a/tools/rmboard.py +++ b/tools/rmboard.py @@ -1,4 +1,4 @@ -#! /usr/bin/python +#! /usr/bin/python3 # SPDX-License-Identifier: GPL-2.0+ # Copyright 2019 Google LLC # @@ -23,8 +23,6 @@ This script works by: Search for ## to update the commit message manually. """ -from __future__ import print_function - import glob import os import re @@ -32,9 +30,8 @@ import sys # Bring in the patman libraries our_path = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(our_path, '../tools/patman')) -import command +from patman import command def rm_kconfig_include(path): """Remove a path from Kconfig files