Unverified Commit 799bbb1d authored by Antonio Niño Díaz's avatar Antonio Niño Díaz Committed by GitHub
Browse files

Merge pull request #1643 from antonio-nino-diaz-arm/an/libfdt

Update libfdt to version 1.4.7
parents dfe5c78e 630b011f
...@@ -27,5 +27,6 @@ char *strchr(const char *s, int c); ...@@ -27,5 +27,6 @@ char *strchr(const char *s, int c);
void *memset(void *dst, int val, size_t count); void *memset(void *dst, int val, size_t count);
size_t strlen(const char *s); size_t strlen(const char *s);
size_t strnlen(const char *s, size_t maxlen); size_t strnlen(const char *s, size_t maxlen);
char *strrchr(const char *p, int ch);
#endif /* STRING_H */ #endif /* STRING_H */
#ifndef _FDT_H #ifndef FDT_H
#define _FDT_H #define FDT_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
...@@ -52,16 +52,8 @@ ...@@ -52,16 +52,8 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/*
* Portions copyright (c) 2016-2017, ARM Limited and Contributors.
* All rights reserved.
*/
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <libfdt_env.h>
struct fdt_header { struct fdt_header {
fdt32_t magic; /* magic word FDT_MAGIC */ fdt32_t magic; /* magic word FDT_MAGIC */
fdt32_t totalsize; /* total size of DT block */ fdt32_t totalsize; /* total size of DT block */
...@@ -88,14 +80,14 @@ struct fdt_reserve_entry { ...@@ -88,14 +80,14 @@ struct fdt_reserve_entry {
struct fdt_node_header { struct fdt_node_header {
fdt32_t tag; fdt32_t tag;
char name[]; char name[0];
}; };
struct fdt_property { struct fdt_property {
fdt32_t tag; fdt32_t tag;
fdt32_t len; fdt32_t len;
fdt32_t nameoff; fdt32_t nameoff;
char data[]; char data[0];
}; };
#endif /* !__ASSEMBLY */ #endif /* !__ASSEMBLY */
...@@ -116,4 +108,4 @@ struct fdt_property { ...@@ -116,4 +108,4 @@ struct fdt_property {
#define FDT_V16_SIZE FDT_V3_SIZE #define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
#endif /* _FDT_H */ #endif /* FDT_H */
#ifndef _LIBFDT_H #ifndef LIBFDT_H
#define _LIBFDT_H #define LIBFDT_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
...@@ -51,22 +51,17 @@ ...@@ -51,22 +51,17 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
/*
* Portions copyright (c) 2016-2017, ARM Limited and Contributors.
* All rights reserved.
*/
#include <libfdt_env.h> #include <libfdt_env.h>
#include <fdt.h> #include <fdt.h>
#define FDT_FIRST_SUPPORTED_VERSION 0x10 #define FDT_FIRST_SUPPORTED_VERSION 0x02
#define FDT_LAST_SUPPORTED_VERSION 0x11 #define FDT_LAST_SUPPORTED_VERSION 0x11
/* Error codes: informative error codes */ /* Error codes: informative error codes */
#define FDT_ERR_NOTFOUND 1 #define FDT_ERR_NOTFOUND 1
/* FDT_ERR_NOTFOUND: The requested node or property does not exist */ /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
#define FDT_ERR_EXISTS 2 #define FDT_ERR_EXISTS 2
/* FDT_ERR_EXISTS: Attemped to create a node or property which /* FDT_ERR_EXISTS: Attempted to create a node or property which
* already exists */ * already exists */
#define FDT_ERR_NOSPACE 3 #define FDT_ERR_NOSPACE 3
/* FDT_ERR_NOSPACE: Operation needed to expand the device /* FDT_ERR_NOSPACE: Operation needed to expand the device
...@@ -84,8 +79,10 @@ ...@@ -84,8 +79,10 @@
* (e.g. missing a leading / for a function which requires an * (e.g. missing a leading / for a function which requires an
* absolute path) */ * absolute path) */
#define FDT_ERR_BADPHANDLE 6 #define FDT_ERR_BADPHANDLE 6
/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
* value. phandle values of 0 and -1 are not permitted. */ * This can be caused either by an invalid phandle property
* length, or the phandle value was either 0 or -1, which are
* not permitted. */
#define FDT_ERR_BADSTATE 7 #define FDT_ERR_BADSTATE 7
/* FDT_ERR_BADSTATE: Function was passed an incomplete device /* FDT_ERR_BADSTATE: Function was passed an incomplete device
* tree created by the sequential-write functions, which is * tree created by the sequential-write functions, which is
...@@ -93,8 +90,9 @@ ...@@ -93,8 +90,9 @@
/* Error codes: codes for bad device tree blobs */ /* Error codes: codes for bad device tree blobs */
#define FDT_ERR_TRUNCATED 8 #define FDT_ERR_TRUNCATED 8
/* FDT_ERR_TRUNCATED: Structure block of the given device tree /* FDT_ERR_TRUNCATED: FDT or a sub-block is improperly
* ends without an FDT_END tag. */ * terminated (overflows, goes outside allowed bounds, or
* isn't properly terminated). */
#define FDT_ERR_BADMAGIC 9 #define FDT_ERR_BADMAGIC 9
/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
* device tree at all - it is missing the flattened device * device tree at all - it is missing the flattened device
...@@ -131,13 +129,24 @@ ...@@ -131,13 +129,24 @@
* value. For example: a property expected to contain a string list * value. For example: a property expected to contain a string list
* is not NUL-terminated within the length of its value. */ * is not NUL-terminated within the length of its value. */
#define FDT_ERR_MAX 15 #define FDT_ERR_BADOVERLAY 16
/* FDT_ERR_BADOVERLAY: The device tree overlay, while
* correctly structured, cannot be applied due to some
* unexpected or missing value, property or node. */
#define FDT_ERR_NOPHANDLES 17
/* FDT_ERR_NOPHANDLES: The device tree doesn't have any
* phandle available anymore without causing an overflow */
#define FDT_ERR_MAX 17
/**********************************************************************/ /**********************************************************************/
/* Low-level functions (you probably don't need these) */ /* Low-level functions (you probably don't need these) */
/**********************************************************************/ /**********************************************************************/
#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
static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) 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);
...@@ -145,6 +154,29 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) ...@@ -145,6 +154,29 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
/*
* Alignment helpers:
* These helpers access words from a device tree blob. They're
* built to work even with unaligned pointers on platforms (ike
* ARM) that don't like unaligned loads and stores
*/
static inline uint32_t fdt32_ld(const fdt32_t *p)
{
fdt32_t v;
memcpy(&v, p, sizeof(v));
return fdt32_to_cpu(v);
}
static inline uint64_t fdt64_ld(const fdt64_t *p)
{
fdt64_t v;
memcpy(&v, p, sizeof(v));
return fdt64_to_cpu(v);
}
/**********************************************************************/ /**********************************************************************/
/* Traversal functions */ /* Traversal functions */
/**********************************************************************/ /**********************************************************************/
...@@ -204,9 +236,8 @@ int fdt_next_subnode(const void *fdt, int offset); ...@@ -204,9 +236,8 @@ int fdt_next_subnode(const void *fdt, int offset);
/**********************************************************************/ /**********************************************************************/
/* General functions */ /* General functions */
/**********************************************************************/ /**********************************************************************/
#define fdt_get_header(fdt, field) \ #define fdt_get_header(fdt, field) \
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) (fdt32_ld(&((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize))
#define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct))
...@@ -218,37 +249,50 @@ int fdt_next_subnode(const void *fdt, int offset); ...@@ -218,37 +249,50 @@ int fdt_next_subnode(const void *fdt, int offset);
#define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings))
#define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct))
#define __fdt_set_hdr(name) \ #define fdt_set_hdr_(name) \
static inline void fdt_set_##name(void *fdt, uint32_t val) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \
{ \ { \
struct fdt_header *fdth = (struct fdt_header *)fdt; \ struct fdt_header *fdth = (struct fdt_header *)fdt; \
fdth->name = cpu_to_fdt32(val); \ fdth->name = cpu_to_fdt32(val); \
} }
__fdt_set_hdr(magic) fdt_set_hdr_(magic);
__fdt_set_hdr(totalsize) fdt_set_hdr_(totalsize);
__fdt_set_hdr(off_dt_struct) fdt_set_hdr_(off_dt_struct);
__fdt_set_hdr(off_dt_strings) fdt_set_hdr_(off_dt_strings);
__fdt_set_hdr(off_mem_rsvmap) fdt_set_hdr_(off_mem_rsvmap);
__fdt_set_hdr(version) fdt_set_hdr_(version);
__fdt_set_hdr(last_comp_version) fdt_set_hdr_(last_comp_version);
__fdt_set_hdr(boot_cpuid_phys) fdt_set_hdr_(boot_cpuid_phys);
__fdt_set_hdr(size_dt_strings) fdt_set_hdr_(size_dt_strings);
__fdt_set_hdr(size_dt_struct) fdt_set_hdr_(size_dt_struct);
#undef __fdt_set_hdr #undef fdt_set_hdr_
/** /**
* fdt_check_header - sanity check a device tree or possible device tree * fdt_header_size - return the size of the tree's header
* @fdt: pointer to a flattened device tree
*/
size_t fdt_header_size_(uint32_t version);
static inline size_t fdt_header_size(const void *fdt)
{
return fdt_header_size_(fdt_version(fdt));
}
/**
* fdt_check_header - sanity check a device tree header
* @fdt: pointer to data which might be a flattened device tree * @fdt: pointer to data which might be a flattened device tree
* *
* fdt_check_header() checks that the given buffer contains what * fdt_check_header() checks that the given buffer contains what
* appears to be a flattened device tree with sane information in its * appears to be a flattened device tree, and that the header contains
* header. * valid information (to the extent that can be determined from the
* header alone).
* *
* returns: * returns:
* 0, if the buffer appears to contain a valid device tree * 0, if the buffer appears to contain a valid device tree
* -FDT_ERR_BADMAGIC, * -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION, * -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings, as above * -FDT_ERR_BADSTATE,
* -FDT_ERR_TRUNCATED, standard meanings, as above
*/ */
int fdt_check_header(const void *fdt); int fdt_check_header(const void *fdt);
...@@ -277,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize); ...@@ -277,6 +321,24 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
/* Read-only functions */ /* Read-only functions */
/**********************************************************************/ /**********************************************************************/
int fdt_check_full(const void *fdt, size_t bufsize);
/**
* fdt_get_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob
* @stroffset: offset of the string within the strings block (native endian)
* @lenp: optional pointer to return the string's length
*
* fdt_get_string() retrieves a pointer to a single string from the
* strings block of the device tree blob at fdt, and optionally also
* returns the string's length in *lenp.
*
* returns:
* a pointer to the string, on success
* NULL, if stroffset is out of bounds, or doesn't point to a valid string
*/
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp);
/** /**
* fdt_string - retrieve a string from the strings block of a device tree * fdt_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob
...@@ -287,7 +349,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize); ...@@ -287,7 +349,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
* *
* returns: * returns:
* a pointer to the string, on success * a pointer to the string, on success
* NULL, if stroffset is out of bounds * NULL, if stroffset is out of bounds, or doesn't point to a valid string
*/ */
const char *fdt_string(const void *fdt, int stroffset); const char *fdt_string(const void *fdt, int stroffset);
...@@ -348,8 +410,10 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); ...@@ -348,8 +410,10 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
* useful for finding subnodes based on a portion of a larger string, * useful for finding subnodes based on a portion of a larger string,
* such as a full path. * such as a full path.
*/ */
#ifndef SWIG /* Not available in Python */
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
const char *name, int namelen); const char *name, int namelen);
#endif
/** /**
* fdt_subnode_offset - find a subnode of a given node * fdt_subnode_offset - find a subnode of a given node
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob
...@@ -385,7 +449,9 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); ...@@ -385,7 +449,9 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
* Identical to fdt_path_offset(), but only consider the first namelen * Identical to fdt_path_offset(), but only consider the first namelen
* characters of path as the path name. * characters of path as the path name.
*/ */
#ifndef SWIG /* Not available in Python */
int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
#endif
/** /**
* fdt_path_offset - find a tree node by its full path * fdt_path_offset - find a tree node by its full path
...@@ -516,6 +582,9 @@ int fdt_next_property_offset(const void *fdt, int offset); ...@@ -516,6 +582,9 @@ int fdt_next_property_offset(const void *fdt, int offset);
* offset. If lenp is non-NULL, the length of the property value is * offset. If lenp is non-NULL, the length of the property value is
* also returned, in the integer pointed to by lenp. * also returned, in the integer pointed to by lenp.
* *
* Note that this code only works on device tree versions >= 16. fdt_getprop()
* works on all versions.
*
* returns: * returns:
* pointer to the structure representing the property * pointer to the structure representing the property
* if lenp is non-NULL, *lenp contains the length of the property * if lenp is non-NULL, *lenp contains the length of the property
...@@ -544,10 +613,12 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, ...@@ -544,10 +613,12 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
* Identical to fdt_get_property(), but only examine the first namelen * Identical to fdt_get_property(), but only examine the first namelen
* characters of name for matching the property name. * characters of name for matching the property name.
*/ */
#ifndef SWIG /* Not available in Python */
const struct fdt_property *fdt_get_property_namelen(const void *fdt, const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int nodeoffset, int nodeoffset,
const char *name, const char *name,
int namelen, int *lenp); int namelen, int *lenp);
#endif
/** /**
* fdt_get_property - find a given property in a given node * fdt_get_property - find a given property in a given node
...@@ -618,8 +689,10 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, ...@@ -618,8 +689,10 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
* -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings * -FDT_ERR_TRUNCATED, standard meanings
*/ */
#ifndef SWIG /* This function is not useful in Python */
const void *fdt_getprop_by_offset(const void *fdt, int offset, const void *fdt_getprop_by_offset(const void *fdt, int offset,
const char **namep, int *lenp); const char **namep, int *lenp);
#endif
/** /**
* fdt_getprop_namelen - get property value based on substring * fdt_getprop_namelen - get property value based on substring
...@@ -632,6 +705,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, ...@@ -632,6 +705,7 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
* Identical to fdt_getprop(), but only examine the first namelen * Identical to fdt_getprop(), but only examine the first namelen
* characters of name for matching the property name. * characters of name for matching the property name.
*/ */
#ifndef SWIG /* Not available in Python */
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp); const char *name, int namelen, int *lenp);
static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
...@@ -641,6 +715,7 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, ...@@ -641,6 +715,7 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset,
return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name,
namelen, lenp); namelen, lenp);
} }
#endif
/** /**
* fdt_getprop - retrieve the value of a given property * fdt_getprop - retrieve the value of a given property
...@@ -701,11 +776,13 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); ...@@ -701,11 +776,13 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
* Identical to fdt_get_alias(), but only examine the first namelen * Identical to fdt_get_alias(), but only examine the first namelen
* characters of name for matching the alias name. * characters of name for matching the alias name.
*/ */
#ifndef SWIG /* Not available in Python */
const char *fdt_get_alias_namelen(const void *fdt, const char *fdt_get_alias_namelen(const void *fdt,
const char *name, int namelen); const char *name, int namelen);
#endif
/** /**
* fdt_get_alias - retreive the path referenced by a given alias * fdt_get_alias - retrieve the path referenced by a given alias
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob
* @name: name of the alias th look up * @name: name of the alias th look up
* *
...@@ -1068,7 +1145,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset); ...@@ -1068,7 +1145,7 @@ int fdt_address_cells(const void *fdt, int nodeoffset);
* *
* returns: * returns:
* 0 <= n < FDT_MAX_NCELLS, on success * 0 <= n < FDT_MAX_NCELLS, on success
* 2, if the node has no #address-cells property * 2, if the node has no #size-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #size-cells property * #size-cells property
* -FDT_ERR_BADMAGIC, * -FDT_ERR_BADMAGIC,
...@@ -1100,10 +1177,12 @@ int fdt_size_cells(const void *fdt, int nodeoffset); ...@@ -1100,10 +1177,12 @@ int fdt_size_cells(const void *fdt, int nodeoffset);
* of the name. It is useful when you want to manipulate only one value of * of the name. It is useful when you want to manipulate only one value of
* an array and you have a string that doesn't end with \0. * an array and you have a string that doesn't end with \0.
*/ */
#ifndef SWIG /* Not available in Python */
int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
const char *name, int namelen, const char *name, int namelen,
uint32_t idx, const void *val, uint32_t idx, const void *val,
int len); int len);
#endif
/** /**
* fdt_setprop_inplace - change a property's value, but not its size * fdt_setprop_inplace - change a property's value, but not its size
...@@ -1133,8 +1212,10 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, ...@@ -1133,8 +1212,10 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset,
* -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings * -FDT_ERR_TRUNCATED, standard meanings
*/ */
#ifndef SWIG /* Not available in Python */
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len); const void *val, int len);
#endif
/** /**
* fdt_setprop_inplace_u32 - change the value of a 32-bit integer property * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
...@@ -1287,10 +1368,29 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) ...@@ -1287,10 +1368,29 @@ static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
fdt64_t tmp = cpu_to_fdt64(val); fdt64_t tmp = cpu_to_fdt64(val);
return fdt_property(fdt, name, &tmp, sizeof(tmp)); return fdt_property(fdt, name, &tmp, sizeof(tmp));
} }
#ifndef SWIG /* Not available in Python */
static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
{ {
return fdt_property_u32(fdt, name, val); return fdt_property_u32(fdt, name, val);
} }
#endif
/**
* fdt_property_placeholder - add a new property and return a ptr to its value
*
* @fdt: pointer to the device tree blob
* @name: name of property to add
* @len: length of property value in bytes
* @valp: returns a pointer to where where the value should be placed
*
* returns:
* 0, on success
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_NOSPACE, standard meanings
*/
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)
int fdt_end_node(void *fdt); int fdt_end_node(void *fdt);
...@@ -1409,6 +1509,37 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name); ...@@ -1409,6 +1509,37 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
int fdt_setprop(void *fdt, int nodeoffset, const char *name, int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len); const void *val, int len);
/**
* fdt_setprop_placeholder - allocate space for a property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @len: length of the property value
* @prop_data: return pointer to property data
*
* fdt_setprop_placeholer() allocates the named property in the given node.
* If the property exists it is resized. In either case a pointer to the
* property data is returned.
*
* This function may insert or delete data from the blob, and will
* therefore change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
* contain the new property value
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
int len, void **prop_data);
/** /**
* fdt_setprop_u32 - set a property to a 32-bit integer * fdt_setprop_u32 - set a property to a 32-bit integer
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob
...@@ -1521,6 +1652,36 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, ...@@ -1521,6 +1652,36 @@ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
#define fdt_setprop_string(fdt, nodeoffset, name, str) \ #define fdt_setprop_string(fdt, nodeoffset, name, str) \
fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
/**
* fdt_setprop_empty - set a property to an empty value
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
*
* fdt_setprop_empty() sets the value of the named property in the
* given node to an empty (zero length) value, or creates a new empty
* property if it does not already exist.
*
* This function may insert or delete data from the blob, and will
* therefore change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
* contain the new property value
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
#define fdt_setprop_empty(fdt, nodeoffset, name) \
fdt_setprop((fdt), (nodeoffset), (name), NULL, 0)
/** /**
* fdt_appendprop - append to or create a property * fdt_appendprop - append to or create a property
* @fdt: pointer to the device tree blob * @fdt: pointer to the device tree blob
...@@ -1698,8 +1859,10 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name); ...@@ -1698,8 +1859,10 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name);
* creating subnodes based on a portion of a larger string, such as a * creating subnodes based on a portion of a larger string, such as a
* full path. * full path.
*/ */
#ifndef SWIG /* Not available in Python */
int fdt_add_subnode_namelen(void *fdt, int parentoffset, int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen); const char *name, int namelen);
#endif
/** /**
* fdt_add_subnode - creates a new node * fdt_add_subnode - creates a new node
...@@ -1757,10 +1920,41 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); ...@@ -1757,10 +1920,41 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
*/ */
int fdt_del_node(void *fdt, int nodeoffset); int fdt_del_node(void *fdt, int nodeoffset);
/**
* fdt_overlay_apply - Applies a DT overlay on a base DT
* @fdt: pointer to the base device tree blob
* @fdto: pointer to the device tree overlay blob
*
* fdt_overlay_apply() will apply the given device tree overlay on the
* given base device tree.
*
* Expect the base device tree to be modified, even if the function
* returns an error.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there's not enough space in the base device tree
* -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or
* properties in the base DT
* -FDT_ERR_BADPHANDLE,
* -FDT_ERR_BADOVERLAY,
* -FDT_ERR_NOPHANDLES,
* -FDT_ERR_INTERNAL,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADOFFSET,
* -FDT_ERR_BADPATH,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int fdt_overlay_apply(void *fdt, void *fdto);
/**********************************************************************/ /**********************************************************************/
/* Debugging / informational functions */ /* Debugging / informational functions */
/**********************************************************************/ /**********************************************************************/
const char *fdt_strerror(int errval); const char *fdt_strerror(int errval);
#endif /* _LIBFDT_H */ #endif /* LIBFDT_H */
#ifndef _LIBFDT_ENV_H #ifndef LIBFDT_ENV_H
#define _LIBFDT_ENV_H #define LIBFDT_ENV_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
...@@ -54,19 +54,21 @@ ...@@ -54,19 +54,21 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h>
#ifdef __CHECKER__ #ifdef __CHECKER__
#define __force __attribute__((force)) #define FDT_FORCE __attribute__((force))
#define __bitwise __attribute__((bitwise)) #define FDT_BITWISE __attribute__((bitwise))
#else #else
#define __force #define FDT_FORCE
#define __bitwise #define FDT_BITWISE
#endif #endif
typedef uint16_t __bitwise fdt16_t; typedef uint16_t FDT_BITWISE fdt16_t;
typedef uint32_t __bitwise fdt32_t; typedef uint32_t FDT_BITWISE fdt32_t;
typedef uint64_t __bitwise fdt64_t; typedef uint64_t FDT_BITWISE fdt64_t;
#define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) #define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n])
#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) #define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
...@@ -79,33 +81,60 @@ typedef uint64_t __bitwise fdt64_t; ...@@ -79,33 +81,60 @@ typedef uint64_t __bitwise fdt64_t;
static inline uint16_t fdt16_to_cpu(fdt16_t x) static inline uint16_t fdt16_to_cpu(fdt16_t x)
{ {
return (__force uint16_t)CPU_TO_FDT16(x); return (FDT_FORCE uint16_t)CPU_TO_FDT16(x);
} }
static inline fdt16_t cpu_to_fdt16(uint16_t x) static inline fdt16_t cpu_to_fdt16(uint16_t x)
{ {
return (__force fdt16_t)CPU_TO_FDT16(x); return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x);
} }
static inline uint32_t fdt32_to_cpu(fdt32_t x) static inline uint32_t fdt32_to_cpu(fdt32_t x)
{ {
return (__force uint32_t)CPU_TO_FDT32(x); return (FDT_FORCE uint32_t)CPU_TO_FDT32(x);
} }
static inline fdt32_t cpu_to_fdt32(uint32_t x) static inline fdt32_t cpu_to_fdt32(uint32_t x)
{ {
return (__force fdt32_t)CPU_TO_FDT32(x); return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x);
} }
static inline uint64_t fdt64_to_cpu(fdt64_t x) static inline uint64_t fdt64_to_cpu(fdt64_t x)
{ {
return (__force uint64_t)CPU_TO_FDT64(x); return (FDT_FORCE uint64_t)CPU_TO_FDT64(x);
} }
static inline fdt64_t cpu_to_fdt64(uint64_t x) static inline fdt64_t cpu_to_fdt64(uint64_t x)
{ {
return (__force fdt64_t)CPU_TO_FDT64(x); return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x);
} }
#undef CPU_TO_FDT64 #undef CPU_TO_FDT64
#undef CPU_TO_FDT32 #undef CPU_TO_FDT32
#undef CPU_TO_FDT16 #undef CPU_TO_FDT16
#undef EXTRACT_BYTE #undef EXTRACT_BYTE
#endif /* _LIBFDT_ENV_H */ #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 */
...@@ -21,7 +21,8 @@ LIBC_SRCS := $(addprefix lib/libc/, \ ...@@ -21,7 +21,8 @@ LIBC_SRCS := $(addprefix lib/libc/, \
strcmp.c \ strcmp.c \
strlen.c \ strlen.c \
strncmp.c \ strncmp.c \
strnlen.c) strnlen.c \
strrchr.c)
INCLUDES += -Iinclude/lib/libc \ INCLUDES += -Iinclude/lib/libc \
-Iinclude/lib/libc/$(ARCH) \ -Iinclude/lib/libc/$(ARCH) \
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stddef.h>
#include <string.h>
char *
strrchr(const char *p, int ch)
{
char *save;
char c;
c = ch;
for (save = NULL;; ++p) {
if (*p == c)
save = (char *)p;
if (*p == '\0')
return (save);
}
/* NOTREACHED */
}
...@@ -55,7 +55,12 @@ ...@@ -55,7 +55,12 @@
#include "libfdt_internal.h" #include "libfdt_internal.h"
int fdt_check_header(const void *fdt) /*
* Minimal sanity check for a read-only tree. fdt_ro_probe_() checks
* that the given buffer contains what appears to be a flattened
* device tree with sane information in its header.
*/
int fdt_ro_probe_(const void *fdt)
{ {
if (fdt_magic(fdt) == FDT_MAGIC) { if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */ /* Complete tree */
...@@ -74,6 +79,78 @@ int fdt_check_header(const void *fdt) ...@@ -74,6 +79,78 @@ int fdt_check_header(const void *fdt)
return 0; return 0;
} }
static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off)
{
return (off >= hdrsize) && (off <= totalsize);
}
static int check_block_(uint32_t hdrsize, uint32_t totalsize,
uint32_t base, uint32_t size)
{
if (!check_off_(hdrsize, totalsize, base))
return 0; /* block start out of bounds */
if ((base + size) < base)
return 0; /* overflow */
if (!check_off_(hdrsize, totalsize, base + size))
return 0; /* block end out of bounds */
return 1;
}
size_t fdt_header_size_(uint32_t version)
{
if (version <= 1)
return FDT_V1_SIZE;
else if (version <= 2)
return FDT_V2_SIZE;
else if (version <= 3)
return FDT_V3_SIZE;
else if (version <= 16)
return FDT_V16_SIZE;
else
return FDT_V17_SIZE;
}
int fdt_check_header(const void *fdt)
{
size_t hdrsize;
if (fdt_magic(fdt) != FDT_MAGIC)
return -FDT_ERR_BADMAGIC;
hdrsize = fdt_header_size(fdt);
if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
|| (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION))
return -FDT_ERR_BADVERSION;
if (fdt_version(fdt) < fdt_last_comp_version(fdt))
return -FDT_ERR_BADVERSION;
if ((fdt_totalsize(fdt) < hdrsize)
|| (fdt_totalsize(fdt) > INT_MAX))
return -FDT_ERR_TRUNCATED;
/* Bounds check memrsv block */
if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt)))
return -FDT_ERR_TRUNCATED;
/* Bounds check structure block */
if (fdt_version(fdt) < 17) {
if (!check_off_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
} else {
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_struct(fdt),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_TRUNCATED;
}
/* Bounds check strings block */
if (!check_block_(hdrsize, fdt_totalsize(fdt),
fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt)))
return -FDT_ERR_TRUNCATED;
return 0;
}
const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
{ {
unsigned absoffset = offset + fdt_off_dt_struct(fdt); unsigned absoffset = offset + fdt_off_dt_struct(fdt);
...@@ -88,7 +165,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) ...@@ -88,7 +165,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
|| ((offset + len) > fdt_size_dt_struct(fdt))) || ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL; return NULL;
return _fdt_offset_ptr(fdt, offset); return fdt_offset_ptr_(fdt, offset);
} }
uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
...@@ -123,6 +200,9 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) ...@@ -123,6 +200,9 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
/* skip-name offset, length and value */ /* skip-name offset, length and value */
offset += sizeof(struct fdt_property) - FDT_TAGSIZE offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+ fdt32_to_cpu(*lenp); + fdt32_to_cpu(*lenp);
if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 &&
((offset - fdt32_to_cpu(*lenp)) % 8) != 0)
offset += 4;
break; break;
case FDT_END: case FDT_END:
...@@ -141,7 +221,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) ...@@ -141,7 +221,7 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
return tag; return tag;
} }
int _fdt_check_node_offset(const void *fdt, int offset) int fdt_check_node_offset_(const void *fdt, int offset)
{ {
if ((offset < 0) || (offset % FDT_TAGSIZE) if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
...@@ -150,7 +230,7 @@ int _fdt_check_node_offset(const void *fdt, int offset) ...@@ -150,7 +230,7 @@ int _fdt_check_node_offset(const void *fdt, int offset)
return offset; return offset;
} }
int _fdt_check_prop_offset(const void *fdt, int offset) int fdt_check_prop_offset_(const void *fdt, int offset)
{ {
if ((offset < 0) || (offset % FDT_TAGSIZE) if ((offset < 0) || (offset % FDT_TAGSIZE)
|| (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
...@@ -165,7 +245,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth) ...@@ -165,7 +245,7 @@ int fdt_next_node(const void *fdt, int offset, int *depth)
uint32_t tag; uint32_t tag;
if (offset >= 0) if (offset >= 0)
if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0)
return nextoffset; return nextoffset;
do { do {
...@@ -227,7 +307,7 @@ int fdt_next_subnode(const void *fdt, int offset) ...@@ -227,7 +307,7 @@ int fdt_next_subnode(const void *fdt, int offset)
return offset; return offset;
} }
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) const char *fdt_find_string_(const char *strtab, int tabsize, const char *s)
{ {
int len = strlen(s) + 1; int len = strlen(s) + 1;
const char *last = strtab + tabsize - len; const char *last = strtab + tabsize - len;
...@@ -241,7 +321,7 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) ...@@ -241,7 +321,7 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
int fdt_move(const void *fdt, void *buf, int bufsize) int fdt_move(const void *fdt, void *buf, int bufsize)
{ {
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (fdt_totalsize(fdt) > bufsize) if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
......
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au> * Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
* Copyright (C) 2018 embedded brains GmbH
* *
* libfdt is dual licensed: you can use it either under the terms of * libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option. * the GPL, or the BSD license, at your option.
...@@ -55,42 +56,32 @@ ...@@ -55,42 +56,32 @@
#include "libfdt_internal.h" #include "libfdt_internal.h"
int fdt_address_cells(const void *fdt, int nodeoffset) static int fdt_cells(const void *fdt, int nodeoffset, const char *name)
{ {
const fdt32_t *ac; const fdt32_t *c;
int val; int val;
int len; int len;
ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); c = fdt_getprop(fdt, nodeoffset, name, &len);
if (!ac) if (!c)
return 2; return 2;
if (len != sizeof(*ac)) if (len != sizeof(*c))
return -FDT_ERR_BADNCELLS; return -FDT_ERR_BADNCELLS;
val = fdt32_to_cpu(*ac); val = fdt32_to_cpu(*c);
if ((val <= 0) || (val > FDT_MAX_NCELLS)) if ((val <= 0) || (val > FDT_MAX_NCELLS))
return -FDT_ERR_BADNCELLS; return -FDT_ERR_BADNCELLS;
return val; return val;
} }
int fdt_size_cells(const void *fdt, int nodeoffset) int fdt_address_cells(const void *fdt, int nodeoffset)
{ {
const fdt32_t *sc; return fdt_cells(fdt, nodeoffset, "#address-cells");
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; int fdt_size_cells(const void *fdt, int nodeoffset)
{
return fdt_cells(fdt, nodeoffset, "#size-cells");
} }
...@@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize) ...@@ -81,4 +81,3 @@ int fdt_create_empty_tree(void *buf, int bufsize)
return fdt_open_into(buf, buf, bufsize); return fdt_open_into(buf, buf, bufsize);
} }
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2016 Free Electrons
* Copyright (C) 2016 NextThing Co.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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_RO_PROBE(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_RO_PROBE(fdt);
FDT_RO_PROBE(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;
}
...@@ -55,12 +55,13 @@ ...@@ -55,12 +55,13 @@
#include "libfdt_internal.h" #include "libfdt_internal.h"
static int _fdt_nodename_eq(const void *fdt, int offset, static int fdt_nodename_eq_(const void *fdt, int offset,
const char *s, int len) const char *s, int len)
{ {
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); int olen;
const char *p = fdt_get_name(fdt, offset, &olen);
if (! p) if (!p || olen < len)
/* short match */ /* short match */
return 0; return 0;
...@@ -75,17 +76,72 @@ static int _fdt_nodename_eq(const void *fdt, int offset, ...@@ -75,17 +76,72 @@ static int _fdt_nodename_eq(const void *fdt, int offset,
return 0; return 0;
} }
const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
{
uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt);
size_t len;
int err;
const char *s, *n;
err = fdt_ro_probe_(fdt);
if (err != 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
if (absoffset >= fdt_totalsize(fdt))
goto fail;
len = fdt_totalsize(fdt) - absoffset;
if (fdt_magic(fdt) == FDT_MAGIC) {
if (stroffset < 0)
goto fail;
if (fdt_version(fdt) >= 17) {
if (stroffset >= fdt_size_dt_strings(fdt))
goto fail;
if ((fdt_size_dt_strings(fdt) - stroffset) < len)
len = fdt_size_dt_strings(fdt) - stroffset;
}
} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
if ((stroffset >= 0)
|| (stroffset < -fdt_size_dt_strings(fdt)))
goto fail;
if ((-stroffset) < len)
len = -stroffset;
} else {
err = -FDT_ERR_INTERNAL;
goto fail;
}
s = (const char *)fdt + absoffset;
n = memchr(s, '\0', len);
if (!n) {
/* missing terminating NULL */
err = -FDT_ERR_TRUNCATED;
goto fail;
}
if (lenp)
*lenp = n - s;
return s;
fail:
if (lenp)
*lenp = err;
return NULL;
}
const char *fdt_string(const void *fdt, int stroffset) const char *fdt_string(const void *fdt, int stroffset)
{ {
return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; return fdt_get_string(fdt, stroffset, NULL);
} }
static int _fdt_string_eq(const void *fdt, int stroffset, static int fdt_string_eq_(const void *fdt, int stroffset,
const char *s, int len) const char *s, int len)
{ {
const char *p = fdt_string(fdt, stroffset); int slen;
const char *p = fdt_get_string(fdt, stroffset, &slen);
return (strlen(p) == len) && (memcmp(p, s, len) == 0); return p && (slen == len) && (memcmp(p, s, len) == 0);
} }
uint32_t fdt_get_max_phandle(const void *fdt) uint32_t fdt_get_max_phandle(const void *fdt)
...@@ -114,24 +170,45 @@ uint32_t fdt_get_max_phandle(const void *fdt) ...@@ -114,24 +170,45 @@ uint32_t fdt_get_max_phandle(const void *fdt)
return 0; return 0;
} }
static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
{
int offset = n * sizeof(struct fdt_reserve_entry);
int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
if (absoffset < fdt_off_mem_rsvmap(fdt))
return NULL;
if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry))
return NULL;
return fdt_mem_rsv_(fdt, n);
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{ {
FDT_CHECK_HEADER(fdt); const struct fdt_reserve_entry *re;
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); FDT_RO_PROBE(fdt);
re = fdt_mem_rsv(fdt, n);
if (!re)
return -FDT_ERR_BADOFFSET;
*address = fdt64_ld(&re->address);
*size = fdt64_ld(&re->size);
return 0; return 0;
} }
int fdt_num_mem_rsv(const void *fdt) int fdt_num_mem_rsv(const void *fdt)
{ {
int i = 0; int i;
const struct fdt_reserve_entry *re;
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
i++; if (fdt64_ld(&re->size) == 0)
return i; return i;
}
return -FDT_ERR_TRUNCATED;
} }
static int _nextprop(const void *fdt, int offset) static int nextprop_(const void *fdt, int offset)
{ {
uint32_t tag; uint32_t tag;
int nextoffset; int nextoffset;
...@@ -160,13 +237,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, ...@@ -160,13 +237,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset,
{ {
int depth; int depth;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
for (depth = 0; for (depth = 0;
(offset >= 0) && (depth >= 0); (offset >= 0) && (depth >= 0);
offset = fdt_next_node(fdt, offset, &depth)) offset = fdt_next_node(fdt, offset, &depth))
if ((depth == 1) if ((depth == 1)
&& _fdt_nodename_eq(fdt, offset, name, namelen)) && fdt_nodename_eq_(fdt, offset, name, namelen))
return offset; return offset;
if (depth < 0) if (depth < 0)
...@@ -186,7 +263,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) ...@@ -186,7 +263,7 @@ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
const char *p = path; const char *p = path;
int offset = 0; int offset = 0;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* see if we have an alias */ /* see if we have an alias */
if (*path != '/') { if (*path != '/') {
...@@ -232,17 +309,35 @@ int fdt_path_offset(const void *fdt, const char *path) ...@@ -232,17 +309,35 @@ int fdt_path_offset(const void *fdt, const char *path)
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{ {
const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
const char *nameptr;
int err; int err;
if (((err = fdt_check_header(fdt)) != 0) if (((err = fdt_ro_probe_(fdt)) != 0)
|| ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
goto fail;
nameptr = nh->name;
if (fdt_version(fdt) < 0x10) {
/*
* For old FDT versions, match the naming conventions of V16:
* give only the leaf name (after all /). The actual tree
* contents are loosely checked.
*/
const char *leaf;
leaf = strrchr(nameptr, '/');
if (leaf == NULL) {
err = -FDT_ERR_BADSTRUCTURE;
goto fail; goto fail;
}
nameptr = leaf+1;
}
if (len) if (len)
*len = strlen(nh->name); *len = strlen(nameptr);
return nh->name; return nameptr;
fail: fail:
if (len) if (len)
...@@ -254,65 +349,105 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset) ...@@ -254,65 +349,105 @@ int fdt_first_property_offset(const void *fdt, int nodeoffset)
{ {
int offset; int offset;
if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return offset; return offset;
return _nextprop(fdt, offset); return nextprop_(fdt, offset);
} }
int fdt_next_property_offset(const void *fdt, int offset) int fdt_next_property_offset(const void *fdt, int offset)
{ {
if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
return offset; return offset;
return _nextprop(fdt, offset); return nextprop_(fdt, offset);
} }
const struct fdt_property *fdt_get_property_by_offset(const void *fdt, static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
int offset, int offset,
int *lenp) int *lenp)
{ {
int err; int err;
const struct fdt_property *prop; const struct fdt_property *prop;
if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
if (lenp) if (lenp)
*lenp = err; *lenp = err;
return NULL; return NULL;
} }
prop = _fdt_offset_ptr(fdt, offset); prop = fdt_offset_ptr_(fdt, offset);
if (lenp) if (lenp)
*lenp = fdt32_to_cpu(prop->len); *lenp = fdt32_ld(&prop->len);
return prop; return prop;
} }
const struct fdt_property *fdt_get_property_namelen(const void *fdt, const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
int offset,
int *lenp)
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
}
return fdt_get_property_by_offset_(fdt, offset, lenp);
}
static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
int offset, int offset,
const char *name, const char *name,
int namelen, int *lenp) int namelen,
int *lenp,
int *poffset)
{ {
for (offset = fdt_first_property_offset(fdt, offset); for (offset = fdt_first_property_offset(fdt, offset);
(offset >= 0); (offset >= 0);
(offset = fdt_next_property_offset(fdt, offset))) { (offset = fdt_next_property_offset(fdt, offset))) {
const struct fdt_property *prop; const struct fdt_property *prop;
if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
offset = -FDT_ERR_INTERNAL; offset = -FDT_ERR_INTERNAL;
break; break;
} }
if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff),
name, namelen)) name, namelen)) {
if (poffset)
*poffset = offset;
return prop; return prop;
} }
}
if (lenp) if (lenp)
*lenp = offset; *lenp = offset;
return NULL; return NULL;
} }
const struct fdt_property *fdt_get_property_namelen(const void *fdt,
int offset,
const char *name,
int namelen, int *lenp)
{
/* Prior to version 16, properties may need realignment
* and this API does not work. fdt_getprop_*() will, however. */
if (fdt_version(fdt) < 0x10) {
if (lenp)
*lenp = -FDT_ERR_BADVERSION;
return NULL;
}
return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
NULL);
}
const struct fdt_property *fdt_get_property(const void *fdt, const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset, int nodeoffset,
const char *name, int *lenp) const char *name, int *lenp)
...@@ -324,12 +459,18 @@ const struct fdt_property *fdt_get_property(const void *fdt, ...@@ -324,12 +459,18 @@ const struct fdt_property *fdt_get_property(const void *fdt,
const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
const char *name, int namelen, int *lenp) const char *name, int namelen, int *lenp)
{ {
int poffset;
const struct fdt_property *prop; const struct fdt_property *prop;
prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
if (! prop) &poffset);
if (!prop)
return NULL; return NULL;
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data; return prop->data;
} }
...@@ -338,11 +479,26 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, ...@@ -338,11 +479,26 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset,
{ {
const struct fdt_property *prop; const struct fdt_property *prop;
prop = fdt_get_property_by_offset(fdt, offset, lenp); prop = fdt_get_property_by_offset_(fdt, offset, lenp);
if (!prop) if (!prop)
return NULL; return NULL;
if (namep) if (namep) {
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); const char *name;
int namelen;
name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff),
&namelen);
if (!name) {
if (lenp)
*lenp = namelen;
return NULL;
}
*namep = name;
}
/* Handle realignment */
if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
fdt32_ld(&prop->len) >= 8)
return prop->data + 4;
return prop->data; return prop->data;
} }
...@@ -366,7 +522,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) ...@@ -366,7 +522,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
return 0; return 0;
} }
return fdt32_to_cpu(*php); return fdt32_ld(php);
} }
const char *fdt_get_alias_namelen(const void *fdt, const char *fdt_get_alias_namelen(const void *fdt,
...@@ -392,7 +548,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) ...@@ -392,7 +548,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
int offset, depth, namelen; int offset, depth, namelen;
const char *name; const char *name;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (buflen < 2) if (buflen < 2)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
...@@ -444,7 +600,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, ...@@ -444,7 +600,7 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int offset, depth; int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL; int supernodeoffset = -FDT_ERR_INTERNAL;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (supernodedepth < 0) if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND; return -FDT_ERR_NOTFOUND;
...@@ -503,7 +659,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, ...@@ -503,7 +659,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const void *val; const void *val;
int len; int len;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't * property of a node in fdt_getprop(), then if that didn't
...@@ -529,7 +685,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) ...@@ -529,7 +685,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
if ((phandle == 0) || (phandle == -1)) if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE; return -FDT_ERR_BADPHANDLE;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we /* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in * potentially scan each property of a node in
...@@ -571,7 +727,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) ...@@ -571,7 +727,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
list = fdt_getprop(fdt, nodeoffset, property, &length); list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list) if (!list)
return -length; return length;
end = list + length; end = list + length;
...@@ -597,7 +753,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, ...@@ -597,7 +753,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
list = fdt_getprop(fdt, nodeoffset, property, &length); list = fdt_getprop(fdt, nodeoffset, property, &length);
if (!list) if (!list)
return -length; return length;
len = strlen(string) + 1; len = strlen(string) + 1;
end = list + length; end = list + length;
...@@ -682,7 +838,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, ...@@ -682,7 +838,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
{ {
int offset, err; int offset, err;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each /* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if * property of a node in fdt_node_check_compatible(), then if
...@@ -701,3 +857,66 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, ...@@ -701,3 +857,66 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
return offset; /* error from fdt_next_node() */ return offset; /* error from fdt_next_node() */
} }
int fdt_check_full(const void *fdt, size_t bufsize)
{
int err;
int num_memrsv;
int offset, nextoffset = 0;
uint32_t tag;
unsigned depth = 0;
const void *prop;
const char *propname;
if (bufsize < FDT_V1_SIZE)
return -FDT_ERR_TRUNCATED;
err = fdt_check_header(fdt);
if (err != 0)
return err;
if (bufsize < fdt_totalsize(fdt))
return -FDT_ERR_TRUNCATED;
num_memrsv = fdt_num_mem_rsv(fdt);
if (num_memrsv < 0)
return num_memrsv;
while (1) {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
if (nextoffset < 0)
return nextoffset;
switch (tag) {
case FDT_NOP:
break;
case FDT_END:
if (depth != 0)
return -FDT_ERR_BADSTRUCTURE;
return 0;
case FDT_BEGIN_NODE:
depth++;
if (depth > INT_MAX)
return -FDT_ERR_BADSTRUCTURE;
break;
case FDT_END_NODE:
if (depth == 0)
return -FDT_ERR_BADSTRUCTURE;
depth--;
break;
case FDT_PROP:
prop = fdt_getprop_by_offset(fdt, offset, &propname,
&err);
if (!prop)
return err;
break;
default:
return -FDT_ERR_INTERNAL;
}
}
}
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
#include "libfdt_internal.h" #include "libfdt_internal.h"
static int _fdt_blocks_misordered(const void *fdt, static int fdt_blocks_misordered_(const void *fdt,
int mem_rsv_size, int struct_size) int mem_rsv_size, int struct_size)
{ {
return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
...@@ -67,13 +67,13 @@ static int _fdt_blocks_misordered(const void *fdt, ...@@ -67,13 +67,13 @@ static int _fdt_blocks_misordered(const void *fdt,
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
} }
static int _fdt_rw_check_header(void *fdt) static int fdt_rw_probe_(void *fdt)
{ {
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
if (fdt_version(fdt) < 17) if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION; return -FDT_ERR_BADVERSION;
if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt))) fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT; return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17) if (fdt_version(fdt) > 17)
...@@ -82,22 +82,22 @@ static int _fdt_rw_check_header(void *fdt) ...@@ -82,22 +82,22 @@ static int _fdt_rw_check_header(void *fdt)
return 0; return 0;
} }
#define FDT_RW_CHECK_HEADER(fdt) \ #define FDT_RW_PROBE(fdt) \
{ \ { \
int __err; \ int err_; \
if ((__err = _fdt_rw_check_header(fdt)) != 0) \ if ((err_ = fdt_rw_probe_(fdt)) != 0) \
return __err; \ return err_; \
} }
static inline int _fdt_data_size(void *fdt) static inline int fdt_data_size_(void *fdt)
{ {
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
} }
static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen)
{ {
char *p = splicepoint; char *p = splicepoint;
char *end = (char *)fdt + _fdt_data_size(fdt); char *end = (char *)fdt + fdt_data_size_(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end)) if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET; return -FDT_ERR_BADOFFSET;
...@@ -109,12 +109,12 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) ...@@ -109,12 +109,12 @@ static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
return 0; return 0;
} }
static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p,
int oldn, int newn) int oldn, int newn)
{ {
int delta = (newn - oldn) * sizeof(*p); int delta = (newn - oldn) * sizeof(*p);
int err; int err;
err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err) if (err)
return err; return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
...@@ -122,13 +122,13 @@ static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, ...@@ -122,13 +122,13 @@ static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
return 0; return 0;
} }
static int _fdt_splice_struct(void *fdt, void *p, static int fdt_splice_struct_(void *fdt, void *p,
int oldlen, int newlen) int oldlen, int newlen)
{ {
int delta = newlen - oldlen; int delta = newlen - oldlen;
int err; int err;
if ((err = _fdt_splice(fdt, p, oldlen, newlen))) if ((err = fdt_splice_(fdt, p, oldlen, newlen)))
return err; return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
...@@ -136,20 +136,20 @@ static int _fdt_splice_struct(void *fdt, void *p, ...@@ -136,20 +136,20 @@ static int _fdt_splice_struct(void *fdt, void *p,
return 0; return 0;
} }
static int _fdt_splice_string(void *fdt, int newlen) static int fdt_splice_string_(void *fdt, int newlen)
{ {
void *p = (char *)fdt void *p = (char *)fdt
+ fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err; int err;
if ((err = _fdt_splice(fdt, p, 0, newlen))) if ((err = fdt_splice_(fdt, p, 0, newlen)))
return err; return err;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0; return 0;
} }
static int _fdt_find_add_string(void *fdt, const char *s) static int fdt_find_add_string_(void *fdt, const char *s)
{ {
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p; const char *p;
...@@ -157,13 +157,13 @@ static int _fdt_find_add_string(void *fdt, const char *s) ...@@ -157,13 +157,13 @@ static int _fdt_find_add_string(void *fdt, const char *s)
int len = strlen(s) + 1; int len = strlen(s) + 1;
int err; int err;
p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s);
if (p) if (p)
/* found it */ /* found it */
return (p - strtab); return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt); new = strtab + fdt_size_dt_strings(fdt);
err = _fdt_splice_string(fdt, len); err = fdt_splice_string_(fdt, len);
if (err) if (err)
return err; return err;
...@@ -176,10 +176,10 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) ...@@ -176,10 +176,10 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
struct fdt_reserve_entry *re; struct fdt_reserve_entry *re;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt));
err = _fdt_splice_mem_rsv(fdt, re, 0, 1); err = fdt_splice_mem_rsv_(fdt, re, 0, 1);
if (err) if (err)
return err; return err;
...@@ -190,27 +190,27 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) ...@@ -190,27 +190,27 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
int fdt_del_mem_rsv(void *fdt, int n) int fdt_del_mem_rsv(void *fdt, int n)
{ {
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n);
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
if (n >= fdt_num_mem_rsv(fdt)) if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND; return -FDT_ERR_NOTFOUND;
return _fdt_splice_mem_rsv(fdt, re, 1, 0); return fdt_splice_mem_rsv_(fdt, re, 1, 0);
} }
static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop) int len, struct fdt_property **prop)
{ {
int oldlen; int oldlen;
int err; int err;
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (! (*prop)) if (!*prop)
return oldlen; return oldlen;
if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(len)))) FDT_TAGALIGN(len))))
return err; return err;
...@@ -218,7 +218,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, ...@@ -218,7 +218,7 @@ static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
return 0; return 0;
} }
static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
int len, struct fdt_property **prop) int len, struct fdt_property **prop)
{ {
int proplen; int proplen;
...@@ -226,17 +226,17 @@ static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, ...@@ -226,17 +226,17 @@ static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
int namestroff; int namestroff;
int err; int err;
if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
return nextoffset; return nextoffset;
namestroff = _fdt_find_add_string(fdt, name); namestroff = fdt_find_add_string_(fdt, name);
if (namestroff < 0) if (namestroff < 0)
return namestroff; return namestroff;
*prop = _fdt_offset_ptr_w(fdt, nextoffset); *prop = fdt_offset_ptr_w_(fdt, nextoffset);
proplen = sizeof(**prop) + FDT_TAGALIGN(len); proplen = sizeof(**prop) + FDT_TAGALIGN(len);
err = _fdt_splice_struct(fdt, *prop, 0, proplen); err = fdt_splice_struct_(fdt, *prop, 0, proplen);
if (err) if (err)
return err; return err;
...@@ -252,7 +252,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) ...@@ -252,7 +252,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
int oldlen, newlen; int oldlen, newlen;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep) if (!namep)
...@@ -260,7 +260,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) ...@@ -260,7 +260,7 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
newlen = strlen(name); newlen = strlen(name);
err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1),
FDT_TAGALIGN(newlen+1)); FDT_TAGALIGN(newlen+1));
if (err) if (err)
return err; return err;
...@@ -269,21 +269,36 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name) ...@@ -269,21 +269,36 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name)
return 0; return 0;
} }
int fdt_setprop(void *fdt, int nodeoffset, const char *name, int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name,
const void *val, int len) int len, void **prop_data)
{ {
struct fdt_property *prop; struct fdt_property *prop;
int err; int err;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND) if (err == -FDT_ERR_NOTFOUND)
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err) if (err)
return err; return err;
memcpy(prop->data, val, len); *prop_data = prop->data;
return 0;
}
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
void *prop_data;
int err;
err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data);
if (err)
return err;
if (len)
memcpy(prop_data, val, len);
return 0; return 0;
} }
...@@ -293,12 +308,12 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, ...@@ -293,12 +308,12 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
struct fdt_property *prop; struct fdt_property *prop;
int err, oldlen, newlen; int err, oldlen, newlen;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (prop) { if (prop) {
newlen = len + oldlen; newlen = len + oldlen;
err = _fdt_splice_struct(fdt, prop->data, err = fdt_splice_struct_(fdt, prop->data,
FDT_TAGALIGN(oldlen), FDT_TAGALIGN(oldlen),
FDT_TAGALIGN(newlen)); FDT_TAGALIGN(newlen));
if (err) if (err)
...@@ -306,7 +321,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, ...@@ -306,7 +321,7 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
prop->len = cpu_to_fdt32(newlen); prop->len = cpu_to_fdt32(newlen);
memcpy(prop->data + oldlen, val, len); memcpy(prop->data + oldlen, val, len);
} else { } else {
err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); err = fdt_add_property_(fdt, nodeoffset, name, len, &prop);
if (err) if (err)
return err; return err;
memcpy(prop->data, val, len); memcpy(prop->data, val, len);
...@@ -319,14 +334,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name) ...@@ -319,14 +334,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
struct fdt_property *prop; struct fdt_property *prop;
int len, proplen; int len, proplen;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len); prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop) if (!prop)
return len; return len;
proplen = sizeof(*prop) + FDT_TAGALIGN(len); proplen = sizeof(*prop) + FDT_TAGALIGN(len);
return _fdt_splice_struct(fdt, prop, proplen, 0); return fdt_splice_struct_(fdt, prop, proplen, 0);
} }
int fdt_add_subnode_namelen(void *fdt, int parentoffset, int fdt_add_subnode_namelen(void *fdt, int parentoffset,
...@@ -339,7 +354,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, ...@@ -339,7 +354,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
uint32_t tag; uint32_t tag;
fdt32_t *endtag; fdt32_t *endtag;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0) if (offset >= 0)
...@@ -354,10 +369,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, ...@@ -354,10 +369,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
tag = fdt_next_tag(fdt, offset, &nextoffset); tag = fdt_next_tag(fdt, offset, &nextoffset);
} while ((tag == FDT_PROP) || (tag == FDT_NOP)); } while ((tag == FDT_PROP) || (tag == FDT_NOP));
nh = _fdt_offset_ptr_w(fdt, offset); nh = fdt_offset_ptr_w_(fdt, offset);
nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
err = _fdt_splice_struct(fdt, nh, 0, nodelen); err = fdt_splice_struct_(fdt, nh, 0, nodelen);
if (err) if (err)
return err; return err;
...@@ -379,17 +394,17 @@ int fdt_del_node(void *fdt, int nodeoffset) ...@@ -379,17 +394,17 @@ int fdt_del_node(void *fdt, int nodeoffset)
{ {
int endoffset; int endoffset;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
endoffset = _fdt_node_end_offset(fdt, nodeoffset); endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0) if (endoffset < 0)
return endoffset; return endoffset;
return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset),
endoffset - nodeoffset, 0); endoffset - nodeoffset, 0);
} }
static void _fdt_packblocks(const char *old, char *new, static void fdt_packblocks_(const char *old, char *new,
int mem_rsv_size, int struct_size) int mem_rsv_size, int struct_size)
{ {
int mem_rsv_off, struct_off, strings_off; int mem_rsv_off, struct_off, strings_off;
...@@ -420,7 +435,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) ...@@ -420,7 +435,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
const char *fdtend = fdtstart + fdt_totalsize(fdt); const char *fdtend = fdtstart + fdt_totalsize(fdt);
char *tmp; char *tmp;
FDT_CHECK_HEADER(fdt); FDT_RO_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry); * sizeof(struct fdt_reserve_entry);
...@@ -435,7 +450,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) ...@@ -435,7 +450,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return struct_size; return struct_size;
} }
if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */ /* no further work necessary */
err = fdt_move(fdt, buf, bufsize); err = fdt_move(fdt, buf, bufsize);
if (err) if (err)
...@@ -463,7 +478,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) ...@@ -463,7 +478,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
} }
_fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize); memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC); fdt_set_magic(buf, FDT_MAGIC);
...@@ -479,12 +494,12 @@ int fdt_pack(void *fdt) ...@@ -479,12 +494,12 @@ int fdt_pack(void *fdt)
{ {
int mem_rsv_size; int mem_rsv_size;
FDT_RW_CHECK_HEADER(fdt); FDT_RW_PROBE(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry); * sizeof(struct fdt_reserve_entry);
_fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, _fdt_data_size(fdt)); fdt_set_totalsize(fdt, fdt_data_size_(fdt));
return 0; return 0;
} }
...@@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = { ...@@ -69,6 +69,7 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADOFFSET),
FDT_ERRTABENT(FDT_ERR_BADPATH), FDT_ERRTABENT(FDT_ERR_BADPATH),
FDT_ERRTABENT(FDT_ERR_BADPHANDLE),
FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_BADSTATE),
FDT_ERRTABENT(FDT_ERR_TRUNCATED), FDT_ERRTABENT(FDT_ERR_TRUNCATED),
...@@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = { ...@@ -76,6 +77,11 @@ static struct fdt_errtabent fdt_errtable[] = {
FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADVERSION),
FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
FDT_ERRTABENT(FDT_ERR_BADLAYOUT), 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])) #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
......
...@@ -55,22 +55,78 @@ ...@@ -55,22 +55,78 @@
#include "libfdt_internal.h" #include "libfdt_internal.h"
static int _fdt_sw_check_header(void *fdt) static int fdt_sw_probe_(void *fdt)
{ {
if (fdt_magic(fdt) != FDT_SW_MAGIC) if (fdt_magic(fdt) == FDT_MAGIC)
return -FDT_ERR_BADSTATE;
else if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC; return -FDT_ERR_BADMAGIC;
/* FIXME: should check more details about the header state */
return 0; return 0;
} }
#define FDT_SW_CHECK_HEADER(fdt) \ #define FDT_SW_PROBE(fdt) \
{ \ { \
int err; \ int err; \
if ((err = _fdt_sw_check_header(fdt)) != 0) \ if ((err = fdt_sw_probe_(fdt)) != 0) \
return err; \ return err; \
} }
static void *_fdt_grab_space(void *fdt, size_t len) /* 'memrsv' state: Initial state after fdt_create()
*
* Allowed functions:
* fdt_add_reservmap_entry()
* fdt_finish_reservemap() [moves to 'struct' state]
*/
static int fdt_sw_probe_memrsv_(void *fdt)
{
int err = fdt_sw_probe_(fdt);
if (err)
return err;
if (fdt_off_dt_strings(fdt) != 0)
return -FDT_ERR_BADSTATE;
return 0;
}
#define FDT_SW_PROBE_MEMRSV(fdt) \
{ \
int err; \
if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
return err; \
}
/* 'struct' state: Enter this state after fdt_finish_reservemap()
*
* Allowed functions:
* fdt_begin_node()
* fdt_end_node()
* fdt_property*()
* fdt_finish() [moves to 'complete' state]
*/
static int fdt_sw_probe_struct_(void *fdt)
{
int err = fdt_sw_probe_(fdt);
if (err)
return err;
if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
return -FDT_ERR_BADSTATE;
return 0;
}
#define FDT_SW_PROBE_STRUCT(fdt) \
{ \
int err; \
if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
return err; \
}
/* 'complete' state: Enter this state after fdt_finish()
*
* Allowed functions: none
*/
static void *fdt_grab_space_(void *fdt, size_t len)
{ {
int offset = fdt_size_dt_struct(fdt); int offset = fdt_size_dt_struct(fdt);
int spaceleft; int spaceleft;
...@@ -82,14 +138,16 @@ static void *_fdt_grab_space(void *fdt, size_t len) ...@@ -82,14 +138,16 @@ static void *_fdt_grab_space(void *fdt, size_t len)
return NULL; return NULL;
fdt_set_size_dt_struct(fdt, offset + len); fdt_set_size_dt_struct(fdt, offset + len);
return _fdt_offset_ptr_w(fdt, offset); return fdt_offset_ptr_w_(fdt, offset);
} }
int fdt_create(void *buf, int bufsize) int fdt_create(void *buf, int bufsize)
{ {
const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry));
void *fdt = buf; void *fdt = buf;
if (bufsize < sizeof(struct fdt_header)) if (bufsize < hdrsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
memset(buf, 0, bufsize); memset(buf, 0, bufsize);
...@@ -99,10 +157,9 @@ int fdt_create(void *buf, int bufsize) ...@@ -99,10 +157,9 @@ int fdt_create(void *buf, int bufsize)
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_totalsize(fdt, bufsize); fdt_set_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), fdt_set_off_mem_rsvmap(fdt, hdrsize);
sizeof(struct fdt_reserve_entry)));
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
fdt_set_off_dt_strings(fdt, bufsize); fdt_set_off_dt_strings(fdt, 0);
return 0; return 0;
} }
...@@ -112,11 +169,14 @@ int fdt_resize(void *fdt, void *buf, int bufsize) ...@@ -112,11 +169,14 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
size_t headsize, tailsize; size_t headsize, tailsize;
char *oldtail, *newtail; char *oldtail, *newtail;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE(fdt);
headsize = fdt_off_dt_struct(fdt); headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
tailsize = fdt_size_dt_strings(fdt); tailsize = fdt_size_dt_strings(fdt);
if ((headsize + tailsize) > fdt_totalsize(fdt))
return -FDT_ERR_INTERNAL;
if ((headsize + tailsize) > bufsize) if ((headsize + tailsize) > bufsize)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
...@@ -133,8 +193,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize) ...@@ -133,8 +193,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
memmove(buf, fdt, headsize); memmove(buf, fdt, headsize);
} }
fdt_set_off_dt_strings(buf, bufsize);
fdt_set_totalsize(buf, bufsize); fdt_set_totalsize(buf, bufsize);
if (fdt_off_dt_strings(buf))
fdt_set_off_dt_strings(buf, bufsize);
return 0; return 0;
} }
...@@ -144,10 +205,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) ...@@ -144,10 +205,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
struct fdt_reserve_entry *re; struct fdt_reserve_entry *re;
int offset; int offset;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_MEMRSV(fdt);
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
offset = fdt_off_dt_struct(fdt); offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
...@@ -164,17 +222,24 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) ...@@ -164,17 +222,24 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
int fdt_finish_reservemap(void *fdt) int fdt_finish_reservemap(void *fdt)
{ {
return fdt_add_reservemap_entry(fdt, 0, 0); int err = fdt_add_reservemap_entry(fdt, 0, 0);
if (err)
return err;
fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
return 0;
} }
int fdt_begin_node(void *fdt, const char *name) int fdt_begin_node(void *fdt, const char *name)
{ {
struct fdt_node_header *nh; struct fdt_node_header *nh;
int namelen = strlen(name) + 1; int namelen;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); namelen = strlen(name) + 1;
nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh) if (! nh)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
...@@ -187,9 +252,9 @@ int fdt_end_node(void *fdt) ...@@ -187,9 +252,9 @@ int fdt_end_node(void *fdt)
{ {
fdt32_t *en; fdt32_t *en;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
en = _fdt_grab_space(fdt, FDT_TAGSIZE); en = fdt_grab_space_(fdt, FDT_TAGSIZE);
if (! en) if (! en)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
...@@ -197,7 +262,7 @@ int fdt_end_node(void *fdt) ...@@ -197,7 +262,7 @@ int fdt_end_node(void *fdt)
return 0; return 0;
} }
static int _fdt_find_add_string(void *fdt, const char *s) static int fdt_find_add_string_(void *fdt, const char *s)
{ {
char *strtab = (char *)fdt + fdt_totalsize(fdt); char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p; const char *p;
...@@ -205,7 +270,7 @@ static int _fdt_find_add_string(void *fdt, const char *s) ...@@ -205,7 +270,7 @@ static int _fdt_find_add_string(void *fdt, const char *s)
int len = strlen(s) + 1; int len = strlen(s) + 1;
int struct_top, offset; int struct_top, offset;
p = _fdt_find_string(strtab - strtabsize, strtabsize, s); p = fdt_find_string_(strtab - strtabsize, strtabsize, s);
if (p) if (p)
return p - strtab; return p - strtab;
...@@ -220,25 +285,37 @@ static int _fdt_find_add_string(void *fdt, const char *s) ...@@ -220,25 +285,37 @@ static int _fdt_find_add_string(void *fdt, const char *s)
return offset; return offset;
} }
int fdt_property(void *fdt, const char *name, const void *val, int len) int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp)
{ {
struct fdt_property *prop; struct fdt_property *prop;
int nameoff; int nameoff;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
nameoff = _fdt_find_add_string(fdt, name); nameoff = fdt_find_add_string_(fdt, name);
if (nameoff == 0) if (nameoff == 0)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop) if (! prop)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
prop->tag = cpu_to_fdt32(FDT_PROP); prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff); prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len); prop->len = cpu_to_fdt32(len);
memcpy(prop->data, val, 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; return 0;
} }
...@@ -250,10 +327,10 @@ int fdt_finish(void *fdt) ...@@ -250,10 +327,10 @@ int fdt_finish(void *fdt)
uint32_t tag; uint32_t tag;
int offset, nextoffset; int offset, nextoffset;
FDT_SW_CHECK_HEADER(fdt); FDT_SW_PROBE_STRUCT(fdt);
/* Add terminator */ /* Add terminator */
end = _fdt_grab_space(fdt, sizeof(*end)); end = fdt_grab_space_(fdt, sizeof(*end));
if (! end) if (! end)
return -FDT_ERR_NOSPACE; return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END); *end = cpu_to_fdt32(FDT_END);
...@@ -269,7 +346,7 @@ int fdt_finish(void *fdt) ...@@ -269,7 +346,7 @@ int fdt_finish(void *fdt)
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) { if (tag == FDT_PROP) {
struct fdt_property *prop = struct fdt_property *prop =
_fdt_offset_ptr_w(fdt, offset); fdt_offset_ptr_w_(fdt, offset);
int nameoff; int nameoff;
nameoff = fdt32_to_cpu(prop->nameoff); nameoff = fdt32_to_cpu(prop->nameoff);
......
...@@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, ...@@ -82,7 +82,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
int proplen; int proplen;
propval = fdt_getprop(fdt, nodeoffset, name, &proplen); propval = fdt_getprop(fdt, nodeoffset, name, &proplen);
if (! propval) if (!propval)
return proplen; return proplen;
if (proplen != len) if (proplen != len)
...@@ -93,7 +93,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, ...@@ -93,7 +93,7 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
val, len); val, len);
} }
static void _fdt_nop_region(void *start, int len) static void fdt_nop_region_(void *start, int len)
{ {
fdt32_t *p; fdt32_t *p;
...@@ -107,15 +107,15 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name) ...@@ -107,15 +107,15 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
int len; int len;
prop = fdt_get_property_w(fdt, nodeoffset, name, &len); prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop) if (!prop)
return len; return len;
_fdt_nop_region(prop, len + sizeof(*prop)); fdt_nop_region_(prop, len + sizeof(*prop));
return 0; return 0;
} }
int _fdt_node_end_offset(void *fdt, int offset) int fdt_node_end_offset_(void *fdt, int offset)
{ {
int depth = 0; int depth = 0;
...@@ -129,11 +129,11 @@ int fdt_nop_node(void *fdt, int nodeoffset) ...@@ -129,11 +129,11 @@ int fdt_nop_node(void *fdt, int nodeoffset)
{ {
int endoffset; int endoffset;
endoffset = _fdt_node_end_offset(fdt, nodeoffset); endoffset = fdt_node_end_offset_(fdt, nodeoffset);
if (endoffset < 0) if (endoffset < 0)
return endoffset; return endoffset;
_fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0),
endoffset - nodeoffset); endoffset - nodeoffset);
return 0; return 0;
} }
#ifndef _LIBFDT_INTERNAL_H #ifndef LIBFDT_INTERNAL_H
#define _LIBFDT_INTERNAL_H #define LIBFDT_INTERNAL_H
/* /*
* libfdt - Flat Device Tree manipulation * libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright (C) 2006 David Gibson, IBM Corporation.
...@@ -55,29 +55,30 @@ ...@@ -55,29 +55,30 @@
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
#define FDT_CHECK_HEADER(fdt) \ int fdt_ro_probe_(const void *fdt);
#define FDT_RO_PROBE(fdt) \
{ \ { \
int __err; \ int err_; \
if ((__err = fdt_check_header(fdt)) != 0) \ if ((err_ = fdt_ro_probe_(fdt)) != 0) \
return __err; \ return err_; \
} }
int _fdt_check_node_offset(const void *fdt, int offset); int fdt_check_node_offset_(const void *fdt, int offset);
int _fdt_check_prop_offset(const void *fdt, int offset); int fdt_check_prop_offset_(const void *fdt, int offset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); const char *fdt_find_string_(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset); int fdt_node_end_offset_(void *fdt, int nodeoffset);
static inline const void *_fdt_offset_ptr(const void *fdt, int offset) static inline const void *fdt_offset_ptr_(const void *fdt, int offset)
{ {
return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
} }
static inline void *_fdt_offset_ptr_w(void *fdt, int offset) static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
{ {
return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
} }
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
{ {
const struct fdt_reserve_entry *rsv_table = const struct fdt_reserve_entry *rsv_table =
(const struct fdt_reserve_entry *) (const struct fdt_reserve_entry *)
...@@ -85,11 +86,11 @@ static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int ...@@ -85,11 +86,11 @@ static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int
return rsv_table + n; return rsv_table + n;
} }
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n)
{ {
return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n);
} }
#define FDT_SW_MAGIC (~FDT_MAGIC) #define FDT_SW_MAGIC (~FDT_MAGIC)
#endif /* _LIBFDT_INTERNAL_H */ #endif /* LIBFDT_INTERNAL_H */
...@@ -142,7 +142,7 @@ ...@@ -142,7 +142,7 @@
# define PLAT_ARM_MAX_BL2_SIZE 0x1C000 # define PLAT_ARM_MAX_BL2_SIZE 0x1C000
#endif #endif
#else #else
# define PLAT_ARM_MAX_BL2_SIZE 0xE000 # define PLAT_ARM_MAX_BL2_SIZE 0xF000
#endif #endif
/* /*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment