1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun #ifndef _INCLUDE_LIBFDT_H_ 3*4882a593Smuzhiyun #define _INCLUDE_LIBFDT_H_ 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun #ifndef USE_HOSTCC 6*4882a593Smuzhiyun #include <linux/libfdt_env.h> 7*4882a593Smuzhiyun #endif 8*4882a593Smuzhiyun #include "../../scripts/dtc/libfdt/libfdt.h" 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun /* U-Boot local hacks */ 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun #ifndef SWIG /* Not available in Python */ 13*4882a593Smuzhiyun struct fdt_region { 14*4882a593Smuzhiyun int offset; 15*4882a593Smuzhiyun int size; 16*4882a593Smuzhiyun }; 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun /* 19*4882a593Smuzhiyun * Flags for fdt_find_regions() 20*4882a593Smuzhiyun * 21*4882a593Smuzhiyun * Add a region for the string table (always the last region) 22*4882a593Smuzhiyun */ 23*4882a593Smuzhiyun #define FDT_REG_ADD_STRING_TAB (1 << 0) 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun /* 26*4882a593Smuzhiyun * Add all supernodes of a matching node/property, useful for creating a 27*4882a593Smuzhiyun * valid subset tree 28*4882a593Smuzhiyun */ 29*4882a593Smuzhiyun #define FDT_REG_SUPERNODES (1 << 1) 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun /* Add the FDT_BEGIN_NODE tags of subnodes, including their names */ 32*4882a593Smuzhiyun #define FDT_REG_DIRECT_SUBNODES (1 << 2) 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun /* Add all subnodes of a matching node */ 35*4882a593Smuzhiyun #define FDT_REG_ALL_SUBNODES (1 << 3) 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun /* Add a region for the mem_rsvmap table (always the first region) */ 38*4882a593Smuzhiyun #define FDT_REG_ADD_MEM_RSVMAP (1 << 4) 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun /* Indicates what an fdt part is (node, property, value) */ 41*4882a593Smuzhiyun #define FDT_IS_NODE (1 << 0) 42*4882a593Smuzhiyun #define FDT_IS_PROP (1 << 1) 43*4882a593Smuzhiyun #define FDT_IS_VALUE (1 << 2) /* not supported */ 44*4882a593Smuzhiyun #define FDT_IS_COMPAT (1 << 3) /* used internally */ 45*4882a593Smuzhiyun #define FDT_NODE_HAS_PROP (1 << 4) /* node contains prop */ 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun #define FDT_ANY_GLOBAL (FDT_IS_NODE | FDT_IS_PROP | FDT_IS_VALUE | \ 48*4882a593Smuzhiyun FDT_IS_COMPAT) 49*4882a593Smuzhiyun #define FDT_IS_ANY 0x1f /* all the above */ 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun /* We set a reasonable limit on the number of nested nodes */ 52*4882a593Smuzhiyun #define FDT_MAX_DEPTH 32 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun /* Decribes what we want to include from the current tag */ 55*4882a593Smuzhiyun enum want_t { 56*4882a593Smuzhiyun WANT_NOTHING, 57*4882a593Smuzhiyun WANT_NODES_ONLY, /* No properties */ 58*4882a593Smuzhiyun WANT_NODES_AND_PROPS, /* Everything for one level */ 59*4882a593Smuzhiyun WANT_ALL_NODES_AND_PROPS /* Everything for all levels */ 60*4882a593Smuzhiyun }; 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun /* Keeps track of the state at parent nodes */ 63*4882a593Smuzhiyun struct fdt_subnode_stack { 64*4882a593Smuzhiyun int offset; /* Offset of node */ 65*4882a593Smuzhiyun enum want_t want; /* The 'want' value here */ 66*4882a593Smuzhiyun int included; /* 1 if we included this node, 0 if not */ 67*4882a593Smuzhiyun }; 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun struct fdt_region_ptrs { 70*4882a593Smuzhiyun int depth; /* Current tree depth */ 71*4882a593Smuzhiyun int done; /* What we have completed scanning */ 72*4882a593Smuzhiyun enum want_t want; /* What we are currently including */ 73*4882a593Smuzhiyun char *end; /* Pointer to end of full node path */ 74*4882a593Smuzhiyun int nextoffset; /* Next node offset to check */ 75*4882a593Smuzhiyun }; 76*4882a593Smuzhiyun 77*4882a593Smuzhiyun /* The state of our finding algortihm */ 78*4882a593Smuzhiyun struct fdt_region_state { 79*4882a593Smuzhiyun struct fdt_subnode_stack stack[FDT_MAX_DEPTH]; /* node stack */ 80*4882a593Smuzhiyun struct fdt_region *region; /* Contains list of regions found */ 81*4882a593Smuzhiyun int count; /* Numnber of regions found */ 82*4882a593Smuzhiyun const void *fdt; /* FDT blob */ 83*4882a593Smuzhiyun int max_regions; /* Maximum regions to find */ 84*4882a593Smuzhiyun int can_merge; /* 1 if we can merge with previous region */ 85*4882a593Smuzhiyun int start; /* Start position of current region */ 86*4882a593Smuzhiyun struct fdt_region_ptrs ptrs; /* Pointers for what we are up to */ 87*4882a593Smuzhiyun }; 88*4882a593Smuzhiyun 89*4882a593Smuzhiyun /** 90*4882a593Smuzhiyun * fdt_find_regions() - find regions in device tree 91*4882a593Smuzhiyun * 92*4882a593Smuzhiyun * Given a list of nodes to include and properties to exclude, find 93*4882a593Smuzhiyun * the regions of the device tree which describe those included parts. 94*4882a593Smuzhiyun * 95*4882a593Smuzhiyun * The intent is to get a list of regions which will be invariant provided 96*4882a593Smuzhiyun * those parts are invariant. For example, if you request a list of regions 97*4882a593Smuzhiyun * for all nodes but exclude the property "data", then you will get the 98*4882a593Smuzhiyun * same region contents regardless of any change to "data" properties. 99*4882a593Smuzhiyun * 100*4882a593Smuzhiyun * This function can be used to produce a byte-stream to send to a hashing 101*4882a593Smuzhiyun * function to verify that critical parts of the FDT have not changed. 102*4882a593Smuzhiyun * 103*4882a593Smuzhiyun * Nodes which are given in 'inc' are included in the region list, as 104*4882a593Smuzhiyun * are the names of the immediate subnodes nodes (but not the properties 105*4882a593Smuzhiyun * or subnodes of those subnodes). 106*4882a593Smuzhiyun * 107*4882a593Smuzhiyun * For eaxample "/" means to include the root node, all root properties 108*4882a593Smuzhiyun * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter 109*4882a593Smuzhiyun * ensures that we capture the names of the subnodes. In a hashing situation 110*4882a593Smuzhiyun * it prevents the root node from changing at all Any change to non-excluded 111*4882a593Smuzhiyun * properties, names of subnodes or number of subnodes would be detected. 112*4882a593Smuzhiyun * 113*4882a593Smuzhiyun * When used with FITs this provides the ability to hash and sign parts of 114*4882a593Smuzhiyun * the FIT based on different configurations in the FIT. Then it is 115*4882a593Smuzhiyun * impossible to change anything about that configuration (include images 116*4882a593Smuzhiyun * attached to the configuration), but it may be possible to add new 117*4882a593Smuzhiyun * configurations, new images or new signatures within the existing 118*4882a593Smuzhiyun * framework. 119*4882a593Smuzhiyun * 120*4882a593Smuzhiyun * Adding new properties to a device tree may result in the string table 121*4882a593Smuzhiyun * being extended (if the new property names are different from those 122*4882a593Smuzhiyun * already added). This function can optionally include a region for 123*4882a593Smuzhiyun * the string table so that this can be part of the hash too. 124*4882a593Smuzhiyun * 125*4882a593Smuzhiyun * The device tree header is not included in the list. 126*4882a593Smuzhiyun * 127*4882a593Smuzhiyun * @fdt: Device tree to check 128*4882a593Smuzhiyun * @inc: List of node paths to included 129*4882a593Smuzhiyun * @inc_count: Number of node paths in list 130*4882a593Smuzhiyun * @exc_prop: List of properties names to exclude 131*4882a593Smuzhiyun * @exc_prop_count: Number of properties in exclude list 132*4882a593Smuzhiyun * @region: Returns list of regions 133*4882a593Smuzhiyun * @max_region: Maximum length of region list 134*4882a593Smuzhiyun * @path: Pointer to a temporary string for the function to use for 135*4882a593Smuzhiyun * building path names 136*4882a593Smuzhiyun * @path_len: Length of path, must be large enough to hold the longest 137*4882a593Smuzhiyun * path in the tree 138*4882a593Smuzhiyun * @add_string_tab: 1 to add a region for the string table 139*4882a593Smuzhiyun * @return number of regions in list. If this is >max_regions then the 140*4882a593Smuzhiyun * region array was exhausted. You should increase max_regions and try 141*4882a593Smuzhiyun * the call again. 142*4882a593Smuzhiyun */ 143*4882a593Smuzhiyun int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, 144*4882a593Smuzhiyun char * const exc_prop[], int exc_prop_count, 145*4882a593Smuzhiyun struct fdt_region region[], int max_regions, 146*4882a593Smuzhiyun char *path, int path_len, int add_string_tab); 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun /** 149*4882a593Smuzhiyun * fdt_first_region() - find regions in device tree 150*4882a593Smuzhiyun * 151*4882a593Smuzhiyun * Given a nodes and properties to include and properties to exclude, find 152*4882a593Smuzhiyun * the regions of the device tree which describe those included parts. 153*4882a593Smuzhiyun * 154*4882a593Smuzhiyun * The use for this function is twofold. Firstly it provides a convenient 155*4882a593Smuzhiyun * way of performing a structure-aware grep of the tree. For example it is 156*4882a593Smuzhiyun * possible to grep for a node and get all the properties associated with 157*4882a593Smuzhiyun * that node. Trees can be subsetted easily, by specifying the nodes that 158*4882a593Smuzhiyun * are required, and then writing out the regions returned by this function. 159*4882a593Smuzhiyun * This is useful for small resource-constrained systems, such as boot 160*4882a593Smuzhiyun * loaders, which want to use an FDT but do not need to know about all of 161*4882a593Smuzhiyun * it. 162*4882a593Smuzhiyun * 163*4882a593Smuzhiyun * Secondly it makes it easy to hash parts of the tree and detect changes. 164*4882a593Smuzhiyun * The intent is to get a list of regions which will be invariant provided 165*4882a593Smuzhiyun * those parts are invariant. For example, if you request a list of regions 166*4882a593Smuzhiyun * for all nodes but exclude the property "data", then you will get the 167*4882a593Smuzhiyun * same region contents regardless of any change to "data" properties. 168*4882a593Smuzhiyun * 169*4882a593Smuzhiyun * This function can be used to produce a byte-stream to send to a hashing 170*4882a593Smuzhiyun * function to verify that critical parts of the FDT have not changed. 171*4882a593Smuzhiyun * Note that semantically null changes in order could still cause false 172*4882a593Smuzhiyun * hash misses. Such reordering might happen if the tree is regenerated 173*4882a593Smuzhiyun * from source, and nodes are reordered (the bytes-stream will be emitted 174*4882a593Smuzhiyun * in a different order and many hash functions will detect this). However 175*4882a593Smuzhiyun * if an existing tree is modified using libfdt functions, such as 176*4882a593Smuzhiyun * fdt_add_subnode() and fdt_setprop(), then this problem is avoided. 177*4882a593Smuzhiyun * 178*4882a593Smuzhiyun * The nodes/properties to include/exclude are defined by a function 179*4882a593Smuzhiyun * provided by the caller. This function is called for each node and 180*4882a593Smuzhiyun * property, and must return: 181*4882a593Smuzhiyun * 182*4882a593Smuzhiyun * 0 - to exclude this part 183*4882a593Smuzhiyun * 1 - to include this part 184*4882a593Smuzhiyun * -1 - for FDT_IS_PROP only: no information is available, so include 185*4882a593Smuzhiyun * if its containing node is included 186*4882a593Smuzhiyun * 187*4882a593Smuzhiyun * The last case is only used to deal with properties. Often a property is 188*4882a593Smuzhiyun * included if its containing node is included - this is the case where 189*4882a593Smuzhiyun * -1 is returned.. However if the property is specifically required to be 190*4882a593Smuzhiyun * included/excluded, then 0 or 1 can be returned. Note that including a 191*4882a593Smuzhiyun * property when the FDT_REG_SUPERNODES flag is given will force its 192*4882a593Smuzhiyun * containing node to be included since it is not valid to have a property 193*4882a593Smuzhiyun * that is not in a node. 194*4882a593Smuzhiyun * 195*4882a593Smuzhiyun * Using the information provided, the inclusion of a node can be controlled 196*4882a593Smuzhiyun * either by a node name or its compatible string, or any other property 197*4882a593Smuzhiyun * that the function can determine. 198*4882a593Smuzhiyun * 199*4882a593Smuzhiyun * As an example, including node "/" means to include the root node and all 200*4882a593Smuzhiyun * root properties. A flag provides a way of also including supernodes (of 201*4882a593Smuzhiyun * which there is none for the root node), and another flag includes 202*4882a593Smuzhiyun * immediate subnodes, so in this case we would get the FDT_BEGIN_NODE and 203*4882a593Smuzhiyun * FDT_END_NODE of all subnodes of /. 204*4882a593Smuzhiyun * 205*4882a593Smuzhiyun * The subnode feature helps in a hashing situation since it prevents the 206*4882a593Smuzhiyun * root node from changing at all. Any change to non-excluded properties, 207*4882a593Smuzhiyun * names of subnodes or number of subnodes would be detected. 208*4882a593Smuzhiyun * 209*4882a593Smuzhiyun * When used with FITs this provides the ability to hash and sign parts of 210*4882a593Smuzhiyun * the FIT based on different configurations in the FIT. Then it is 211*4882a593Smuzhiyun * impossible to change anything about that configuration (include images 212*4882a593Smuzhiyun * attached to the configuration), but it may be possible to add new 213*4882a593Smuzhiyun * configurations, new images or new signatures within the existing 214*4882a593Smuzhiyun * framework. 215*4882a593Smuzhiyun * 216*4882a593Smuzhiyun * Adding new properties to a device tree may result in the string table 217*4882a593Smuzhiyun * being extended (if the new property names are different from those 218*4882a593Smuzhiyun * already added). This function can optionally include a region for 219*4882a593Smuzhiyun * the string table so that this can be part of the hash too. This is always 220*4882a593Smuzhiyun * the last region. 221*4882a593Smuzhiyun * 222*4882a593Smuzhiyun * The FDT also has a mem_rsvmap table which can also be included, and is 223*4882a593Smuzhiyun * always the first region if so. 224*4882a593Smuzhiyun * 225*4882a593Smuzhiyun * The device tree header is not included in the region list. Since the 226*4882a593Smuzhiyun * contents of the FDT are changing (shrinking, often), the caller will need 227*4882a593Smuzhiyun * to regenerate the header anyway. 228*4882a593Smuzhiyun * 229*4882a593Smuzhiyun * @fdt: Device tree to check 230*4882a593Smuzhiyun * @h_include: Function to call to determine whether to include a part or 231*4882a593Smuzhiyun * not: 232*4882a593Smuzhiyun * 233*4882a593Smuzhiyun * @priv: Private pointer as passed to fdt_find_regions() 234*4882a593Smuzhiyun * @fdt: Pointer to FDT blob 235*4882a593Smuzhiyun * @offset: Offset of this node / property 236*4882a593Smuzhiyun * @type: Type of this part, FDT_IS_... 237*4882a593Smuzhiyun * @data: Pointer to data (node name, property name, compatible 238*4882a593Smuzhiyun * string, value (not yet supported) 239*4882a593Smuzhiyun * @size: Size of data, or 0 if none 240*4882a593Smuzhiyun * @return 0 to exclude, 1 to include, -1 if no information is 241*4882a593Smuzhiyun * available 242*4882a593Smuzhiyun * @priv: Private pointer passed to h_include 243*4882a593Smuzhiyun * @region: Returns list of regions, sorted by offset 244*4882a593Smuzhiyun * @max_regions: Maximum length of region list 245*4882a593Smuzhiyun * @path: Pointer to a temporary string for the function to use for 246*4882a593Smuzhiyun * building path names 247*4882a593Smuzhiyun * @path_len: Length of path, must be large enough to hold the longest 248*4882a593Smuzhiyun * path in the tree 249*4882a593Smuzhiyun * @flags: Various flags that control the region algortihm, see 250*4882a593Smuzhiyun * FDT_REG_... 251*4882a593Smuzhiyun * @return number of regions in list. If this is >max_regions then the 252*4882a593Smuzhiyun * region array was exhausted. You should increase max_regions and try 253*4882a593Smuzhiyun * the call again. Only the first max_regions elements are available in the 254*4882a593Smuzhiyun * array. 255*4882a593Smuzhiyun * 256*4882a593Smuzhiyun * On error a -ve value is return, which can be: 257*4882a593Smuzhiyun * 258*4882a593Smuzhiyun * -FDT_ERR_BADSTRUCTURE (too deep or more END tags than BEGIN tags 259*4882a593Smuzhiyun * -FDT_ERR_BADLAYOUT 260*4882a593Smuzhiyun * -FDT_ERR_NOSPACE (path area is too small) 261*4882a593Smuzhiyun */ 262*4882a593Smuzhiyun int fdt_first_region(const void *fdt, 263*4882a593Smuzhiyun int (*h_include)(void *priv, const void *fdt, int offset, 264*4882a593Smuzhiyun int type, const char *data, int size), 265*4882a593Smuzhiyun void *priv, struct fdt_region *region, 266*4882a593Smuzhiyun char *path, int path_len, int flags, 267*4882a593Smuzhiyun struct fdt_region_state *info); 268*4882a593Smuzhiyun 269*4882a593Smuzhiyun /** fdt_next_region() - find next region 270*4882a593Smuzhiyun * 271*4882a593Smuzhiyun * See fdt_first_region() for full description. This function finds the 272*4882a593Smuzhiyun * next region according to the provided parameters, which must be the same 273*4882a593Smuzhiyun * as passed to fdt_first_region(). 274*4882a593Smuzhiyun * 275*4882a593Smuzhiyun * This function can additionally return -FDT_ERR_NOTFOUND when there are no 276*4882a593Smuzhiyun * more regions 277*4882a593Smuzhiyun */ 278*4882a593Smuzhiyun int fdt_next_region(const void *fdt, 279*4882a593Smuzhiyun int (*h_include)(void *priv, const void *fdt, int offset, 280*4882a593Smuzhiyun int type, const char *data, int size), 281*4882a593Smuzhiyun void *priv, struct fdt_region *region, 282*4882a593Smuzhiyun char *path, int path_len, int flags, 283*4882a593Smuzhiyun struct fdt_region_state *info); 284*4882a593Smuzhiyun 285*4882a593Smuzhiyun /** 286*4882a593Smuzhiyun * fdt_add_alias_regions() - find aliases that point to existing regions 287*4882a593Smuzhiyun * 288*4882a593Smuzhiyun * Once a device tree grep is complete some of the nodes will be present 289*4882a593Smuzhiyun * and some will have been dropped. This function checks all the alias nodes 290*4882a593Smuzhiyun * to figure out which points point to nodes which are still present. These 291*4882a593Smuzhiyun * aliases need to be kept, along with the nodes they reference. 292*4882a593Smuzhiyun * 293*4882a593Smuzhiyun * Given a list of regions function finds the aliases that still apply and 294*4882a593Smuzhiyun * adds more regions to the list for these. This function is called after 295*4882a593Smuzhiyun * fdt_next_region() has finished returning regions and requires the same 296*4882a593Smuzhiyun * state. 297*4882a593Smuzhiyun * 298*4882a593Smuzhiyun * @fdt: Device tree file to reference 299*4882a593Smuzhiyun * @region: List of regions that will be kept 300*4882a593Smuzhiyun * @count: Number of regions 301*4882a593Smuzhiyun * @max_regions: Number of entries that can fit in @region 302*4882a593Smuzhiyun * @info: Region state as returned from fdt_next_region() 303*4882a593Smuzhiyun * @return new number of regions in @region (i.e. count + the number added) 304*4882a593Smuzhiyun * or -FDT_ERR_NOSPACE if there was not enough space. 305*4882a593Smuzhiyun */ 306*4882a593Smuzhiyun int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count, 307*4882a593Smuzhiyun int max_regions, struct fdt_region_state *info); 308*4882a593Smuzhiyun #endif /* SWIG */ 309*4882a593Smuzhiyun 310*4882a593Smuzhiyun extern struct fdt_header *working_fdt; /* Pointer to the working fdt */ 311*4882a593Smuzhiyun 312*4882a593Smuzhiyun /* adding a ramdisk needs 0x44 bytes in version 2008.10 */ 313*4882a593Smuzhiyun #define FDT_RAMDISK_OVERHEAD 0x80 314*4882a593Smuzhiyun 315*4882a593Smuzhiyun #endif /* _INCLUDE_LIBFDT_H_ */ 316