lib/libfdt/ and scripts/dtc/libfdt have the same copies for the followings 6 files: fdt.c fdt_addresses.c fdt_empty_tree.c fdt_overlay.c fdt_strerr.c fdt_sw.c Make them a wrapper of scripts/dtc/libfdt/*. This is exactly what Linux does to sync libfdt. In order to make is possible, import <linux/libfdt.h> and <linux/libfdt_env.h> from Linux 4.14-rc5. Unfortunately, U-Boot locally modified the following 3 files: fdt_ro.c fdt_wip.c fdt_rw.c The fdt_region.c is U-Boot own file. I did not touch them in order to avoid unpredictable impact. Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>master
parent
1c4b453ad2
commit
50a327ded6
@ -0,0 +1,17 @@ |
||||
#ifndef _LIBFDT_ENV_H |
||||
#define _LIBFDT_ENV_H |
||||
|
||||
#include <linux/string.h> |
||||
|
||||
#include <asm/byteorder.h> |
||||
|
||||
typedef __be16 fdt16_t; |
||||
typedef __be32 fdt32_t; |
||||
typedef __be64 fdt64_t; |
||||
|
||||
#define fdt32_to_cpu(x) be32_to_cpu(x) |
||||
#define cpu_to_fdt32(x) cpu_to_be32(x) |
||||
#define fdt64_to_cpu(x) be64_to_cpu(x) |
||||
#define cpu_to_fdt64(x) cpu_to_be64(x) |
||||
|
||||
#endif /* _LIBFDT_ENV_H */ |
@ -0,0 +1,22 @@ |
||||
#ifndef _LIBFDT_ENV_H |
||||
#define _LIBFDT_ENV_H |
||||
|
||||
#include <linux/string.h> |
||||
|
||||
#include <asm/byteorder.h> |
||||
|
||||
typedef __be16 fdt16_t; |
||||
typedef __be32 fdt32_t; |
||||
typedef __be64 fdt64_t; |
||||
|
||||
#define fdt32_to_cpu(x) be32_to_cpu(x) |
||||
#define cpu_to_fdt32(x) cpu_to_be32(x) |
||||
#define fdt64_to_cpu(x) be64_to_cpu(x) |
||||
#define cpu_to_fdt64(x) cpu_to_be64(x) |
||||
|
||||
/* U-Boot: for strtoul in fdt_overlay.c */ |
||||
#include <vsprintf.h> |
||||
|
||||
#define strtoul(cp, endp, base) simple_strtoul(cp, endp, base) |
||||
|
||||
#endif /* _LIBFDT_ENV_H */ |
@ -1,210 +1,2 @@ |
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation |
||||
* Copyright (C) 2006 David Gibson, IBM Corporation. |
||||
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause |
||||
*/ |
||||
#include <libfdt_env.h> |
||||
|
||||
#ifndef USE_HOSTCC |
||||
#include <fdt.h> |
||||
#include <libfdt.h> |
||||
#else |
||||
#include "fdt_host.h" |
||||
#endif |
||||
|
||||
#include "libfdt_internal.h" |
||||
|
||||
int fdt_check_header(const void *fdt) |
||||
{ |
||||
if (fdt_magic(fdt) == FDT_MAGIC) { |
||||
/* Complete tree */ |
||||
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) |
||||
return -FDT_ERR_BADVERSION; |
||||
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) |
||||
return -FDT_ERR_BADVERSION; |
||||
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) { |
||||
/* Unfinished sequential-write blob */ |
||||
if (fdt_size_dt_struct(fdt) == 0) |
||||
return -FDT_ERR_BADSTATE; |
||||
} else { |
||||
return -FDT_ERR_BADMAGIC; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) |
||||
{ |
||||
unsigned absoffset = offset + fdt_off_dt_struct(fdt); |
||||
|
||||
if ((absoffset < offset) |
||||
|| ((absoffset + len) < absoffset) |
||||
|| (absoffset + len) > fdt_totalsize(fdt)) |
||||
return NULL; |
||||
|
||||
if (fdt_version(fdt) >= 0x11) |
||||
if (((offset + len) < offset) |
||||
|| ((offset + len) > fdt_size_dt_struct(fdt))) |
||||
return NULL; |
||||
|
||||
return _fdt_offset_ptr(fdt, offset); |
||||
} |
||||
|
||||
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) |
||||
{ |
||||
const fdt32_t *tagp, *lenp; |
||||
uint32_t tag; |
||||
int offset = startoffset; |
||||
const char *p; |
||||
|
||||
*nextoffset = -FDT_ERR_TRUNCATED; |
||||
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); |
||||
if (!tagp) |
||||
return FDT_END; /* premature end */ |
||||
tag = fdt32_to_cpu(*tagp); |
||||
offset += FDT_TAGSIZE; |
||||
|
||||
*nextoffset = -FDT_ERR_BADSTRUCTURE; |
||||
switch (tag) { |
||||
case FDT_BEGIN_NODE: |
||||
/* skip name */ |
||||
do { |
||||
p = fdt_offset_ptr(fdt, offset++, 1); |
||||
} while (p && (*p != '\0')); |
||||
if (!p) |
||||
return FDT_END; /* premature end */ |
||||
break; |
||||
|
||||
case FDT_PROP: |
||||
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); |
||||
if (!lenp) |
||||
return FDT_END; /* premature end */ |
||||
/* skip-name offset, length and value */ |
||||
offset += sizeof(struct fdt_property) - FDT_TAGSIZE |
||||
+ fdt32_to_cpu(*lenp); |
||||
break; |
||||
|
||||
case FDT_END: |
||||
case FDT_END_NODE: |
||||
case FDT_NOP: |
||||
break; |
||||
|
||||
default: |
||||
return FDT_END; |
||||
} |
||||
|
||||
if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) |
||||
return FDT_END; /* premature end */ |
||||
|
||||
*nextoffset = FDT_TAGALIGN(offset); |
||||
return tag; |
||||
} |
||||
|
||||
int _fdt_check_node_offset(const void *fdt, int offset) |
||||
{ |
||||
if ((offset < 0) || (offset % FDT_TAGSIZE) |
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) |
||||
return -FDT_ERR_BADOFFSET; |
||||
|
||||
return offset; |
||||
} |
||||
|
||||
int _fdt_check_prop_offset(const void *fdt, int offset) |
||||
{ |
||||
if ((offset < 0) || (offset % FDT_TAGSIZE) |
||||
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) |
||||
return -FDT_ERR_BADOFFSET; |
||||
|
||||
return offset; |
||||
} |
||||
|
||||
int fdt_next_node(const void *fdt, int offset, int *depth) |
||||
{ |
||||
int nextoffset = 0; |
||||
uint32_t tag; |
||||
|
||||
if (offset >= 0) |
||||
if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) |
||||
return nextoffset; |
||||
|
||||
do { |
||||
offset = nextoffset; |
||||
tag = fdt_next_tag(fdt, offset, &nextoffset); |
||||
|
||||
switch (tag) { |
||||
case FDT_PROP: |
||||
case FDT_NOP: |
||||
break; |
||||
|
||||
case FDT_BEGIN_NODE: |
||||
if (depth) |
||||
(*depth)++; |
||||
break; |
||||
|
||||
case FDT_END_NODE: |
||||
if (depth && ((--(*depth)) < 0)) |
||||
return nextoffset; |
||||
break; |
||||
|
||||
case FDT_END: |
||||
if ((nextoffset >= 0) |
||||
|| ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) |
||||
return -FDT_ERR_NOTFOUND; |
||||
else |
||||
return nextoffset; |
||||
} |
||||
} while (tag != FDT_BEGIN_NODE); |
||||
|
||||
return offset; |
||||
} |
||||
|
||||
int fdt_first_subnode(const void *fdt, int offset) |
||||
{ |
||||
int depth = 0; |
||||
|
||||
offset = fdt_next_node(fdt, offset, &depth); |
||||
if (offset < 0 || depth != 1) |
||||
return -FDT_ERR_NOTFOUND; |
||||
|
||||
return offset; |
||||
} |
||||
|
||||
int fdt_next_subnode(const void *fdt, int offset) |
||||
{ |
||||
int depth = 1; |
||||
|
||||
/*
|
||||
* With respect to the parent, the depth of the next subnode will be |
||||
* the same as the last. |
||||
*/ |
||||
do { |
||||
offset = fdt_next_node(fdt, offset, &depth); |
||||
if (offset < 0 || depth < 1) |
||||
return -FDT_ERR_NOTFOUND; |
||||
} while (depth > 1); |
||||
|
||||
return offset; |
||||
} |
||||
|
||||
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) |
||||
{ |
||||
int len = strlen(s) + 1; |
||||
const char *last = strtab + tabsize - len; |
||||
const char *p; |
||||
|
||||
for (p = strtab; p <= last; p++) |
||||
if (memcmp(p, s, len) == 0) |
||||
return p; |
||||
return NULL; |
||||
} |
||||
|
||||
int fdt_move(const void *fdt, void *buf, int bufsize) |
||||
{ |
||||
FDT_CHECK_HEADER(fdt); |
||||
|
||||
if (fdt_totalsize(fdt) > bufsize) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
memmove(buf, fdt, fdt_totalsize(fdt)); |
||||
return 0; |
||||
} |
||||
#include <linux/libfdt_env.h> |
||||
#include "../../scripts/dtc/libfdt/fdt.c" |
||||
|
@ -1,55 +1,2 @@ |
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation |
||||
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> |
||||
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause |
||||
*/ |
||||
#include <libfdt_env.h> |
||||
|
||||
#ifndef USE_HOSTCC |
||||
#include <fdt.h> |
||||
#include <libfdt.h> |
||||
#else |
||||
#include "fdt_host.h" |
||||
#endif |
||||
|
||||
#include "libfdt_internal.h" |
||||
|
||||
int fdt_address_cells(const void *fdt, int nodeoffset) |
||||
{ |
||||
const fdt32_t *ac; |
||||
int val; |
||||
int len; |
||||
|
||||
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); |
||||
if (!ac) |
||||
return 2; |
||||
|
||||
if (len != sizeof(*ac)) |
||||
return -FDT_ERR_BADNCELLS; |
||||
|
||||
val = fdt32_to_cpu(*ac); |
||||
if ((val <= 0) || (val > FDT_MAX_NCELLS)) |
||||
return -FDT_ERR_BADNCELLS; |
||||
|
||||
return val; |
||||
} |
||||
|
||||
int fdt_size_cells(const void *fdt, int nodeoffset) |
||||
{ |
||||
const fdt32_t *sc; |
||||
int val; |
||||
int len; |
||||
|
||||
sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); |
||||
if (!sc) |
||||
return 2; |
||||
|
||||
if (len != sizeof(*sc)) |
||||
return -FDT_ERR_BADNCELLS; |
||||
|
||||
val = fdt32_to_cpu(*sc); |
||||
if ((val < 0) || (val > FDT_MAX_NCELLS)) |
||||
return -FDT_ERR_BADNCELLS; |
||||
|
||||
return val; |
||||
} |
||||
#include <linux/libfdt_env.h> |
||||
#include "../../scripts/dtc/libfdt/fdt_addresses.c" |
||||
|
@ -1,37 +1,2 @@ |
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation |
||||
* Copyright (C) 2012 David Gibson, IBM Corporation. |
||||
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause |
||||
*/ |
||||
#include <libfdt_env.h> |
||||
#include <fdt.h> |
||||
#include <libfdt.h> |
||||
|
||||
#include "libfdt_internal.h" |
||||
|
||||
int fdt_create_empty_tree(void *buf, int bufsize) |
||||
{ |
||||
int err; |
||||
|
||||
err = fdt_create(buf, bufsize); |
||||
if (err) |
||||
return err; |
||||
|
||||
err = fdt_finish_reservemap(buf); |
||||
if (err) |
||||
return err; |
||||
|
||||
err = fdt_begin_node(buf, ""); |
||||
if (err) |
||||
return err; |
||||
|
||||
err = fdt_end_node(buf); |
||||
if (err) |
||||
return err; |
||||
|
||||
err = fdt_finish(buf); |
||||
if (err) |
||||
return err; |
||||
|
||||
return fdt_open_into(buf, buf, bufsize); |
||||
} |
||||
#include <linux/libfdt_env.h> |
||||
#include "../../scripts/dtc/libfdt/fdt_empty_tree.c" |
||||
|
@ -1,861 +1,2 @@ |
||||
#include "libfdt_env.h" |
||||
|
||||
#include <fdt.h> |
||||
#include <libfdt.h> |
||||
|
||||
#include "libfdt_internal.h" |
||||
|
||||
/**
|
||||
* overlay_get_target_phandle - retrieves the target phandle of a fragment |
||||
* @fdto: pointer to the device tree overlay blob |
||||
* @fragment: node offset of the fragment in the overlay |
||||
* |
||||
* overlay_get_target_phandle() retrieves the target phandle of an |
||||
* overlay fragment when that fragment uses a phandle (target |
||||
* property) instead of a path (target-path property). |
||||
* |
||||
* returns: |
||||
* the phandle pointed by the target property |
||||
* 0, if the phandle was not found |
||||
* -1, if the phandle was malformed |
||||
*/ |
||||
static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) |
||||
{ |
||||
const fdt32_t *val; |
||||
int len; |
||||
|
||||
val = fdt_getprop(fdto, fragment, "target", &len); |
||||
if (!val) |
||||
return 0; |
||||
|
||||
if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) |
||||
return (uint32_t)-1; |
||||
|
||||
return fdt32_to_cpu(*val); |
||||
} |
||||
|
||||
/**
|
||||
* overlay_get_target - retrieves the offset of a fragment's target |
||||
* @fdt: Base device tree blob |
||||
* @fdto: Device tree overlay blob |
||||
* @fragment: node offset of the fragment in the overlay |
||||
* @pathp: pointer which receives the path of the target (or NULL) |
||||
* |
||||
* overlay_get_target() retrieves the target offset in the base |
||||
* device tree of a fragment, no matter how the actual targetting is |
||||
* done (through a phandle or a path) |
||||
* |
||||
* returns: |
||||
* the targetted node offset in the base device tree |
||||
* Negative error code on error |
||||
*/ |
||||
static int overlay_get_target(const void *fdt, const void *fdto, |
||||
int fragment, char const **pathp) |
||||
{ |
||||
uint32_t phandle; |
||||
const char *path = NULL; |
||||
int path_len = 0, ret; |
||||
|
||||
/* Try first to do a phandle based lookup */ |
||||
phandle = overlay_get_target_phandle(fdto, fragment); |
||||
if (phandle == (uint32_t)-1) |
||||
return -FDT_ERR_BADPHANDLE; |
||||
|
||||
/* no phandle, try path */ |
||||
if (!phandle) { |
||||
/* And then a path based lookup */ |
||||
path = fdt_getprop(fdto, fragment, "target-path", &path_len); |
||||
if (path) |
||||
ret = fdt_path_offset(fdt, path); |
||||
else |
||||
ret = path_len; |
||||
} else |
||||
ret = fdt_node_offset_by_phandle(fdt, phandle); |
||||
|
||||
/*
|
||||
* If we haven't found either a target or a |
||||
* target-path property in a node that contains a |
||||
* __overlay__ subnode (we wouldn't be called |
||||
* otherwise), consider it a improperly written |
||||
* overlay |
||||
*/ |
||||
if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) |
||||
ret = -FDT_ERR_BADOVERLAY; |
||||
|
||||
/* return on error */ |
||||
if (ret < 0) |
||||
return ret; |
||||
|
||||
/* return pointer to path (if available) */ |
||||
if (pathp) |
||||
*pathp = path ? path : NULL; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
/**
|
||||
* overlay_phandle_add_offset - Increases a phandle by an offset |
||||
* @fdt: Base device tree blob |
||||
* @node: Device tree overlay blob |
||||
* @name: Name of the property to modify (phandle or linux,phandle) |
||||
* @delta: offset to apply |
||||
* |
||||
* overlay_phandle_add_offset() increments a node phandle by a given |
||||
* offset. |
||||
* |
||||
* returns: |
||||
* 0 on success. |
||||
* Negative error code on error |
||||
*/ |
||||
static int overlay_phandle_add_offset(void *fdt, int node, |
||||
const char *name, uint32_t delta) |
||||
{ |
||||
const fdt32_t *val; |
||||
uint32_t adj_val; |
||||
int len; |
||||
|
||||
val = fdt_getprop(fdt, node, name, &len); |
||||
if (!val) |
||||
return len; |
||||
|
||||
if (len != sizeof(*val)) |
||||
return -FDT_ERR_BADPHANDLE; |
||||
|
||||
adj_val = fdt32_to_cpu(*val); |
||||
if ((adj_val + delta) < adj_val) |
||||
return -FDT_ERR_NOPHANDLES; |
||||
|
||||
adj_val += delta; |
||||
if (adj_val == (uint32_t)-1) |
||||
return -FDT_ERR_NOPHANDLES; |
||||
|
||||
return fdt_setprop_inplace_u32(fdt, node, name, adj_val); |
||||
} |
||||
|
||||
/**
|
||||
* overlay_adjust_node_phandles - Offsets the phandles of a node |
||||
* @fdto: Device tree overlay blob |
||||
* @node: Offset of the node we want to adjust |
||||
* @delta: Offset to shift the phandles of |
||||
* |
||||
* overlay_adjust_node_phandles() adds a constant to all the phandles |
||||
* of a given node. This is mainly use as part of the overlay |
||||
* application process, when we want to update all the overlay |
||||
* phandles to not conflict with the overlays of the base device tree. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_adjust_node_phandles(void *fdto, int node, |
||||
uint32_t delta) |
||||
{ |
||||
int child; |
||||
int ret; |
||||
|
||||
ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); |
||||
if (ret && ret != -FDT_ERR_NOTFOUND) |
||||
return ret; |
||||
|
||||
ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); |
||||
if (ret && ret != -FDT_ERR_NOTFOUND) |
||||
return ret; |
||||
|
||||
fdt_for_each_subnode(child, fdto, node) { |
||||
ret = overlay_adjust_node_phandles(fdto, child, delta); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* overlay_adjust_local_phandles - Adjust the phandles of a whole overlay |
||||
* @fdto: Device tree overlay blob |
||||
* @delta: Offset to shift the phandles of |
||||
* |
||||
* overlay_adjust_local_phandles() adds a constant to all the |
||||
* phandles of an overlay. This is mainly use as part of the overlay |
||||
* application process, when we want to update all the overlay |
||||
* phandles to not conflict with the overlays of the base device tree. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) |
||||
{ |
||||
/*
|
||||
* Start adjusting the phandles from the overlay root |
||||
*/ |
||||
return overlay_adjust_node_phandles(fdto, 0, delta); |
||||
} |
||||
|
||||
/**
|
||||
* overlay_update_local_node_references - Adjust the overlay references |
||||
* @fdto: Device tree overlay blob |
||||
* @tree_node: Node offset of the node to operate on |
||||
* @fixup_node: Node offset of the matching local fixups node |
||||
* @delta: Offset to shift the phandles of |
||||
* |
||||
* overlay_update_local_nodes_references() update the phandles |
||||
* pointing to a node within the device tree overlay by adding a |
||||
* constant delta. |
||||
* |
||||
* This is mainly used as part of a device tree application process, |
||||
* where you want the device tree overlays phandles to not conflict |
||||
* with the ones from the base device tree before merging them. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_update_local_node_references(void *fdto, |
||||
int tree_node, |
||||
int fixup_node, |
||||
uint32_t delta) |
||||
{ |
||||
int fixup_prop; |
||||
int fixup_child; |
||||
int ret; |
||||
|
||||
fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { |
||||
const fdt32_t *fixup_val; |
||||
const char *tree_val; |
||||
const char *name; |
||||
int fixup_len; |
||||
int tree_len; |
||||
int i; |
||||
|
||||
fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, |
||||
&name, &fixup_len); |
||||
if (!fixup_val) |
||||
return fixup_len; |
||||
|
||||
if (fixup_len % sizeof(uint32_t)) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); |
||||
if (!tree_val) { |
||||
if (tree_len == -FDT_ERR_NOTFOUND) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
return tree_len; |
||||
} |
||||
|
||||
for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { |
||||
fdt32_t adj_val; |
||||
uint32_t poffset; |
||||
|
||||
poffset = fdt32_to_cpu(fixup_val[i]); |
||||
|
||||
/*
|
||||
* phandles to fixup can be unaligned. |
||||
* |
||||
* Use a memcpy for the architectures that do |
||||
* not support unaligned accesses. |
||||
*/ |
||||
memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); |
||||
|
||||
adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); |
||||
|
||||
ret = fdt_setprop_inplace_namelen_partial(fdto, |
||||
tree_node, |
||||
name, |
||||
strlen(name), |
||||
poffset, |
||||
&adj_val, |
||||
sizeof(adj_val)); |
||||
if (ret == -FDT_ERR_NOSPACE) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
if (ret) |
||||
return ret; |
||||
} |
||||
} |
||||
|
||||
fdt_for_each_subnode(fixup_child, fdto, fixup_node) { |
||||
const char *fixup_child_name = fdt_get_name(fdto, fixup_child, |
||||
NULL); |
||||
int tree_child; |
||||
|
||||
tree_child = fdt_subnode_offset(fdto, tree_node, |
||||
fixup_child_name); |
||||
if (tree_child == -FDT_ERR_NOTFOUND) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
if (tree_child < 0) |
||||
return tree_child; |
||||
|
||||
ret = overlay_update_local_node_references(fdto, |
||||
tree_child, |
||||
fixup_child, |
||||
delta); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* overlay_update_local_references - Adjust the overlay references |
||||
* @fdto: Device tree overlay blob |
||||
* @delta: Offset to shift the phandles of |
||||
* |
||||
* overlay_update_local_references() update all the phandles pointing |
||||
* to a node within the device tree overlay by adding a constant |
||||
* delta to not conflict with the base overlay. |
||||
* |
||||
* This is mainly used as part of a device tree application process, |
||||
* where you want the device tree overlays phandles to not conflict |
||||
* with the ones from the base device tree before merging them. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_update_local_references(void *fdto, uint32_t delta) |
||||
{ |
||||
int fixups; |
||||
|
||||
fixups = fdt_path_offset(fdto, "/__local_fixups__"); |
||||
if (fixups < 0) { |
||||
/* There's no local phandles to adjust, bail out */ |
||||
if (fixups == -FDT_ERR_NOTFOUND) |
||||
return 0; |
||||
|
||||
return fixups; |
||||
} |
||||
|
||||
/*
|
||||
* Update our local references from the root of the tree |
||||
*/ |
||||
return overlay_update_local_node_references(fdto, 0, fixups, |
||||
delta); |
||||
} |
||||
|
||||
/**
|
||||
* overlay_fixup_one_phandle - Set an overlay phandle to the base one |
||||
* @fdt: Base Device Tree blob |
||||
* @fdto: Device tree overlay blob |
||||
* @symbols_off: Node offset of the symbols node in the base device tree |
||||
* @path: Path to a node holding a phandle in the overlay |
||||
* @path_len: number of path characters to consider |
||||
* @name: Name of the property holding the phandle reference in the overlay |
||||
* @name_len: number of name characters to consider |
||||
* @poffset: Offset within the overlay property where the phandle is stored |
||||
* @label: Label of the node referenced by the phandle |
||||
* |
||||
* overlay_fixup_one_phandle() resolves an overlay phandle pointing to |
||||
* a node in the base device tree. |
||||
* |
||||
* This is part of the device tree overlay application process, when |
||||
* you want all the phandles in the overlay to point to the actual |
||||
* base dt nodes. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_fixup_one_phandle(void *fdt, void *fdto, |
||||
int symbols_off, |
||||
const char *path, uint32_t path_len, |
||||
const char *name, uint32_t name_len, |
||||
int poffset, const char *label) |
||||
{ |
||||
const char *symbol_path; |
||||
uint32_t phandle; |
||||
fdt32_t phandle_prop; |
||||
int symbol_off, fixup_off; |
||||
int prop_len; |
||||
|
||||
if (symbols_off < 0) |
||||
return symbols_off; |
||||
|
||||
symbol_path = fdt_getprop(fdt, symbols_off, label, |
||||
&prop_len); |
||||
if (!symbol_path) |
||||
return prop_len; |
||||
|
||||
symbol_off = fdt_path_offset(fdt, symbol_path); |
||||
if (symbol_off < 0) |
||||
return symbol_off; |
||||
|
||||
phandle = fdt_get_phandle(fdt, symbol_off); |
||||
if (!phandle) |
||||
return -FDT_ERR_NOTFOUND; |
||||
|
||||
fixup_off = fdt_path_offset_namelen(fdto, path, path_len); |
||||
if (fixup_off == -FDT_ERR_NOTFOUND) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
if (fixup_off < 0) |
||||
return fixup_off; |
||||
|
||||
phandle_prop = cpu_to_fdt32(phandle); |
||||
return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, |
||||
name, name_len, poffset, |
||||
&phandle_prop, |
||||
sizeof(phandle_prop)); |
||||
}; |
||||
|
||||
/**
|
||||
* overlay_fixup_phandle - Set an overlay phandle to the base one |
||||
* @fdt: Base Device Tree blob |
||||
* @fdto: Device tree overlay blob |
||||
* @symbols_off: Node offset of the symbols node in the base device tree |
||||
* @property: Property offset in the overlay holding the list of fixups |
||||
* |
||||
* overlay_fixup_phandle() resolves all the overlay phandles pointed |
||||
* to in a __fixups__ property, and updates them to match the phandles |
||||
* in use in the base device tree. |
||||
* |
||||
* This is part of the device tree overlay application process, when |
||||
* you want all the phandles in the overlay to point to the actual |
||||
* base dt nodes. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, |
||||
int property) |
||||
{ |
||||
const char *value; |
||||
const char *label; |
||||
int len; |
||||
|
||||
value = fdt_getprop_by_offset(fdto, property, |
||||
&label, &len); |
||||
if (!value) { |
||||
if (len == -FDT_ERR_NOTFOUND) |
||||
return -FDT_ERR_INTERNAL; |
||||
|
||||
return len; |
||||
} |
||||
|
||||
do { |
||||
const char *path, *name, *fixup_end; |
||||
const char *fixup_str = value; |
||||
uint32_t path_len, name_len; |
||||
uint32_t fixup_len; |
||||
char *sep, *endptr; |
||||
int poffset, ret; |
||||
|
||||
fixup_end = memchr(value, '\0', len); |
||||
if (!fixup_end) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
fixup_len = fixup_end - fixup_str; |
||||
|
||||
len -= fixup_len + 1; |
||||
value += fixup_len + 1; |
||||
|
||||
path = fixup_str; |
||||
sep = memchr(fixup_str, ':', fixup_len); |
||||
if (!sep || *sep != ':') |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
path_len = sep - path; |
||||
if (path_len == (fixup_len - 1)) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
fixup_len -= path_len + 1; |
||||
name = sep + 1; |
||||
sep = memchr(name, ':', fixup_len); |
||||
if (!sep || *sep != ':') |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
name_len = sep - name; |
||||
if (!name_len) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
poffset = strtoul(sep + 1, &endptr, 10); |
||||
if ((*endptr != '\0') || (endptr <= (sep + 1))) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, |
||||
path, path_len, name, name_len, |
||||
poffset, label); |
||||
if (ret) |
||||
return ret; |
||||
} while (len > 0); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* overlay_fixup_phandles - Resolve the overlay phandles to the base |
||||
* device tree |
||||
* @fdt: Base Device Tree blob |
||||
* @fdto: Device tree overlay blob |
||||
* |
||||
* overlay_fixup_phandles() resolves all the overlay phandles pointing |
||||
* to nodes in the base device tree. |
||||
* |
||||
* This is one of the steps of the device tree overlay application |
||||
* process, when you want all the phandles in the overlay to point to |
||||
* the actual base dt nodes. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_fixup_phandles(void *fdt, void *fdto) |
||||
{ |
||||
int fixups_off, symbols_off; |
||||
int property; |
||||
|
||||
/* We can have overlays without any fixups */ |
||||
fixups_off = fdt_path_offset(fdto, "/__fixups__"); |
||||
if (fixups_off == -FDT_ERR_NOTFOUND) |
||||
return 0; /* nothing to do */ |
||||
if (fixups_off < 0) |
||||
return fixups_off; |
||||
|
||||
/* And base DTs without symbols */ |
||||
symbols_off = fdt_path_offset(fdt, "/__symbols__"); |
||||
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) |
||||
return symbols_off; |
||||
|
||||
fdt_for_each_property_offset(property, fdto, fixups_off) { |
||||
int ret; |
||||
|
||||
ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* overlay_apply_node - Merges a node into the base device tree |
||||
* @fdt: Base Device Tree blob |
||||
* @target: Node offset in the base device tree to apply the fragment to |
||||
* @fdto: Device tree overlay blob |
||||
* @node: Node offset in the overlay holding the changes to merge |
||||
* |
||||
* overlay_apply_node() merges a node into a target base device tree |
||||
* node pointed. |
||||
* |
||||
* This is part of the final step in the device tree overlay |
||||
* application process, when all the phandles have been adjusted and |
||||
* resolved and you just have to merge overlay into the base device |
||||
* tree. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_apply_node(void *fdt, int target, |
||||
void *fdto, int node) |
||||
{ |
||||
int property; |
||||
int subnode; |
||||
|
||||
fdt_for_each_property_offset(property, fdto, node) { |
||||
const char *name; |
||||
const void *prop; |
||||
int prop_len; |
||||
int ret; |
||||
|
||||
prop = fdt_getprop_by_offset(fdto, property, &name, |
||||
&prop_len); |
||||
if (prop_len == -FDT_ERR_NOTFOUND) |
||||
return -FDT_ERR_INTERNAL; |
||||
if (prop_len < 0) |
||||
return prop_len; |
||||
|
||||
ret = fdt_setprop(fdt, target, name, prop, prop_len); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
fdt_for_each_subnode(subnode, fdto, node) { |
||||
const char *name = fdt_get_name(fdto, subnode, NULL); |
||||
int nnode; |
||||
int ret; |
||||
|
||||
nnode = fdt_add_subnode(fdt, target, name); |
||||
if (nnode == -FDT_ERR_EXISTS) { |
||||
nnode = fdt_subnode_offset(fdt, target, name); |
||||
if (nnode == -FDT_ERR_NOTFOUND) |
||||
return -FDT_ERR_INTERNAL; |
||||
} |
||||
|
||||
if (nnode < 0) |
||||
return nnode; |
||||
|
||||
ret = overlay_apply_node(fdt, nnode, fdto, subnode); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* overlay_merge - Merge an overlay into its base device tree |
||||
* @fdt: Base Device Tree blob |
||||
* @fdto: Device tree overlay blob |
||||
* |
||||
* overlay_merge() merges an overlay into its base device tree. |
||||
* |
||||
* This is the next to last step in the device tree overlay application |
||||
* process, when all the phandles have been adjusted and resolved and |
||||
* you just have to merge overlay into the base device tree. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_merge(void *fdt, void *fdto) |
||||
{ |
||||
int fragment; |
||||
|
||||
fdt_for_each_subnode(fragment, fdto, 0) { |
||||
int overlay; |
||||
int target; |
||||
int ret; |
||||
|
||||
/*
|
||||
* Each fragments will have an __overlay__ node. If |
||||
* they don't, it's not supposed to be merged |
||||
*/ |
||||
overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); |
||||
if (overlay == -FDT_ERR_NOTFOUND) |
||||
continue; |
||||
|
||||
if (overlay < 0) |
||||
return overlay; |
||||
|
||||
target = overlay_get_target(fdt, fdto, fragment, NULL); |
||||
if (target < 0) |
||||
return target; |
||||
|
||||
ret = overlay_apply_node(fdt, target, fdto, overlay); |
||||
if (ret) |
||||
return ret; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int get_path_len(const void *fdt, int nodeoffset) |
||||
{ |
||||
int len = 0, namelen; |
||||
const char *name; |
||||
|
||||
FDT_CHECK_HEADER(fdt); |
||||
|
||||
for (;;) { |
||||
name = fdt_get_name(fdt, nodeoffset, &namelen); |
||||
if (!name) |
||||
return namelen; |
||||
|
||||
/* root? we're done */ |
||||
if (namelen == 0) |
||||
break; |
||||
|
||||
nodeoffset = fdt_parent_offset(fdt, nodeoffset); |
||||
if (nodeoffset < 0) |
||||
return nodeoffset; |
||||
len += namelen + 1; |
||||
} |
||||
|
||||
/* in case of root pretend it's "/" */ |
||||
if (len == 0) |
||||
len++; |
||||
return len; |
||||
} |
||||
|
||||
/**
|
||||
* overlay_symbol_update - Update the symbols of base tree after a merge |
||||
* @fdt: Base Device Tree blob |
||||
* @fdto: Device tree overlay blob |
||||
* |
||||
* overlay_symbol_update() updates the symbols of the base tree with the |
||||
* symbols of the applied overlay |
||||
* |
||||
* This is the last step in the device tree overlay application |
||||
* process, allowing the reference of overlay symbols by subsequent |
||||
* overlay operations. |
||||
* |
||||
* returns: |
||||
* 0 on success |
||||
* Negative error code on failure |
||||
*/ |
||||
static int overlay_symbol_update(void *fdt, void *fdto) |
||||
{ |
||||
int root_sym, ov_sym, prop, path_len, fragment, target; |
||||
int len, frag_name_len, ret, rel_path_len; |
||||
const char *s, *e; |
||||
const char *path; |
||||
const char *name; |
||||
const char *frag_name; |
||||
const char *rel_path; |
||||
const char *target_path; |
||||
char *buf; |
||||
void *p; |
||||
|
||||
ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); |
||||
|
||||
/* if no overlay symbols exist no problem */ |
||||
if (ov_sym < 0) |
||||
return 0; |
||||
|
||||
root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); |
||||
|
||||
/* it no root symbols exist we should create them */ |
||||
if (root_sym == -FDT_ERR_NOTFOUND) |
||||
root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); |
||||
|
||||
/* any error is fatal now */ |
||||
if (root_sym < 0) |
||||
return root_sym; |
||||
|
||||
/* iterate over each overlay symbol */ |
||||
fdt_for_each_property_offset(prop, fdto, ov_sym) { |
||||
path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); |
||||
if (!path) |
||||
return path_len; |
||||
|
||||
/* verify it's a string property (terminated by a single \0) */ |
||||
if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) |
||||
return -FDT_ERR_BADVALUE; |
||||
|
||||
/* keep end marker to avoid strlen() */ |
||||
e = path + path_len; |
||||
|
||||
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */ |
||||
|
||||
if (*path != '/') |
||||
return -FDT_ERR_BADVALUE; |
||||
|
||||
/* get fragment name first */ |
||||
s = strchr(path + 1, '/'); |
||||
if (!s) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
frag_name = path + 1; |
||||
frag_name_len = s - path - 1; |
||||
|
||||
/* verify format; safe since "s" lies in \0 terminated prop */ |
||||
len = sizeof("/__overlay__/") - 1; |
||||
if ((e - s) < len || memcmp(s, "/__overlay__/", len)) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
rel_path = s + len; |
||||
rel_path_len = e - rel_path; |
||||
|
||||
/* find the fragment index in which the symbol lies */ |
||||
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, |
||||
frag_name_len); |
||||
/* not found? */ |
||||
if (ret < 0) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
fragment = ret; |
||||
|
||||
/* an __overlay__ subnode must exist */ |
||||
ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); |
||||
if (ret < 0) |
||||
return -FDT_ERR_BADOVERLAY; |
||||
|
||||
/* get the target of the fragment */ |
||||
ret = overlay_get_target(fdt, fdto, fragment, &target_path); |
||||
if (ret < 0) |
||||
return ret; |
||||
target = ret; |
||||
|
||||
/* if we have a target path use */ |
||||
if (!target_path) { |
||||
ret = get_path_len(fdt, target); |
||||
if (ret < 0) |
||||
return ret; |
||||
len = ret; |
||||
} else { |
||||
len = strlen(target_path); |
||||
} |
||||
|
||||
ret = fdt_setprop_placeholder(fdt, root_sym, name, |
||||
len + (len > 1) + rel_path_len + 1, &p); |
||||
if (ret < 0) |
||||
return ret; |
||||
|
||||
if (!target_path) { |
||||
/* again in case setprop_placeholder changed it */ |
||||
ret = overlay_get_target(fdt, fdto, fragment, &target_path); |
||||
if (ret < 0) |
||||
return ret; |
||||
target = ret; |
||||
} |
||||
|
||||
buf = p; |
||||
if (len > 1) { /* target is not root */ |
||||
if (!target_path) { |
||||
ret = fdt_get_path(fdt, target, buf, len + 1); |
||||
if (ret < 0) |
||||
return ret; |
||||
} else |
||||
memcpy(buf, target_path, len + 1); |
||||
|
||||
} else |
||||
len--; |
||||
|
||||
buf[len] = '/'; |
||||
memcpy(buf + len + 1, rel_path, rel_path_len); |
||||
buf[len + 1 + rel_path_len] = '\0'; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int fdt_overlay_apply(void *fdt, void *fdto) |
||||
{ |
||||
uint32_t delta = fdt_get_max_phandle(fdt); |
||||
int ret; |
||||
|
||||
FDT_CHECK_HEADER(fdt); |
||||
FDT_CHECK_HEADER(fdto); |
||||
|
||||
ret = overlay_adjust_local_phandles(fdto, delta); |
||||
if (ret) |
||||
goto err; |
||||
|
||||
ret = overlay_update_local_references(fdto, delta); |
||||
if (ret) |
||||
goto err; |
||||
|
||||
ret = overlay_fixup_phandles(fdt, fdto); |
||||
if (ret) |
||||
goto err; |
||||
|
||||
ret = overlay_merge(fdt, fdto); |
||||
if (ret) |
||||
goto err; |
||||
|
||||
ret = overlay_symbol_update(fdt, fdto); |
||||
if (ret) |
||||
goto err; |
||||
|
||||
/*
|
||||
* The overlay has been damaged, erase its magic. |
||||
*/ |
||||
fdt_set_magic(fdto, ~0); |
||||
|
||||
return 0; |
||||
|
||||
err: |
||||
/*
|
||||
* The overlay might have been damaged, erase its magic. |
||||
*/ |
||||
fdt_set_magic(fdto, ~0); |
||||
|
||||
/*
|
||||
* The base device tree might have been damaged, erase its |
||||
* magic. |
||||
*/ |
||||
fdt_set_magic(fdt, ~0); |
||||
|
||||
return ret; |
||||
} |
||||
#include <linux/libfdt_env.h> |
||||
#include "../../scripts/dtc/libfdt/fdt_overlay.c" |
||||
|
@ -1,61 +1,2 @@ |
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation |
||||
* Copyright (C) 2006 David Gibson, IBM Corporation. |
||||
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause |
||||
*/ |
||||
#include <libfdt_env.h> |
||||
|
||||
#ifndef USE_HOSTCC |
||||
#include <fdt.h> |
||||
#include <libfdt.h> |
||||
#else |
||||
#include "fdt_host.h" |
||||
#endif |
||||
|
||||
#include "libfdt_internal.h" |
||||
|
||||
struct fdt_errtabent { |
||||
const char *str; |
||||
}; |
||||
|
||||
#define FDT_ERRTABENT(val) \ |
||||
[(val)] = { .str = #val, } |
||||
|
||||
static struct fdt_errtabent fdt_errtable[] = { |
||||
FDT_ERRTABENT(FDT_ERR_NOTFOUND), |
||||
FDT_ERRTABENT(FDT_ERR_EXISTS), |
||||
FDT_ERRTABENT(FDT_ERR_NOSPACE), |
||||
|
||||
FDT_ERRTABENT(FDT_ERR_BADOFFSET), |
||||
FDT_ERRTABENT(FDT_ERR_BADPATH), |
||||
FDT_ERRTABENT(FDT_ERR_BADPHANDLE), |
||||
FDT_ERRTABENT(FDT_ERR_BADSTATE), |
||||
|
||||
FDT_ERRTABENT(FDT_ERR_TRUNCATED), |
||||
FDT_ERRTABENT(FDT_ERR_BADMAGIC), |
||||
FDT_ERRTABENT(FDT_ERR_BADVERSION), |
||||
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), |
||||
FDT_ERRTABENT(FDT_ERR_BADLAYOUT), |
||||
FDT_ERRTABENT(FDT_ERR_INTERNAL), |
||||
FDT_ERRTABENT(FDT_ERR_BADNCELLS), |
||||
FDT_ERRTABENT(FDT_ERR_BADVALUE), |
||||
FDT_ERRTABENT(FDT_ERR_BADOVERLAY), |
||||
FDT_ERRTABENT(FDT_ERR_NOPHANDLES), |
||||
}; |
||||
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) |
||||
|
||||
const char *fdt_strerror(int errval) |
||||
{ |
||||
if (errval > 0) |
||||
return "<valid offset/length>"; |
||||
else if (errval == 0) |
||||
return "<no error>"; |
||||
else if (errval > -FDT_ERRTABSIZE) { |
||||
const char *s = fdt_errtable[-errval].str; |
||||
|
||||
if (s) |
||||
return s; |
||||
} |
||||
|
||||
return "<unknown error>"; |
||||
} |
||||
#include <linux/libfdt_env.h> |
||||
#include "../../scripts/dtc/libfdt/fdt_strerror.c" |
||||
|
@ -1,254 +1,2 @@ |
||||
/*
|
||||
* libfdt - Flat Device Tree manipulation |
||||
* Copyright (C) 2006 David Gibson, IBM Corporation. |
||||
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause |
||||
*/ |
||||
#include <libfdt_env.h> |
||||
#include <fdt.h> |
||||
#include <libfdt.h> |
||||
|
||||
#include "libfdt_internal.h" |
||||
|
||||
static int _fdt_sw_check_header(void *fdt) |
||||
{ |
||||
if (fdt_magic(fdt) != FDT_SW_MAGIC) |
||||
return -FDT_ERR_BADMAGIC; |
||||
/* FIXME: should check more details about the header state */ |
||||
return 0; |
||||
} |
||||
|
||||
#define FDT_SW_CHECK_HEADER(fdt) \ |
||||
{ \
|
||||
int err; \
|
||||
if ((err = _fdt_sw_check_header(fdt)) != 0) \
|
||||
return err; \
|
||||
} |
||||
|
||||
static void *_fdt_grab_space(void *fdt, size_t len) |
||||
{ |
||||
int offset = fdt_size_dt_struct(fdt); |
||||
int spaceleft; |
||||
|
||||
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) |
||||
- fdt_size_dt_strings(fdt); |
||||
|
||||
if ((offset + len < offset) || (offset + len > spaceleft)) |
||||
return NULL; |
||||
|
||||
fdt_set_size_dt_struct(fdt, offset + len); |
||||
return _fdt_offset_ptr_w(fdt, offset); |
||||
} |
||||
|
||||
int fdt_create(void *buf, int bufsize) |
||||
{ |
||||
void *fdt = buf; |
||||
|
||||
if (bufsize < sizeof(struct fdt_header)) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
memset(buf, 0, bufsize); |
||||
|
||||
fdt_set_magic(fdt, FDT_SW_MAGIC); |
||||
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); |
||||
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); |
||||
fdt_set_totalsize(fdt, bufsize); |
||||
|
||||
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), |
||||
sizeof(struct fdt_reserve_entry))); |
||||
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); |
||||
fdt_set_off_dt_strings(fdt, bufsize); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int fdt_resize(void *fdt, void *buf, int bufsize) |
||||
{ |
||||
size_t headsize, tailsize; |
||||
char *oldtail, *newtail; |
||||
|
||||
FDT_SW_CHECK_HEADER(fdt); |
||||
|
||||
headsize = fdt_off_dt_struct(fdt); |
||||
tailsize = fdt_size_dt_strings(fdt); |
||||
|
||||
if ((headsize + tailsize) > bufsize) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; |
||||
newtail = (char *)buf + bufsize - tailsize; |
||||
|
||||
/* Two cases to avoid clobbering data if the old and new
|
||||
* buffers partially overlap */ |
||||
if (buf <= fdt) { |
||||
memmove(buf, fdt, headsize); |
||||
memmove(newtail, oldtail, tailsize); |
||||
} else { |
||||
memmove(newtail, oldtail, tailsize); |
||||
memmove(buf, fdt, headsize); |
||||
} |
||||
|
||||
fdt_set_off_dt_strings(buf, bufsize); |
||||
fdt_set_totalsize(buf, bufsize); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) |
||||
{ |
||||
struct fdt_reserve_entry *re; |
||||
int offset; |
||||
|
||||
FDT_SW_CHECK_HEADER(fdt); |
||||
|
||||
if (fdt_size_dt_struct(fdt)) |
||||
return -FDT_ERR_BADSTATE; |
||||
|
||||
offset = fdt_off_dt_struct(fdt); |
||||
if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
re = (struct fdt_reserve_entry *)((char *)fdt + offset); |
||||
re->address = cpu_to_fdt64(addr); |
||||
re->size = cpu_to_fdt64(size); |
||||
|
||||
fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int fdt_finish_reservemap(void *fdt) |
||||
{ |
||||
return fdt_add_reservemap_entry(fdt, 0, 0); |
||||
} |
||||
|
||||
int fdt_begin_node(void *fdt, const char *name) |
||||
{ |
||||
struct fdt_node_header *nh; |
||||
int namelen = strlen(name) + 1; |
||||
|
||||
FDT_SW_CHECK_HEADER(fdt); |
||||
|
||||
nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); |
||||
if (! nh) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); |
||||
memcpy(nh->name, name, namelen); |
||||
return 0; |
||||
} |
||||
|
||||
int fdt_end_node(void *fdt) |
||||
{ |
||||
fdt32_t *en; |
||||
|
||||
FDT_SW_CHECK_HEADER(fdt); |
||||
|
||||
en = _fdt_grab_space(fdt, FDT_TAGSIZE); |
||||
if (! en) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
*en = cpu_to_fdt32(FDT_END_NODE); |
||||
return 0; |
||||
} |
||||
|
||||
static int _fdt_find_add_string(void *fdt, const char *s) |
||||
{ |
||||
char *strtab = (char *)fdt + fdt_totalsize(fdt); |
||||
const char *p; |
||||
int strtabsize = fdt_size_dt_strings(fdt); |
||||
int len = strlen(s) + 1; |
||||
int struct_top, offset; |
||||
|
||||
p = _fdt_find_string(strtab - strtabsize, strtabsize, s); |
||||
if (p) |
||||
return p - strtab; |
||||
|
||||
/* Add it */ |
||||
offset = -strtabsize - len; |
||||
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); |
||||
if (fdt_totalsize(fdt) + offset < struct_top) |
||||
return 0; /* no more room :( */ |
||||
|
||||
memcpy(strtab + offset, s, len); |
||||
fdt_set_size_dt_strings(fdt, strtabsize + len); |
||||
return offset; |
||||
} |
||||
|
||||
int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) |
||||
{ |
||||
struct fdt_property *prop; |
||||
int nameoff; |
||||
|
||||
FDT_SW_CHECK_HEADER(fdt); |
||||
|
||||
nameoff = _fdt_find_add_string(fdt, name); |
||||
if (nameoff == 0) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); |
||||
if (! prop) |
||||
return -FDT_ERR_NOSPACE; |
||||
|
||||
prop->tag = cpu_to_fdt32(FDT_PROP); |
||||
prop->nameoff = cpu_to_fdt32(nameoff); |
||||
prop->len = cpu_to_fdt32(len); |
||||
*valp = prop->data; |
||||
return 0; |
||||
} |
||||
|
||||
int fdt_property(void *fdt, const char *name, const void *val, int len) |
||||
{ |
||||
void *ptr; |
||||
int ret; |
||||
|
||||
ret = fdt_property_placeholder(fdt, name, len, &ptr); |
||||
if (ret) |
||||
return ret; |
||||
memcpy(ptr, val, len); |
||||
return 0; |
||||
} |
||||
|
||||
int fdt_finish(void *fdt) |
||||
{ |
||||
char *p = (char *)fdt; |
||||
fdt32_t *end; |
||||
int oldstroffset, newstroffset; |
||||
uint32_t tag; |
||||
int offset, nextoffset; |
||||
|
||||
FDT_SW_CHECK_HEADER(fdt); |
||||
|
||||
/* Add terminator */ |
||||
end = _fdt_grab_space(fdt, sizeof(*end)); |
||||
if (! end) |
||||
return -FDT_ERR_NOSPACE; |
||||
*end = cpu_to_fdt32(FDT_END); |
||||
|
||||
/* Relocate the string table */ |
||||
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); |
||||
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); |
||||
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); |
||||
fdt_set_off_dt_strings(fdt, newstroffset); |
||||
|
||||
/* Walk the structure, correcting string offsets */ |
||||
offset = 0; |
||||
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { |
||||
if (tag == FDT_PROP) { |
||||
struct fdt_property *prop = |
||||
_fdt_offset_ptr_w(fdt, offset); |
||||
int nameoff; |
||||
|
||||
nameoff = fdt32_to_cpu(prop->nameoff); |
||||
nameoff += fdt_size_dt_strings(fdt); |
||||
prop->nameoff = cpu_to_fdt32(nameoff); |
||||
} |
||||
offset = nextoffset; |
||||
} |
||||
if (nextoffset < 0) |
||||
return nextoffset; |
||||
|
||||
/* Finally, adjust the header */ |
||||
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); |
||||
fdt_set_magic(fdt, FDT_MAGIC); |
||||
return 0; |
||||
} |
||||
#include <linux/libfdt_env.h> |
||||
#include "../../scripts/dtc/libfdt/fdt_sw.c" |
||||
|
Loading…
Reference in new issue