mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
scripts/dtc: Update to upstream version v1.7.2-62-ga26ef6400bd8
This adds the following commits from upstream: a26ef6400bd8 Restore phandle references from __fixups__ node 05c524db44ff Restore phandle references from __local_fixups__ node db65a3a3f4f0 Restore labels from __symbols__ node 64330c682cac Improve type guessing when compiling to dts format cbb48690c697 Set DTSF_PLUGIN if needed when compiling from dtb ef3b1baf6370 Emit /plugin/ when compiling to .dts with DTSF_PLUGIN set 7c78c8542d73 Added empty node name check 14dd76b96732 fdtdump: Change FDT_PROP prob handling to ease future addition 9a1c801a1a3c Fix discarded const qualifiers 194ac9422ac9 libfdt: fdt_get_name: Add can_assume(VALID_DTB) check 39cae0bd0031 libfdt: Improve size savings in FDT_RO_PROBE slightly b12692473298 libfdt: libfdt_internal.h correct final comment in ASSUME block 7f3184a6c550 libfdt: Remove old MacOS strnlen workaround 9197f1ccd95c checks: Do not check overlays for alias paths e1284ee5dc20 livetree: Add only new data to fixup nodes instead of complete regeneration cba90ce82064 checks: Remove check for graph child addresses 763c6ab4189c livetree: Simplify append_to_property() 739403f22242 libfdt: Drop including string.h from libfdt_internal.h 1c6c51e51b29 Consider drive letters when checking for absolute paths on Windows. 617f3d9b60f7 ci: Add Cirrus CI configuration for FreeBSD testing 04f948e83fef ci: Add GitLab CI configuration for Linux builds e89680263137 ci: Tweaks to GitHub Actions setup 2ad738722b79 build: Add FreeBSD and non-GNU linker compatibility 4132ac08ba95 libfdt: Document most remaining functions 33e66ec845b8 tests: Add compatibility with uutils a0dd7b608102 fdtput: Use strtol() in preference to sscanf() 5b71660724d7 tests: Work around limitation in FreeBSD's printf(1) The graph_child_address check has been removed from upstream. Drop it from the makefiles. Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
This commit is contained in:
@@ -56,7 +56,6 @@ DT_DOCS = $(patsubst $(srctree)/%,%,$(shell $(find_all_cmd)))
|
|||||||
|
|
||||||
override DTC_FLAGS := \
|
override DTC_FLAGS := \
|
||||||
-Wno-avoid_unnecessary_addr_size \
|
-Wno-avoid_unnecessary_addr_size \
|
||||||
-Wno-graph_child_address \
|
|
||||||
-Wno-unique_unit_address \
|
-Wno-unique_unit_address \
|
||||||
-Wunique_unit_address_if_enabled
|
-Wunique_unit_address_if_enabled
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),)
|
|||||||
DTC_FLAGS += -Wno-unit_address_vs_reg \
|
DTC_FLAGS += -Wno-unit_address_vs_reg \
|
||||||
-Wno-avoid_unnecessary_addr_size \
|
-Wno-avoid_unnecessary_addr_size \
|
||||||
-Wno-alias_paths \
|
-Wno-alias_paths \
|
||||||
-Wno-graph_child_address \
|
|
||||||
-Wno-interrupt_map \
|
-Wno-interrupt_map \
|
||||||
-Wno-simple_bus_reg
|
-Wno-simple_bus_reg
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -340,6 +340,14 @@ static void check_node_name_format(struct check *c, struct dt_info *dti,
|
|||||||
}
|
}
|
||||||
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
|
ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars);
|
||||||
|
|
||||||
|
static void check_node_name_not_empty(struct check *c, struct dt_info *dti,
|
||||||
|
struct node *node)
|
||||||
|
{
|
||||||
|
if (node->basenamelen == 0 && node->parent != NULL)
|
||||||
|
FAIL(c, dti, node, "Empty node name");
|
||||||
|
}
|
||||||
|
ERROR(node_name_not_empty, check_node_name_not_empty, NULL, &node_name_chars);
|
||||||
|
|
||||||
static void check_node_name_vs_property_name(struct check *c,
|
static void check_node_name_vs_property_name(struct check *c,
|
||||||
struct dt_info *dti,
|
struct dt_info *dti,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
@@ -718,11 +726,14 @@ static void check_alias_paths(struct check *c, struct dt_info *dti,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prop->val.val || !get_node_by_path(dti->dt, prop->val.val)) {
|
/* This check does not work for overlays with external paths */
|
||||||
|
if (!(dti->dtsflags & DTSF_PLUGIN) &&
|
||||||
|
(!prop->val.val || !get_node_by_path(dti->dt, prop->val.val))) {
|
||||||
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
|
FAIL_PROP(c, dti, node, prop, "aliases property is not a valid node (%s)",
|
||||||
prop->val.val);
|
prop->val.val);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name))
|
if (strspn(prop->name, LOWERCASE DIGITS "-") != strlen(prop->name))
|
||||||
FAIL(c, dti, node, "aliases property name must include only lowercase and '-'");
|
FAIL(c, dti, node, "aliases property name must include only lowercase and '-'");
|
||||||
}
|
}
|
||||||
@@ -1894,34 +1905,9 @@ static void check_graph_endpoint(struct check *c, struct dt_info *dti,
|
|||||||
}
|
}
|
||||||
WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
|
WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes);
|
||||||
|
|
||||||
static void check_graph_child_address(struct check *c, struct dt_info *dti,
|
|
||||||
struct node *node)
|
|
||||||
{
|
|
||||||
int cnt = 0;
|
|
||||||
struct node *child;
|
|
||||||
|
|
||||||
if (node->bus != &graph_ports_bus && node->bus != &graph_port_bus)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for_each_child(node, child) {
|
|
||||||
struct property *prop = get_property(child, "reg");
|
|
||||||
|
|
||||||
/* No error if we have any non-zero unit address */
|
|
||||||
if (prop && propval_cell(prop) != 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt == 1 && node->addr_cells != -1)
|
|
||||||
FAIL(c, dti, node, "graph node has single child node '%s', #address-cells/#size-cells are not necessary",
|
|
||||||
node->children->name);
|
|
||||||
}
|
|
||||||
WARNING(graph_child_address, check_graph_child_address, NULL, &graph_nodes, &graph_port, &graph_endpoint);
|
|
||||||
|
|
||||||
static struct check *check_table[] = {
|
static struct check *check_table[] = {
|
||||||
&duplicate_node_names, &duplicate_property_names,
|
&duplicate_node_names, &duplicate_property_names,
|
||||||
&node_name_chars, &node_name_format, &property_name_chars,
|
&node_name_chars, &node_name_format, &node_name_not_empty, &property_name_chars,
|
||||||
&name_is_string, &name_properties, &node_name_vs_property_name,
|
&name_is_string, &name_properties, &node_name_vs_property_name,
|
||||||
|
|
||||||
&duplicate_label,
|
&duplicate_label,
|
||||||
@@ -2005,7 +1991,7 @@ static struct check *check_table[] = {
|
|||||||
|
|
||||||
&alias_paths,
|
&alias_paths,
|
||||||
|
|
||||||
&graph_nodes, &graph_child_address, &graph_port, &graph_endpoint,
|
&graph_nodes, &graph_port, &graph_endpoint,
|
||||||
|
|
||||||
&always_fail,
|
&always_fail,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -338,9 +338,14 @@ int main(int argc, char *argv[])
|
|||||||
if (auto_label_aliases)
|
if (auto_label_aliases)
|
||||||
generate_label_tree(dti, "aliases", false);
|
generate_label_tree(dti, "aliases", false);
|
||||||
|
|
||||||
|
generate_labels_from_tree(dti, "__symbols__");
|
||||||
|
|
||||||
if (generate_symbols)
|
if (generate_symbols)
|
||||||
generate_label_tree(dti, "__symbols__", true);
|
generate_label_tree(dti, "__symbols__", true);
|
||||||
|
|
||||||
|
fixup_phandles(dti, "__fixups__");
|
||||||
|
local_fixup_phandles(dti, "__local_fixups__");
|
||||||
|
|
||||||
if (generate_fixups) {
|
if (generate_fixups) {
|
||||||
generate_fixups_tree(dti, "__fixups__");
|
generate_fixups_tree(dti, "__fixups__");
|
||||||
generate_local_fixups_tree(dti, "__local_fixups__");
|
generate_local_fixups_tree(dti, "__local_fixups__");
|
||||||
|
|||||||
@@ -339,9 +339,12 @@ struct dt_info *build_dt_info(unsigned int dtsflags,
|
|||||||
struct reserve_info *reservelist,
|
struct reserve_info *reservelist,
|
||||||
struct node *tree, uint32_t boot_cpuid_phys);
|
struct node *tree, uint32_t boot_cpuid_phys);
|
||||||
void sort_tree(struct dt_info *dti);
|
void sort_tree(struct dt_info *dti);
|
||||||
|
void generate_labels_from_tree(struct dt_info *dti, const char *name);
|
||||||
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
|
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph);
|
||||||
void generate_fixups_tree(struct dt_info *dti, const char *name);
|
void generate_fixups_tree(struct dt_info *dti, const char *name);
|
||||||
|
void fixup_phandles(struct dt_info *dti, const char *name);
|
||||||
void generate_local_fixups_tree(struct dt_info *dti, const char *name);
|
void generate_local_fixups_tree(struct dt_info *dti, const char *name);
|
||||||
|
void local_fixup_phandles(struct dt_info *dti, const char *name);
|
||||||
|
|
||||||
/* Checks */
|
/* Checks */
|
||||||
|
|
||||||
@@ -357,6 +360,9 @@ struct dt_info *dt_from_blob(const char *fname);
|
|||||||
|
|
||||||
/* Tree source */
|
/* Tree source */
|
||||||
|
|
||||||
|
void property_add_marker(struct property *prop,
|
||||||
|
enum markertype type, unsigned int offset, char *ref);
|
||||||
|
void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset);
|
||||||
void dt_to_source(FILE *f, struct dt_info *dti);
|
void dt_to_source(FILE *f, struct dt_info *dti);
|
||||||
struct dt_info *dt_from_source(const char *f);
|
struct dt_info *dt_from_source(const char *f);
|
||||||
|
|
||||||
|
|||||||
@@ -807,6 +807,7 @@ struct dt_info *dt_from_blob(const char *fname)
|
|||||||
struct node *tree;
|
struct node *tree;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
unsigned int dtsflags = DTSF_V1;
|
||||||
|
|
||||||
f = srcfile_relative_open(fname, NULL);
|
f = srcfile_relative_open(fname, NULL);
|
||||||
|
|
||||||
@@ -919,5 +920,8 @@ struct dt_info *dt_from_blob(const char *fname)
|
|||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
return build_dt_info(DTSF_V1, reservelist, tree, boot_cpuid_phys);
|
if (get_subnode(tree, "__fixups__") || get_subnode(tree, "__local_fixups__"))
|
||||||
|
dtsflags |= DTSF_PLUGIN;
|
||||||
|
|
||||||
|
return build_dt_info(dtsflags, reservelist, tree, boot_cpuid_phys);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -407,7 +407,8 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
|
|||||||
const char *fixup_str = value;
|
const char *fixup_str = value;
|
||||||
uint32_t path_len, name_len;
|
uint32_t path_len, name_len;
|
||||||
uint32_t fixup_len;
|
uint32_t fixup_len;
|
||||||
char *sep, *endptr;
|
const char *sep;
|
||||||
|
char *endptr;
|
||||||
int poffset, ret;
|
int poffset, ret;
|
||||||
|
|
||||||
fixup_end = memchr(value, '\0', len);
|
fixup_end = memchr(value, '\0', len);
|
||||||
|
|||||||
@@ -306,8 +306,8 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
|
|||||||
const char *nameptr;
|
const char *nameptr;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (((err = fdt_ro_probe_(fdt)) < 0)
|
if (!can_assume(VALID_DTB) && (((err = fdt_ro_probe_(fdt)) < 0)
|
||||||
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
|
|| ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
nameptr = nh->name;
|
nameptr = nh->name;
|
||||||
|
|||||||
@@ -116,6 +116,20 @@ extern "C" {
|
|||||||
/* Low-level functions (you probably don't need these) */
|
/* Low-level functions (you probably don't need these) */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_offset_ptr - safely get a byte range within the device tree blob
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
* @offset: Offset within the blob to the desired byte range
|
||||||
|
* @checklen: Required length of the byte range
|
||||||
|
*
|
||||||
|
* fdt_offset_ptr() returns a pointer to the byte range of length @checklen at
|
||||||
|
* the given @offset within the device tree blob, after verifying that the byte
|
||||||
|
* range fits entirely within the blob and does not overflow.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* pointer to the byte range, on success
|
||||||
|
* NULL, if the requested range does not fit within the blob
|
||||||
|
*/
|
||||||
#ifndef SWIG /* This function is not useful in Python */
|
#ifndef SWIG /* This function is not useful in Python */
|
||||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
|
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
|
||||||
#endif
|
#endif
|
||||||
@@ -124,6 +138,20 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
|
|||||||
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
|
return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_next_tag - get next tag in the device tree
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
* @offset: Offset within the blob to start searching
|
||||||
|
* @nextoffset: Pointer to variable to store the offset of the next tag
|
||||||
|
*
|
||||||
|
* fdt_next_tag() returns the tag type of the next tag in the device tree
|
||||||
|
* blob starting from the given @offset. If @nextoffset is non-NULL, it will
|
||||||
|
* be set to the offset immediately following the tag.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* the tag type (FDT_BEGIN_NODE, FDT_END_NODE, FDT_PROP, FDT_NOP, FDT_END),
|
||||||
|
* FDT_END, if offset is out of bounds
|
||||||
|
*/
|
||||||
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
|
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -334,6 +362,23 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
|
|||||||
/* Read-only functions */
|
/* Read-only functions */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_check_full - check device tree validity
|
||||||
|
* @fdt: pointer to the device tree blob
|
||||||
|
* @bufsize: size of the buffer containing the device tree
|
||||||
|
*
|
||||||
|
* fdt_check_full() checks that the given buffer contains a valid
|
||||||
|
* flattened device tree and that the tree structure is internally
|
||||||
|
* consistent. This is a more thorough check than fdt_check_header().
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
* -FDT_ERR_BADVERSION,
|
||||||
|
* -FDT_ERR_BADSTATE,
|
||||||
|
* -FDT_ERR_BADSTRUCTURE,
|
||||||
|
* -FDT_ERR_TRUNCATED, standard meanings
|
||||||
|
*/
|
||||||
int fdt_check_full(const void *fdt, size_t bufsize);
|
int fdt_check_full(const void *fdt, size_t bufsize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1540,10 +1585,90 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags);
|
|||||||
*/
|
*/
|
||||||
int fdt_create(void *buf, int bufsize);
|
int fdt_create(void *buf, int bufsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_resize - move and resize a device tree in sequential write state
|
||||||
|
* @fdt: Pointer to the device tree to resize
|
||||||
|
* @buf: Buffer where resized tree should be placed
|
||||||
|
* @bufsize: Size of the buffer at @buf
|
||||||
|
*
|
||||||
|
* fdt_resize() moves the device tree blob from @fdt to @buf and
|
||||||
|
* resizes it to fit in the new buffer size.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, if @bufsize is too small
|
||||||
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
* -FDT_ERR_BADVERSION,
|
||||||
|
* -FDT_ERR_BADSTATE, standard meanings
|
||||||
|
*/
|
||||||
int fdt_resize(void *fdt, void *buf, int bufsize);
|
int fdt_resize(void *fdt, void *buf, int bufsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_add_reservemap_entry - add an entry to the memory reserve map
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
* @addr: Start address of the reserve map entry
|
||||||
|
* @size: Size of the reserved region
|
||||||
|
*
|
||||||
|
* fdt_add_reservemap_entry() adds a memory reserve map entry to the
|
||||||
|
* device tree blob during the sequential write process. This function
|
||||||
|
* can only be called after fdt_create() and before fdt_finish_reservemap().
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, if there is insufficient space in the blob
|
||||||
|
* -FDT_ERR_BADSTATE, if not in the correct sequential write state
|
||||||
|
*/
|
||||||
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
|
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_finish_reservemap - complete the memory reserve map
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
*
|
||||||
|
* fdt_finish_reservemap() completes the memory reserve map section
|
||||||
|
* of the device tree blob during sequential write. After calling this
|
||||||
|
* function, no more reserve map entries can be added and the blob
|
||||||
|
* moves to the structure creation phase.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_BADSTATE, if not in the correct sequential write state
|
||||||
|
*/
|
||||||
int fdt_finish_reservemap(void *fdt);
|
int fdt_finish_reservemap(void *fdt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_begin_node - start creation of a new node
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
* @name: Name of the node to create
|
||||||
|
*
|
||||||
|
* fdt_begin_node() starts the creation of a new node with the given
|
||||||
|
* @name during sequential write. After calling this function, properties
|
||||||
|
* can be added with fdt_property() and subnodes can be created with
|
||||||
|
* additional fdt_begin_node() calls. The node must be completed with
|
||||||
|
* fdt_end_node().
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, if there is insufficient space in the blob
|
||||||
|
* -FDT_ERR_BADSTATE, if not in the correct sequential write state
|
||||||
|
*/
|
||||||
int fdt_begin_node(void *fdt, const char *name);
|
int fdt_begin_node(void *fdt, const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_property - add a property to the current node
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
* @name: Name of the property to add
|
||||||
|
* @val: Pointer to the property value
|
||||||
|
* @len: Length of the property value in bytes
|
||||||
|
*
|
||||||
|
* fdt_property() adds a property with the given @name and value to
|
||||||
|
* the current node during sequential write. This function can only
|
||||||
|
* be called between fdt_begin_node() and fdt_end_node().
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, if there is insufficient space in the blob
|
||||||
|
* -FDT_ERR_BADSTATE, if not currently within a node
|
||||||
|
*/
|
||||||
int fdt_property(void *fdt, const char *name, const void *val, int len);
|
int fdt_property(void *fdt, const char *name, const void *val, int len);
|
||||||
static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
|
static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
|
||||||
{
|
{
|
||||||
@@ -1580,15 +1705,94 @@ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp);
|
|||||||
|
|
||||||
#define fdt_property_string(fdt, name, str) \
|
#define fdt_property_string(fdt, name, str) \
|
||||||
fdt_property(fdt, name, str, strlen(str)+1)
|
fdt_property(fdt, name, str, strlen(str)+1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_end_node - complete the current node
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
*
|
||||||
|
* fdt_end_node() completes the current node during sequential write. This
|
||||||
|
* function must be called to close each node started with
|
||||||
|
* fdt_begin_node(). After calling this function, no more properties or subnodes
|
||||||
|
* can be added to the node.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_BADSTATE, if not currently within a node
|
||||||
|
*/
|
||||||
int fdt_end_node(void *fdt);
|
int fdt_end_node(void *fdt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_finish - complete device tree creation
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
*
|
||||||
|
* fdt_finish() completes the device tree creation process started with
|
||||||
|
* fdt_create(). This function finalizes the device tree blob and makes it ready
|
||||||
|
* for use. After calling this function, the blob is complete and can be used
|
||||||
|
* with libfdt read-only and read-write functions, but not with sequential write
|
||||||
|
* functions.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_BADSTATE, if the sequential write process is incomplete
|
||||||
|
*/
|
||||||
int fdt_finish(void *fdt);
|
int fdt_finish(void *fdt);
|
||||||
|
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
/* Read-write functions */
|
/* Read-write functions */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_create_empty_tree - create an empty device tree
|
||||||
|
* @buf: Buffer where the empty tree should be created
|
||||||
|
* @bufsize: Size of the buffer at @buf
|
||||||
|
*
|
||||||
|
* fdt_create_empty_tree() creates a minimal empty device tree blob
|
||||||
|
* in the given buffer. The tree contains only a root node with no
|
||||||
|
* properties or subnodes.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, if @bufsize is too small for even an empty tree
|
||||||
|
*/
|
||||||
int fdt_create_empty_tree(void *buf, int bufsize);
|
int fdt_create_empty_tree(void *buf, int bufsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_open_into - move a device tree into a new buffer and make editable
|
||||||
|
* @fdt: Pointer to the device tree to move
|
||||||
|
* @buf: Buffer where the editable tree should be placed
|
||||||
|
* @bufsize: Size of the buffer at @buf
|
||||||
|
*
|
||||||
|
* fdt_open_into() moves and reorganizes the device tree blob from @fdt
|
||||||
|
* into @buf, converting it to a format suitable for read-write operations.
|
||||||
|
* The new buffer should allow space for modifications.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_NOSPACE, if @bufsize is too small
|
||||||
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
* -FDT_ERR_BADVERSION,
|
||||||
|
* -FDT_ERR_BADSTATE,
|
||||||
|
* -FDT_ERR_BADSTRUCTURE,
|
||||||
|
* -FDT_ERR_TRUNCATED, standard meanings
|
||||||
|
*/
|
||||||
int fdt_open_into(const void *fdt, void *buf, int bufsize);
|
int fdt_open_into(const void *fdt, void *buf, int bufsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_pack - pack a device tree blob
|
||||||
|
* @fdt: Pointer to the device tree blob
|
||||||
|
*
|
||||||
|
* fdt_pack() reorganizes the device tree blob to eliminate any free space
|
||||||
|
* and pack it into the minimum possible size. This is useful after making
|
||||||
|
* modifications that might have left gaps in the blob.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* 0, on success
|
||||||
|
* -FDT_ERR_BADMAGIC,
|
||||||
|
* -FDT_ERR_BADVERSION,
|
||||||
|
* -FDT_ERR_BADSTATE,
|
||||||
|
* -FDT_ERR_BADSTRUCTURE,
|
||||||
|
* -FDT_ERR_BADLAYOUT, standard meanings
|
||||||
|
*/
|
||||||
int fdt_pack(void *fdt);
|
int fdt_pack(void *fdt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2317,6 +2521,16 @@ int fdt_overlay_target_offset(const void *fdt, const void *fdto,
|
|||||||
/* Debugging / informational functions */
|
/* Debugging / informational functions */
|
||||||
/**********************************************************************/
|
/**********************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_strerror - return string description of error code
|
||||||
|
* @errval: Error code returned by a libfdt function
|
||||||
|
*
|
||||||
|
* fdt_strerror() returns a string description of the error code passed
|
||||||
|
* in @errval.
|
||||||
|
*
|
||||||
|
* returns:
|
||||||
|
* pointer to a string describing the error code
|
||||||
|
*/
|
||||||
const char *fdt_strerror(int errval);
|
const char *fdt_strerror(int errval);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -66,31 +66,4 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
|
|||||||
#undef CPU_TO_FDT16
|
#undef CPU_TO_FDT16
|
||||||
#undef EXTRACT_BYTE
|
#undef EXTRACT_BYTE
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <AvailabilityMacros.h>
|
|
||||||
|
|
||||||
/* strnlen() is not available on Mac OS < 10.7 */
|
|
||||||
# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
|
|
||||||
MAC_OS_X_VERSION_10_7)
|
|
||||||
|
|
||||||
#define strnlen fdt_strnlen
|
|
||||||
|
|
||||||
/*
|
|
||||||
* fdt_strnlen: returns the length of a string or max_count - which ever is
|
|
||||||
* smallest.
|
|
||||||
* Input 1 string: the string whose size is to be determined
|
|
||||||
* Input 2 max_count: the maximum value returned by this function
|
|
||||||
* Output: length of the string or max_count (the smallest of the two)
|
|
||||||
*/
|
|
||||||
static inline size_t fdt_strnlen(const char *string, size_t max_count)
|
|
||||||
{
|
|
||||||
const char *p = memchr(string, 0, max_count);
|
|
||||||
return p ? p - string : max_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
|
|
||||||
MAC_OS_X_VERSION_10_7) */
|
|
||||||
|
|
||||||
#endif /* __APPLE__ */
|
|
||||||
|
|
||||||
#endif /* LIBFDT_ENV_H */
|
#endif /* LIBFDT_ENV_H */
|
||||||
|
|||||||
@@ -11,11 +11,13 @@
|
|||||||
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
|
||||||
|
|
||||||
int32_t fdt_ro_probe_(const void *fdt);
|
int32_t fdt_ro_probe_(const void *fdt);
|
||||||
#define FDT_RO_PROBE(fdt) \
|
#define FDT_RO_PROBE(fdt) \
|
||||||
{ \
|
{ \
|
||||||
int32_t totalsize_; \
|
if (!can_assume(VALID_DTB)) { \
|
||||||
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
|
int32_t totalsize_; \
|
||||||
return totalsize_; \
|
if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \
|
||||||
|
return totalsize_; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
int fdt_check_node_offset_(const void *fdt, int offset);
|
int fdt_check_node_offset_(const void *fdt, int offset);
|
||||||
@@ -92,7 +94,7 @@ static inline uint64_t fdt64_ld_(const fdt64_t *p)
|
|||||||
* signature or hash check before using libfdt.
|
* signature or hash check before using libfdt.
|
||||||
*
|
*
|
||||||
* For situations where security is not a concern it may be safe to enable
|
* For situations where security is not a concern it may be safe to enable
|
||||||
* ASSUME_SANE.
|
* ASSUME_PERFECT.
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -340,20 +340,73 @@ void append_to_property(struct node *node,
|
|||||||
char *name, const void *data, int len,
|
char *name, const void *data, int len,
|
||||||
enum markertype type)
|
enum markertype type)
|
||||||
{
|
{
|
||||||
struct data d;
|
struct property *p;
|
||||||
|
|
||||||
|
p = get_property(node, name);
|
||||||
|
if (!p) {
|
||||||
|
p = build_property(name, empty_data, NULL);
|
||||||
|
add_property(node, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->val = data_add_marker(p->val, type, name);
|
||||||
|
p->val = data_append_data(p->val, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int append_unique_str_to_property(struct node *node,
|
||||||
|
char *name, const char *data, int len)
|
||||||
|
{
|
||||||
struct property *p;
|
struct property *p;
|
||||||
|
|
||||||
p = get_property(node, name);
|
p = get_property(node, name);
|
||||||
if (p) {
|
if (p) {
|
||||||
d = data_add_marker(p->val, type, name);
|
const char *s;
|
||||||
d = data_append_data(d, data, len);
|
|
||||||
p->val = d;
|
if (p->val.len && p->val.val[p->val.len - 1] != '\0')
|
||||||
|
/* The current content doesn't look like a string */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (s = p->val.val; s < p->val.val + p->val.len; s = strchr(s, '\0') + 1) {
|
||||||
|
if (strcmp(data, s) == 0)
|
||||||
|
/* data already contained in node.name */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
d = data_add_marker(empty_data, type, name);
|
p = build_property(name, empty_data, NULL);
|
||||||
d = data_append_data(d, data, len);
|
|
||||||
p = build_property(name, d, NULL);
|
|
||||||
add_property(node, p);
|
add_property(node, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->val = data_add_marker(p->val, TYPE_STRING, name);
|
||||||
|
p->val = data_append_data(p->val, data, len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int append_unique_u32_to_property(struct node *node, char *name, fdt32_t value)
|
||||||
|
{
|
||||||
|
struct property *p;
|
||||||
|
|
||||||
|
p = get_property(node, name);
|
||||||
|
if (p) {
|
||||||
|
const fdt32_t *v, *val_end = (const fdt32_t *)p->val.val + p->val.len / 4;
|
||||||
|
|
||||||
|
if (p->val.len % 4 != 0)
|
||||||
|
/* The current content doesn't look like a u32 array */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (v = (const void *)p->val.val; v < val_end; v++) {
|
||||||
|
if (*v == value)
|
||||||
|
/* value already contained */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p = build_property(name, empty_data, NULL);
|
||||||
|
add_property(node, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->val = data_add_marker(p->val, TYPE_UINT32, name);
|
||||||
|
p->val = data_append_data(p->val, &value, 4);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
|
struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size)
|
||||||
@@ -918,11 +971,12 @@ static bool any_fixup_tree(struct dt_info *dti, struct node *node)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_fixup_entry(struct dt_info *dti, struct node *fn,
|
static int add_fixup_entry(struct dt_info *dti, struct node *fn,
|
||||||
struct node *node, struct property *prop,
|
struct node *node, struct property *prop,
|
||||||
struct marker *m)
|
struct marker *m)
|
||||||
{
|
{
|
||||||
char *entry;
|
char *entry;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* m->ref can only be a REF_PHANDLE, but check anyway */
|
/* m->ref can only be a REF_PHANDLE, but check anyway */
|
||||||
assert(m->type == REF_PHANDLE);
|
assert(m->type == REF_PHANDLE);
|
||||||
@@ -939,32 +993,39 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn,
|
|||||||
|
|
||||||
xasprintf(&entry, "%s:%s:%u",
|
xasprintf(&entry, "%s:%s:%u",
|
||||||
node->fullpath, prop->name, m->offset);
|
node->fullpath, prop->name, m->offset);
|
||||||
append_to_property(fn, m->ref, entry, strlen(entry) + 1, TYPE_STRING);
|
ret = append_unique_str_to_property(fn, m->ref, entry, strlen(entry) + 1);
|
||||||
|
|
||||||
free(entry);
|
free(entry);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_fixups_tree_internal(struct dt_info *dti,
|
static int generate_fixups_tree_internal(struct dt_info *dti,
|
||||||
struct node *fn,
|
struct node *fn,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct node *dt = dti->dt;
|
struct node *dt = dti->dt;
|
||||||
struct node *c;
|
struct node *c;
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
struct marker *m;
|
struct marker *m;
|
||||||
struct node *refnode;
|
struct node *refnode;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
for_each_property(node, prop) {
|
for_each_property(node, prop) {
|
||||||
m = prop->val.markers;
|
m = prop->val.markers;
|
||||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
refnode = get_node_by_ref(dt, m->ref);
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
if (!refnode)
|
if (!refnode)
|
||||||
add_fixup_entry(dti, fn, node, prop, m);
|
if (add_fixup_entry(dti, fn, node, prop, m))
|
||||||
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_child(node, c)
|
for_each_child(node, c)
|
||||||
generate_fixups_tree_internal(dti, fn, c);
|
if (generate_fixups_tree_internal(dti, fn, c))
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
|
static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
|
||||||
@@ -989,7 +1050,7 @@ static bool any_local_fixup_tree(struct dt_info *dti, struct node *node)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_local_fixup_entry(struct dt_info *dti,
|
static int add_local_fixup_entry(struct dt_info *dti,
|
||||||
struct node *lfn, struct node *node,
|
struct node *lfn, struct node *node,
|
||||||
struct property *prop, struct marker *m,
|
struct property *prop, struct marker *m,
|
||||||
struct node *refnode)
|
struct node *refnode)
|
||||||
@@ -1020,30 +1081,56 @@ static void add_local_fixup_entry(struct dt_info *dti,
|
|||||||
free(compp);
|
free(compp);
|
||||||
|
|
||||||
value_32 = cpu_to_fdt32(m->offset);
|
value_32 = cpu_to_fdt32(m->offset);
|
||||||
append_to_property(wn, prop->name, &value_32, sizeof(value_32), TYPE_UINT32);
|
return append_unique_u32_to_property(wn, prop->name, value_32);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_local_fixups_tree_internal(struct dt_info *dti,
|
static int generate_local_fixups_tree_internal(struct dt_info *dti,
|
||||||
struct node *lfn,
|
struct node *lfn,
|
||||||
struct node *node)
|
struct node *node)
|
||||||
{
|
{
|
||||||
struct node *dt = dti->dt;
|
struct node *dt = dti->dt;
|
||||||
struct node *c;
|
struct node *c;
|
||||||
struct property *prop;
|
struct property *prop;
|
||||||
struct marker *m;
|
struct marker *m;
|
||||||
struct node *refnode;
|
struct node *refnode;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
for_each_property(node, prop) {
|
for_each_property(node, prop) {
|
||||||
m = prop->val.markers;
|
m = prop->val.markers;
|
||||||
for_each_marker_of_type(m, REF_PHANDLE) {
|
for_each_marker_of_type(m, REF_PHANDLE) {
|
||||||
refnode = get_node_by_ref(dt, m->ref);
|
refnode = get_node_by_ref(dt, m->ref);
|
||||||
if (refnode)
|
if (refnode)
|
||||||
add_local_fixup_entry(dti, lfn, node, prop, m, refnode);
|
if (add_local_fixup_entry(dti, lfn, node, prop, m, refnode))
|
||||||
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_child(node, c)
|
for_each_child(node, c)
|
||||||
generate_local_fixups_tree_internal(dti, lfn, c);
|
if (generate_local_fixups_tree_internal(dti, lfn, c))
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_labels_from_tree(struct dt_info *dti, const char *name)
|
||||||
|
{
|
||||||
|
struct node *an;
|
||||||
|
struct property *p;
|
||||||
|
|
||||||
|
an = get_subnode(dti->dt, name);
|
||||||
|
if (!an)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for_each_property(an, p) {
|
||||||
|
struct node *labeled_node;
|
||||||
|
|
||||||
|
labeled_node = get_node_by_path(dti->dt, p->val.val);
|
||||||
|
if (labeled_node)
|
||||||
|
add_label(&labeled_node->labels, p->name);
|
||||||
|
else if (quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: Path %s referenced in property %s/%s missing",
|
||||||
|
p->val.val, name, p->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
|
void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
|
||||||
@@ -1056,29 +1143,173 @@ void generate_label_tree(struct dt_info *dti, const char *name, bool allocph)
|
|||||||
|
|
||||||
void generate_fixups_tree(struct dt_info *dti, const char *name)
|
void generate_fixups_tree(struct dt_info *dti, const char *name)
|
||||||
{
|
{
|
||||||
struct node *n = get_subnode(dti->dt, name);
|
|
||||||
|
|
||||||
/* Start with an empty __fixups__ node to not get duplicates */
|
|
||||||
if (n)
|
|
||||||
n->deleted = true;
|
|
||||||
|
|
||||||
if (!any_fixup_tree(dti, dti->dt))
|
if (!any_fixup_tree(dti, dti->dt))
|
||||||
return;
|
return;
|
||||||
generate_fixups_tree_internal(dti,
|
if (generate_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
|
||||||
build_and_name_child_node(dti->dt, name),
|
fprintf(stderr,
|
||||||
dti->dt);
|
"Warning: Preexisting data in %s malformed, some content could not be added.\n",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixup_phandles(struct dt_info *dti, const char *name)
|
||||||
|
{
|
||||||
|
struct node *an;
|
||||||
|
struct property *fp;
|
||||||
|
|
||||||
|
an = get_subnode(dti->dt, name);
|
||||||
|
if (!an)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for_each_property(an, fp) {
|
||||||
|
char *fnext = fp->val.val;
|
||||||
|
char *fv;
|
||||||
|
unsigned int fl;
|
||||||
|
|
||||||
|
while ((fl = fp->val.len - (fnext - fp->val.val))) {
|
||||||
|
char *propname, *soffset;
|
||||||
|
struct node *n;
|
||||||
|
struct property *p;
|
||||||
|
long offset;
|
||||||
|
|
||||||
|
fv = fnext;
|
||||||
|
fnext = memchr(fv, 0, fl);
|
||||||
|
|
||||||
|
if (!fnext) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
|
||||||
|
fp->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fnext += 1;
|
||||||
|
|
||||||
|
propname = memchr(fv, ':', fnext - 1 - fv);
|
||||||
|
if (!propname) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
|
||||||
|
fp->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
propname++;
|
||||||
|
|
||||||
|
soffset = memchr(propname, ':', fnext - 1 - propname);
|
||||||
|
if (!soffset) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: Malformed fixup entry for label %s\n",
|
||||||
|
fp->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
soffset++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* temporarily modify the property to not have to create
|
||||||
|
* a copy for the node path.
|
||||||
|
*/
|
||||||
|
*(propname - 1) = '\0';
|
||||||
|
|
||||||
|
n = get_node_by_path(dti->dt, fv);
|
||||||
|
if (!n && quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: Label %s references non-existing node %s\n",
|
||||||
|
fp->name, fv);
|
||||||
|
|
||||||
|
*(propname - 1) = ':';
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* temporarily modify the property to not have to create
|
||||||
|
* a copy for the property name.
|
||||||
|
*/
|
||||||
|
*(soffset - 1) = '\0';
|
||||||
|
|
||||||
|
p = get_property(n, propname);
|
||||||
|
|
||||||
|
if (!p && quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: Label %s references non-existing property %s in node %s\n",
|
||||||
|
fp->name, n->fullpath, propname);
|
||||||
|
|
||||||
|
*(soffset - 1) = ':';
|
||||||
|
|
||||||
|
if (!p)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
offset = strtol(soffset, NULL, 0);
|
||||||
|
if (offset < 0 || offset + 4 > p->val.len) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: Label %s contains invalid offset for property %s in node %s\n",
|
||||||
|
fp->name, p->name, n->fullpath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
property_add_marker(p, REF_PHANDLE, offset, fp->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_local_fixups_tree(struct dt_info *dti, const char *name)
|
void generate_local_fixups_tree(struct dt_info *dti, const char *name)
|
||||||
{
|
{
|
||||||
struct node *n = get_subnode(dti->dt, name);
|
|
||||||
|
|
||||||
/* Start with an empty __local_fixups__ node to not get duplicates */
|
|
||||||
if (n)
|
|
||||||
n->deleted = true;
|
|
||||||
if (!any_local_fixup_tree(dti, dti->dt))
|
if (!any_local_fixup_tree(dti, dti->dt))
|
||||||
return;
|
return;
|
||||||
generate_local_fixups_tree_internal(dti,
|
if (generate_local_fixups_tree_internal(dti, build_root_node(dti->dt, name), dti->dt))
|
||||||
build_and_name_child_node(dti->dt, name),
|
fprintf(stderr,
|
||||||
dti->dt);
|
"Warning: Preexisting data in %s malformed, some content could not be added.\n",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void local_fixup_phandles_node(struct dt_info *dti, struct node *lf, struct node *n)
|
||||||
|
{
|
||||||
|
struct property *lfp;
|
||||||
|
struct node *lfsubnode;
|
||||||
|
|
||||||
|
for_each_property(lf, lfp) {
|
||||||
|
struct property *p = get_property(n, lfp->name);
|
||||||
|
fdt32_t *offsets = (fdt32_t *)lfp->val.val;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: Property %s in %s referenced in __local_fixups__ missing\n",
|
||||||
|
lfp->name, n->fullpath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each property in the __local_fixups__ tree is a concatenation
|
||||||
|
* of offsets, so it must be a multiple of sizeof(fdt32_t).
|
||||||
|
*/
|
||||||
|
if (lfp->val.len % sizeof(fdt32_t)) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: property %s in /__local_fixups__%s malformed\n",
|
||||||
|
lfp->name, n->fullpath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < lfp->val.len / sizeof(fdt32_t); i++)
|
||||||
|
add_phandle_marker(dti, p, dtb_ld32(offsets + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_child(lf, lfsubnode) {
|
||||||
|
struct node *subnode = get_subnode(n, lfsubnode->name);
|
||||||
|
|
||||||
|
if (!subnode) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr, "Warning: node %s/%s referenced in __local_fixups__ missing\n",
|
||||||
|
lfsubnode->name, n->fullpath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_fixup_phandles_node(dti, lfsubnode, subnode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void local_fixup_phandles(struct dt_info *dti, const char *name)
|
||||||
|
{
|
||||||
|
struct node *an;
|
||||||
|
|
||||||
|
an = get_subnode(dti->dt, name);
|
||||||
|
if (!an)
|
||||||
|
return;
|
||||||
|
|
||||||
|
local_fixup_phandles_node(dti, an, dti->dt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,26 @@ static char *shorten_to_initial_path(char *fname)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given path is an absolute one.
|
||||||
|
*
|
||||||
|
* On Windows, it either needs to begin with a forward slash or with a drive
|
||||||
|
* letter (e.g. "C:").
|
||||||
|
* On all other operating systems, it must begin with a forward slash to be
|
||||||
|
* considered an absolute path.
|
||||||
|
*/
|
||||||
|
static bool is_absolute_path(const char *path)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
return (
|
||||||
|
path[0] == '/' ||
|
||||||
|
(((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z')) && path[1] == ':')
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
return (path[0] == '/');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to open a file in a given directory.
|
* Try to open a file in a given directory.
|
||||||
*
|
*
|
||||||
@@ -103,7 +123,7 @@ static char *try_open(const char *dirname, const char *fname, FILE **fp)
|
|||||||
{
|
{
|
||||||
char *fullname;
|
char *fullname;
|
||||||
|
|
||||||
if (!dirname || fname[0] == '/')
|
if (!dirname || is_absolute_path(fname))
|
||||||
fullname = xstrdup(fname);
|
fullname = xstrdup(fname);
|
||||||
else
|
else
|
||||||
fullname = join_path(dirname, fname);
|
fullname = join_path(dirname, fname);
|
||||||
|
|||||||
@@ -173,23 +173,59 @@ static struct marker **add_marker(struct marker **mi,
|
|||||||
return &nm->next;
|
return &nm->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_string_markers(struct property *prop)
|
void property_add_marker(struct property *prop,
|
||||||
|
enum markertype type, unsigned int offset, char *ref)
|
||||||
{
|
{
|
||||||
int l, len = prop->val.len;
|
add_marker(&prop->val.markers, type, offset, ref);
|
||||||
const char *p = prop->val.val;
|
}
|
||||||
|
|
||||||
|
static void add_string_markers(struct property *prop, unsigned int offset, int len)
|
||||||
|
{
|
||||||
|
int l;
|
||||||
|
const char *p = prop->val.val + offset;
|
||||||
struct marker **mi = &prop->val.markers;
|
struct marker **mi = &prop->val.markers;
|
||||||
|
|
||||||
for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1)
|
for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1)
|
||||||
mi = add_marker(mi, TYPE_STRING, l, NULL);
|
mi = add_marker(mi, TYPE_STRING, offset + l, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum markertype guess_value_type(struct property *prop)
|
void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset)
|
||||||
{
|
{
|
||||||
int len = prop->val.len;
|
cell_t phandle;
|
||||||
const char *p = prop->val.val;
|
struct node *refn;
|
||||||
struct marker *m = prop->val.markers;
|
char *ref;
|
||||||
|
|
||||||
|
if (prop->val.len < offset + 4) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: property %s too short to contain a phandle at offset %u\n",
|
||||||
|
prop->name, offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
phandle = dtb_ld32(prop->val.val + offset);
|
||||||
|
refn = get_node_by_phandle(dti->dt, phandle);
|
||||||
|
|
||||||
|
if (!refn) {
|
||||||
|
if (quiet < 1)
|
||||||
|
fprintf(stderr,
|
||||||
|
"Warning: node referenced by phandle 0x%x in property %s not found\n",
|
||||||
|
phandle, prop->name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refn->labels)
|
||||||
|
ref = refn->labels->label;
|
||||||
|
else
|
||||||
|
ref = refn->fullpath;
|
||||||
|
|
||||||
|
add_marker(&prop->val.markers, REF_PHANDLE, offset, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum markertype guess_value_type(struct property *prop, unsigned int offset, int len)
|
||||||
|
{
|
||||||
|
const char *p = prop->val.val + offset;
|
||||||
int nnotstring = 0, nnul = 0;
|
int nnotstring = 0, nnul = 0;
|
||||||
int nnotstringlbl = 0, nnotcelllbl = 0;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
@@ -199,30 +235,49 @@ static enum markertype guess_value_type(struct property *prop)
|
|||||||
nnul++;
|
nnul++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_marker_of_type(m, LABEL) {
|
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= len - nnul)) {
|
||||||
if ((m->offset > 0) && (prop->val.val[m->offset - 1] != '\0'))
|
|
||||||
nnotstringlbl++;
|
|
||||||
if ((m->offset % sizeof(cell_t)) != 0)
|
|
||||||
nnotcelllbl++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul))
|
|
||||||
&& (nnotstringlbl == 0)) {
|
|
||||||
if (nnul > 1)
|
if (nnul > 1)
|
||||||
add_string_markers(prop);
|
add_string_markers(prop, offset, len);
|
||||||
return TYPE_STRING;
|
return TYPE_STRING;
|
||||||
} else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) {
|
} else if ((len % sizeof(cell_t)) == 0) {
|
||||||
return TYPE_UINT32;
|
return TYPE_UINT32;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TYPE_UINT8;
|
return TYPE_UINT8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void guess_type_markers(struct property *prop)
|
||||||
|
{
|
||||||
|
struct marker **m = &prop->val.markers;
|
||||||
|
unsigned int offset = 0;
|
||||||
|
|
||||||
|
for (m = &prop->val.markers; *m; m = &((*m)->next)) {
|
||||||
|
if (is_type_marker((*m)->type))
|
||||||
|
/* assume the whole property is already marked */
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((*m)->offset > offset) {
|
||||||
|
m = add_marker(m, guess_value_type(prop, offset, (*m)->offset - offset),
|
||||||
|
offset, NULL);
|
||||||
|
|
||||||
|
offset = (*m)->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*m)->type == REF_PHANDLE) {
|
||||||
|
m = add_marker(m, TYPE_UINT32, offset, NULL);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset < prop->val.len)
|
||||||
|
add_marker(m, guess_value_type(prop, offset, prop->val.len - offset),
|
||||||
|
offset, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void write_propval(FILE *f, struct property *prop)
|
static void write_propval(FILE *f, struct property *prop)
|
||||||
{
|
{
|
||||||
size_t len = prop->val.len;
|
size_t len = prop->val.len;
|
||||||
struct marker *m = prop->val.markers;
|
struct marker *m;
|
||||||
struct marker dummy_marker;
|
|
||||||
enum markertype emit_type = TYPE_NONE;
|
enum markertype emit_type = TYPE_NONE;
|
||||||
char *srcstr;
|
char *srcstr;
|
||||||
|
|
||||||
@@ -241,14 +296,8 @@ static void write_propval(FILE *f, struct property *prop)
|
|||||||
|
|
||||||
fprintf(f, " =");
|
fprintf(f, " =");
|
||||||
|
|
||||||
if (!next_type_marker(m)) {
|
guess_type_markers(prop);
|
||||||
/* data type information missing, need to guess */
|
m = prop->val.markers;
|
||||||
dummy_marker.type = guess_value_type(prop);
|
|
||||||
dummy_marker.next = prop->val.markers;
|
|
||||||
dummy_marker.offset = 0;
|
|
||||||
dummy_marker.ref = NULL;
|
|
||||||
m = &dummy_marker;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_each_marker(m) {
|
for_each_marker(m) {
|
||||||
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
|
size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
|
||||||
@@ -369,7 +418,10 @@ void dt_to_source(FILE *f, struct dt_info *dti)
|
|||||||
{
|
{
|
||||||
struct reserve_info *re;
|
struct reserve_info *re;
|
||||||
|
|
||||||
fprintf(f, "/dts-v1/;\n\n");
|
fprintf(f, "/dts-v1/;\n");
|
||||||
|
if (dti->dtsflags & DTSF_PLUGIN)
|
||||||
|
fprintf(f, "/plugin/;\n");
|
||||||
|
fprintf(f, "\n");
|
||||||
|
|
||||||
for (re = dti->reservelist; re; re = re->next) {
|
for (re = dti->reservelist; re; re = re->next) {
|
||||||
struct label *l;
|
struct label *l;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define DTC_VERSION "DTC 1.7.2-g52f07dcc"
|
#define DTC_VERSION "DTC 1.7.2-ga26ef640"
|
||||||
|
|||||||
Reference in New Issue
Block a user