2007-12-10 14:28:39 +11:00
/*
* libfdt - Flat Device Tree manipulation
* Copyright ( C ) 2006 David Gibson , IBM Corporation .
*
* 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"
int fdt_check_header ( const void * fdt )
{
if ( fdt_magic ( fdt ) = = FDT_MAGIC ) {
/* Complete tree */
if ( fdt_version ( fdt ) < FDT_FIRST_SUPPORTED_VERSION )
return - FDT_ERR_BADVERSION ;
if ( fdt_last_comp_version ( fdt ) > FDT_LAST_SUPPORTED_VERSION )
return - FDT_ERR_BADVERSION ;
2008-08-07 12:24:17 +10:00
} else if ( fdt_magic ( fdt ) = = FDT_SW_MAGIC ) {
2007-12-10 14:28:39 +11:00
/* Unfinished sequential-write blob */
if ( fdt_size_dt_struct ( fdt ) = = 0 )
return - FDT_ERR_BADSTATE ;
} else {
return - FDT_ERR_BADMAGIC ;
}
return 0 ;
}
2012-09-28 21:25:59 +00:00
const void * fdt_offset_ptr ( const void * fdt , int offset , unsigned int len )
2007-12-10 14:28:39 +11:00
{
2008-08-07 12:24:17 +10:00
const char * p ;
2007-12-10 14:28:39 +11:00
if ( fdt_version ( fdt ) > = 0x11 )
if ( ( ( offset + len ) < offset )
| | ( ( offset + len ) > fdt_size_dt_struct ( fdt ) ) )
return NULL ;
p = _fdt_offset_ptr ( fdt , offset ) ;
if ( p + len < p )
return NULL ;
return p ;
}
2012-09-28 21:25:59 +00:00
uint32_t fdt_next_tag ( const void * fdt , int startoffset , int * nextoffset )
2007-12-10 14:28:39 +11:00
{
2015-04-29 16:00:05 -05:00
const fdt32_t * tagp , * lenp ;
2007-12-10 14:28:39 +11:00
uint32_t tag ;
2012-09-28 21:25:59 +00:00
int offset = startoffset ;
2007-12-10 14:28:39 +11:00
const char * p ;
2012-09-28 21:25:59 +00:00
* nextoffset = - FDT_ERR_TRUNCATED ;
2007-12-10 14:28:39 +11:00
tagp = fdt_offset_ptr ( fdt , offset , FDT_TAGSIZE ) ;
2012-09-28 21:25:59 +00:00
if ( ! tagp )
2007-12-10 14:28:39 +11:00
return FDT_END ; /* premature end */
tag = fdt32_to_cpu ( * tagp ) ;
offset + = FDT_TAGSIZE ;
2012-09-28 21:25:59 +00:00
* nextoffset = - FDT_ERR_BADSTRUCTURE ;
2007-12-10 14:28:39 +11:00
switch ( tag ) {
case FDT_BEGIN_NODE :
/* skip name */
do {
p = fdt_offset_ptr ( fdt , offset + + , 1 ) ;
} while ( p & & ( * p ! = ' \0 ' ) ) ;
2012-09-28 21:25:59 +00:00
if ( ! p )
return FDT_END ; /* premature end */
2007-12-10 14:28:39 +11:00
break ;
2012-09-28 21:25:59 +00:00
2007-12-10 14:28:39 +11:00
case FDT_PROP :
lenp = fdt_offset_ptr ( fdt , offset , sizeof ( * lenp ) ) ;
2012-09-28 21:25:59 +00:00
if ( ! lenp )
return FDT_END ; /* premature end */
/* skip-name offset, length and value */
offset + = sizeof ( struct fdt_property ) - FDT_TAGSIZE
+ fdt32_to_cpu ( * lenp ) ;
break ;
case FDT_END :
case FDT_END_NODE :
case FDT_NOP :
2007-12-10 14:28:39 +11:00
break ;
2012-09-28 21:25:59 +00:00
default :
return FDT_END ;
2007-12-10 14:28:39 +11:00
}
2012-09-28 21:25:59 +00:00
if ( ! fdt_offset_ptr ( fdt , startoffset , offset - startoffset ) )
return FDT_END ; /* premature end */
2007-12-10 14:28:39 +11:00
2012-09-28 21:25:59 +00:00
* nextoffset = FDT_TAGALIGN ( offset ) ;
2007-12-10 14:28:39 +11:00
return tag ;
}
2008-08-07 12:24:17 +10:00
int _fdt_check_node_offset ( const void * fdt , int offset )
{
if ( ( offset < 0 ) | | ( offset % FDT_TAGSIZE )
| | ( fdt_next_tag ( fdt , offset , & offset ) ! = FDT_BEGIN_NODE ) )
return - FDT_ERR_BADOFFSET ;
return offset ;
}
2012-09-28 21:25:59 +00:00
int _fdt_check_prop_offset ( const void * fdt , int offset )
{
if ( ( offset < 0 ) | | ( offset % FDT_TAGSIZE )
| | ( fdt_next_tag ( fdt , offset , & offset ) ! = FDT_PROP ) )
return - FDT_ERR_BADOFFSET ;
return offset ;
}
2008-08-07 12:24:17 +10:00
int fdt_next_node ( const void * fdt , int offset , int * depth )
{
int nextoffset = 0 ;
uint32_t tag ;
if ( offset > = 0 )
if ( ( nextoffset = _fdt_check_node_offset ( fdt , offset ) ) < 0 )
return nextoffset ;
do {
offset = nextoffset ;
tag = fdt_next_tag ( fdt , offset , & nextoffset ) ;
switch ( tag ) {
case FDT_PROP :
case FDT_NOP :
break ;
case FDT_BEGIN_NODE :
if ( depth )
( * depth ) + + ;
break ;
case FDT_END_NODE :
2012-09-28 21:25:59 +00:00
if ( depth & & ( ( - - ( * depth ) ) < 0 ) )
return nextoffset ;
2008-08-07 12:24:17 +10:00
break ;
case FDT_END :
2012-09-28 21:25:59 +00:00
if ( ( nextoffset > = 0 )
| | ( ( nextoffset = = - FDT_ERR_TRUNCATED ) & & ! depth ) )
return - FDT_ERR_NOTFOUND ;
else
return nextoffset ;
2008-08-07 12:24:17 +10:00
}
} while ( tag ! = FDT_BEGIN_NODE ) ;
return offset ;
}
2015-04-29 16:00:05 -05:00
int fdt_first_subnode ( const void * fdt , int offset )
{
int depth = 0 ;
offset = fdt_next_node ( fdt , offset , & depth ) ;
if ( offset < 0 | | depth ! = 1 )
return - FDT_ERR_NOTFOUND ;
return offset ;
}
int fdt_next_subnode ( const void * fdt , int offset )
{
int depth = 1 ;
/*
* With respect to the parent , the depth of the next subnode will be
* the same as the last .
*/
do {
offset = fdt_next_node ( fdt , offset , & depth ) ;
if ( offset < 0 | | depth < 1 )
return - FDT_ERR_NOTFOUND ;
} while ( depth > 1 ) ;
return offset ;
}
2007-12-10 14:28:39 +11:00
const char * _fdt_find_string ( const char * strtab , int tabsize , const char * s )
{
int len = strlen ( s ) + 1 ;
const char * last = strtab + tabsize - len ;
const char * p ;
for ( p = strtab ; p < = last ; p + + )
2008-08-07 12:24:17 +10:00
if ( memcmp ( p , s , len ) = = 0 )
2007-12-10 14:28:39 +11:00
return p ;
return NULL ;
}
int fdt_move ( const void * fdt , void * buf , int bufsize )
{
2008-08-07 12:24:17 +10:00
FDT_CHECK_HEADER ( fdt ) ;
2007-12-10 14:28:39 +11:00
if ( fdt_totalsize ( fdt ) > bufsize )
return - FDT_ERR_NOSPACE ;
memmove ( buf , fdt , fdt_totalsize ( fdt ) ) ;
return 0 ;
}