2019-06-21 17:18:32 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-12-18 07:06:42 +03:00
/*
* ( C ) Copyright David Gibson < dwg @ au1 . ibm . com > , IBM Corporation . 2005.
*/
# include "dtc.h"
2018-11-29 03:37:35 +03:00
# include "srcpos.h"
2007-12-18 07:06:42 +03:00
/*
* Tree building functions
*/
2010-11-18 02:28:20 +03:00
void add_label ( struct label * * labels , char * label )
{
struct label * new ;
/* Make sure the label isn't already there */
2012-09-29 01:25:59 +04:00
for_each_label_withdel ( * labels , new )
if ( streq ( new - > label , label ) ) {
new - > deleted = 0 ;
2010-11-18 02:28:20 +03:00
return ;
2012-09-29 01:25:59 +04:00
}
2010-11-18 02:28:20 +03:00
new = xmalloc ( sizeof ( * new ) ) ;
2012-09-29 01:25:59 +04:00
memset ( new , 0 , sizeof ( * new ) ) ;
2010-11-18 02:28:20 +03:00
new - > label = label ;
new - > next = * labels ;
* labels = new ;
}
2012-09-29 01:25:59 +04:00
void delete_labels ( struct label * * labels )
{
struct label * label ;
for_each_label ( * labels , label )
label - > deleted = 1 ;
}
2018-11-29 03:37:35 +03:00
struct property * build_property ( char * name , struct data val ,
struct srcpos * srcpos )
2007-12-18 07:06:42 +03:00
{
struct property * new = xmalloc ( sizeof ( * new ) ) ;
2010-11-18 02:28:20 +03:00
memset ( new , 0 , sizeof ( * new ) ) ;
2007-12-18 07:06:42 +03:00
new - > name = name ;
new - > val = val ;
2018-11-29 03:37:35 +03:00
new - > srcpos = srcpos_copy ( srcpos ) ;
2007-12-18 07:06:42 +03:00
return new ;
}
2012-09-29 01:25:59 +04:00
struct property * build_property_delete ( char * name )
{
struct property * new = xmalloc ( sizeof ( * new ) ) ;
memset ( new , 0 , sizeof ( * new ) ) ;
new - > name = name ;
new - > deleted = 1 ;
return new ;
}
2007-12-18 07:06:42 +03:00
struct property * chain_property ( struct property * first , struct property * list )
{
assert ( first - > next = = NULL ) ;
first - > next = list ;
return first ;
}
struct property * reverse_properties ( struct property * first )
{
struct property * p = first ;
struct property * head = NULL ;
struct property * next ;
while ( p ) {
next = p - > next ;
p - > next = head ;
head = p ;
p = next ;
}
return head ;
}
2018-11-29 03:37:35 +03:00
struct node * build_node ( struct property * proplist , struct node * children ,
struct srcpos * srcpos )
2007-12-18 07:06:42 +03:00
{
struct node * new = xmalloc ( sizeof ( * new ) ) ;
struct node * child ;
memset ( new , 0 , sizeof ( * new ) ) ;
new - > proplist = reverse_properties ( proplist ) ;
new - > children = children ;
2018-11-29 03:37:35 +03:00
new - > srcpos = srcpos_copy ( srcpos ) ;
2007-12-18 07:06:42 +03:00
for_each_child ( new , child ) {
child - > parent = new ;
}
return new ;
}
2018-11-29 03:37:35 +03:00
struct node * build_node_delete ( struct srcpos * srcpos )
2012-09-29 01:25:59 +04:00
{
struct node * new = xmalloc ( sizeof ( * new ) ) ;
memset ( new , 0 , sizeof ( * new ) ) ;
new - > deleted = 1 ;
2018-11-29 03:37:35 +03:00
new - > srcpos = srcpos_copy ( srcpos ) ;
2012-09-29 01:25:59 +04:00
return new ;
}
2010-11-18 02:28:20 +03:00
struct node * name_node ( struct node * node , char * name )
2007-12-18 07:06:42 +03:00
{
assert ( node - > name = = NULL ) ;
node - > name = name ;
return node ;
}
2018-05-08 21:07:49 +03:00
struct node * omit_node_if_unused ( struct node * node )
{
node - > omit_if_unused = 1 ;
return node ;
}
struct node * reference_node ( struct node * node )
{
node - > is_referenced = 1 ;
return node ;
}
2010-11-18 02:28:20 +03:00
struct node * merge_nodes ( struct node * old_node , struct node * new_node )
{
struct property * new_prop , * old_prop ;
struct node * new_child , * old_child ;
struct label * l ;
2012-09-29 01:25:59 +04:00
old_node - > deleted = 0 ;
2010-11-18 02:28:20 +03:00
/* Add new node labels to old node */
2012-09-29 01:25:59 +04:00
for_each_label_withdel ( new_node - > labels , l )
2010-11-18 02:28:20 +03:00
add_label ( & old_node - > labels , l - > label ) ;
/* Move properties from the new node to the old node. If there
* is a collision , replace the old value with the new */
while ( new_node - > proplist ) {
/* Pop the property off the list */
new_prop = new_node - > proplist ;
new_node - > proplist = new_prop - > next ;
new_prop - > next = NULL ;
2012-09-29 01:25:59 +04:00
if ( new_prop - > deleted ) {
delete_property_by_name ( old_node , new_prop - > name ) ;
free ( new_prop ) ;
continue ;
}
2010-11-18 02:28:20 +03:00
/* Look for a collision, set new value if there is */
2012-09-29 01:25:59 +04:00
for_each_property_withdel ( old_node , old_prop ) {
2010-11-18 02:28:20 +03:00
if ( streq ( old_prop - > name , new_prop - > name ) ) {
/* Add new labels to old property */
2012-09-29 01:25:59 +04:00
for_each_label_withdel ( new_prop - > labels , l )
2010-11-18 02:28:20 +03:00
add_label ( & old_prop - > labels , l - > label ) ;
old_prop - > val = new_prop - > val ;
2012-09-29 01:25:59 +04:00
old_prop - > deleted = 0 ;
2018-11-29 03:37:35 +03:00
free ( old_prop - > srcpos ) ;
old_prop - > srcpos = new_prop - > srcpos ;
2010-11-18 02:28:20 +03:00
free ( new_prop ) ;
new_prop = NULL ;
break ;
}
}
/* if no collision occurred, add property to the old node. */
if ( new_prop )
add_property ( old_node , new_prop ) ;
}
/* Move the override child nodes into the primary node. If
* there is a collision , then merge the nodes . */
while ( new_node - > children ) {
/* Pop the child node off the list */
new_child = new_node - > children ;
new_node - > children = new_child - > next_sibling ;
new_child - > parent = NULL ;
new_child - > next_sibling = NULL ;
2012-09-29 01:25:59 +04:00
if ( new_child - > deleted ) {
delete_node_by_name ( old_node , new_child - > name ) ;
free ( new_child ) ;
continue ;
}
2010-11-18 02:28:20 +03:00
/* Search for a collision. Merge if there is */
2012-09-29 01:25:59 +04:00
for_each_child_withdel ( old_node , old_child ) {
2010-11-18 02:28:20 +03:00
if ( streq ( old_child - > name , new_child - > name ) ) {
merge_nodes ( old_child , new_child ) ;
new_child = NULL ;
break ;
}
}
2017-01-04 19:45:20 +03:00
/* if no collision occurred, add child to the old node. */
2010-11-18 02:28:20 +03:00
if ( new_child )
add_child ( old_node , new_child ) ;
}
2018-11-29 03:37:35 +03:00
old_node - > srcpos = srcpos_extend ( old_node - > srcpos , new_node - > srcpos ) ;
2010-11-18 02:28:20 +03:00
/* The new node contents are now merged into the old node. Free
* the new node . */
free ( new_node ) ;
return old_node ;
}
2018-02-28 02:40:38 +03:00
struct node * add_orphan_node ( struct node * dt , struct node * new_node , char * ref )
2017-10-03 19:37:04 +03:00
{
static unsigned int next_orphan_fragment = 0 ;
struct node * node ;
struct property * p ;
struct data d = empty_data ;
char * name ;
2018-05-08 21:07:49 +03:00
if ( ref [ 0 ] = = ' / ' ) {
2019-06-12 16:05:52 +03:00
d = data_add_marker ( d , TYPE_STRING , ref ) ;
2018-05-08 21:07:49 +03:00
d = data_append_data ( d , ref , strlen ( ref ) + 1 ) ;
2018-11-29 03:37:35 +03:00
p = build_property ( " target-path " , d , NULL ) ;
2018-05-08 21:07:49 +03:00
} else {
d = data_add_marker ( d , REF_PHANDLE , ref ) ;
d = data_append_integer ( d , 0xffffffff , 32 ) ;
2017-10-03 19:37:04 +03:00
2018-11-29 03:37:35 +03:00
p = build_property ( " target " , d , NULL ) ;
2018-05-08 21:07:49 +03:00
}
2017-10-03 19:37:04 +03:00
xasprintf ( & name , " fragment@%u " ,
next_orphan_fragment + + ) ;
name_node ( new_node , " __overlay__ " ) ;
2018-11-29 03:37:35 +03:00
node = build_node ( p , new_node , NULL ) ;
2017-10-03 19:37:04 +03:00
name_node ( node , name ) ;
add_child ( dt , node ) ;
2018-02-28 02:40:38 +03:00
return dt ;
2017-10-03 19:37:04 +03:00
}
2007-12-18 07:06:42 +03:00
struct node * chain_node ( struct node * first , struct node * list )
{
assert ( first - > next_sibling = = NULL ) ;
first - > next_sibling = list ;
return first ;
}
void add_property ( struct node * node , struct property * prop )
{
struct property * * p ;
prop - > next = NULL ;
p = & node - > proplist ;
while ( * p )
p = & ( ( * p ) - > next ) ;
* p = prop ;
}
2012-09-29 01:25:59 +04:00
void delete_property_by_name ( struct node * node , char * name )
{
struct property * prop = node - > proplist ;
while ( prop ) {
2017-03-21 17:01:08 +03:00
if ( streq ( prop - > name , name ) ) {
2012-09-29 01:25:59 +04:00
delete_property ( prop ) ;
return ;
}
prop = prop - > next ;
}
}
void delete_property ( struct property * prop )
{
prop - > deleted = 1 ;
delete_labels ( & prop - > labels ) ;
}
2007-12-18 07:06:42 +03:00
void add_child ( struct node * parent , struct node * child )
{
struct node * * p ;
child - > next_sibling = NULL ;
2008-08-07 06:24:17 +04:00
child - > parent = parent ;
2007-12-18 07:06:42 +03:00
p = & parent - > children ;
while ( * p )
p = & ( ( * p ) - > next_sibling ) ;
* p = child ;
}
2012-09-29 01:25:59 +04:00
void delete_node_by_name ( struct node * parent , char * name )
{
struct node * node = parent - > children ;
while ( node ) {
2017-03-21 17:01:08 +03:00
if ( streq ( node - > name , name ) ) {
2012-09-29 01:25:59 +04:00
delete_node ( node ) ;
return ;
}
node = node - > next_sibling ;
}
}
void delete_node ( struct node * node )
{
struct property * prop ;
struct node * child ;
node - > deleted = 1 ;
for_each_child ( node , child )
delete_node ( child ) ;
for_each_property ( node , prop )
delete_property ( prop ) ;
delete_labels ( & node - > labels ) ;
}
2017-01-04 19:45:20 +03:00
void append_to_property ( struct node * node ,
2019-06-12 16:05:52 +03:00
char * name , const void * data , int len ,
enum markertype type )
2017-01-04 19:45:20 +03:00
{
struct data d ;
struct property * p ;
p = get_property ( node , name ) ;
if ( p ) {
2019-06-12 16:05:52 +03:00
d = data_add_marker ( p - > val , type , name ) ;
d = data_append_data ( d , data , len ) ;
2017-01-04 19:45:20 +03:00
p - > val = d ;
} else {
2019-06-12 16:05:52 +03:00
d = data_add_marker ( empty_data , type , name ) ;
d = data_append_data ( d , data , len ) ;
2018-11-29 03:37:35 +03:00
p = build_property ( name , d , NULL ) ;
2017-01-04 19:45:20 +03:00
add_property ( node , p ) ;
}
}
2010-11-18 02:28:20 +03:00
struct reserve_info * build_reserve_entry ( uint64_t address , uint64_t size )
2007-12-18 07:06:42 +03:00
{
struct reserve_info * new = xmalloc ( sizeof ( * new ) ) ;
2010-11-18 02:28:20 +03:00
memset ( new , 0 , sizeof ( * new ) ) ;
2017-03-21 17:01:08 +03:00
new - > address = address ;
new - > size = size ;
2007-12-18 07:06:42 +03:00
return new ;
}
struct reserve_info * chain_reserve_entry ( struct reserve_info * first ,
struct reserve_info * list )
{
assert ( first - > next = = NULL ) ;
first - > next = list ;
return first ;
}
struct reserve_info * add_reserve_entry ( struct reserve_info * list ,
struct reserve_info * new )
{
struct reserve_info * last ;
new - > next = NULL ;
if ( ! list )
return new ;
for ( last = list ; last - > next ; last = last - > next )
;
last - > next = new ;
return list ;
}
2017-01-04 19:45:20 +03:00
struct dt_info * build_dt_info ( unsigned int dtsflags ,
struct reserve_info * reservelist ,
struct node * tree , uint32_t boot_cpuid_phys )
2007-12-18 07:06:42 +03:00
{
2017-01-04 19:45:20 +03:00
struct dt_info * dti ;
2007-12-18 07:06:42 +03:00
2017-01-04 19:45:20 +03:00
dti = xmalloc ( sizeof ( * dti ) ) ;
dti - > dtsflags = dtsflags ;
dti - > reservelist = reservelist ;
dti - > dt = tree ;
dti - > boot_cpuid_phys = boot_cpuid_phys ;
2007-12-18 07:06:42 +03:00
2017-01-04 19:45:20 +03:00
return dti ;
2007-12-18 07:06:42 +03:00
}
/*
* Tree accessor functions
*/
const char * get_unitname ( struct node * node )
{
if ( node - > name [ node - > basenamelen ] = = ' \0 ' )
return " " ;
else
return node - > name + node - > basenamelen + 1 ;
}
struct property * get_property ( struct node * node , const char * propname )
{
struct property * prop ;
for_each_property ( node , prop )
if ( streq ( prop - > name , propname ) )
return prop ;
return NULL ;
}
cell_t propval_cell ( struct property * prop )
{
assert ( prop - > val . len = = sizeof ( cell_t ) ) ;
2017-03-21 17:01:08 +03:00
return fdt32_to_cpu ( * ( ( fdt32_t * ) prop - > val . val ) ) ;
2007-12-18 07:06:42 +03:00
}
2017-10-03 19:37:04 +03:00
cell_t propval_cell_n ( struct property * prop , int n )
{
assert ( prop - > val . len / sizeof ( cell_t ) > = n ) ;
return fdt32_to_cpu ( * ( ( fdt32_t * ) prop - > val . val + n ) ) ;
}
2010-11-18 02:28:20 +03:00
struct property * get_property_by_label ( struct node * tree , const char * label ,
struct node * * node )
{
struct property * prop ;
struct node * c ;
* node = tree ;
for_each_property ( tree , prop ) {
struct label * l ;
for_each_label ( prop - > labels , l )
if ( streq ( l - > label , label ) )
return prop ;
}
for_each_child ( tree , c ) {
prop = get_property_by_label ( c , label , node ) ;
if ( prop )
return prop ;
}
* node = NULL ;
return NULL ;
}
struct marker * get_marker_label ( struct node * tree , const char * label ,
struct node * * node , struct property * * prop )
{
struct marker * m ;
struct property * p ;
struct node * c ;
* node = tree ;
for_each_property ( tree , p ) {
* prop = p ;
m = p - > val . markers ;
for_each_marker_of_type ( m , LABEL )
if ( streq ( m - > ref , label ) )
return m ;
}
for_each_child ( tree , c ) {
m = get_marker_label ( c , label , node , prop ) ;
if ( m )
return m ;
}
* prop = NULL ;
* node = NULL ;
return NULL ;
}
2007-12-18 07:06:42 +03:00
struct node * get_subnode ( struct node * node , const char * nodename )
{
struct node * child ;
for_each_child ( node , child )
if ( streq ( child - > name , nodename ) )
return child ;
return NULL ;
}
struct node * get_node_by_path ( struct node * tree , const char * path )
{
const char * p ;
struct node * child ;
2012-09-29 01:25:59 +04:00
if ( ! path | | ! ( * path ) ) {
if ( tree - > deleted )
return NULL ;
2007-12-18 07:06:42 +03:00
return tree ;
2012-09-29 01:25:59 +04:00
}
2007-12-18 07:06:42 +03:00
while ( path [ 0 ] = = ' / ' )
path + + ;
p = strchr ( path , ' / ' ) ;
for_each_child ( tree , child ) {
2019-12-27 01:36:47 +03:00
if ( p & & strprefixeq ( path , p - path , child - > name ) )
2007-12-18 07:06:42 +03:00
return get_node_by_path ( child , p + 1 ) ;
else if ( ! p & & streq ( path , child - > name ) )
return child ;
}
return NULL ;
}
struct node * get_node_by_label ( struct node * tree , const char * label )
{
struct node * child , * node ;
2010-11-18 02:28:20 +03:00
struct label * l ;
2007-12-18 07:06:42 +03:00
assert ( label & & ( strlen ( label ) > 0 ) ) ;
2010-11-18 02:28:20 +03:00
for_each_label ( tree - > labels , l )
if ( streq ( l - > label , label ) )
return tree ;
2007-12-18 07:06:42 +03:00
for_each_child ( tree , child ) {
node = get_node_by_label ( child , label ) ;
if ( node )
return node ;
}
return NULL ;
}
struct node * get_node_by_phandle ( struct node * tree , cell_t phandle )
{
struct node * child , * node ;
2018-02-28 02:40:38 +03:00
if ( ( phandle = = 0 ) | | ( phandle = = - 1 ) ) {
assert ( generate_fixups ) ;
return NULL ;
}
2007-12-18 07:06:42 +03:00
2012-09-29 01:25:59 +04:00
if ( tree - > phandle = = phandle ) {
if ( tree - > deleted )
return NULL ;
2007-12-18 07:06:42 +03:00
return tree ;
2012-09-29 01:25:59 +04:00
}
2007-12-18 07:06:42 +03:00
for_each_child ( tree , child ) {
node = get_node_by_phandle ( child , phandle ) ;
if ( node )
return node ;
}
return NULL ;
}
struct node * get_node_by_ref ( struct node * tree , const char * ref )
{
2015-04-30 00:00:05 +03:00
if ( streq ( ref , " / " ) )
return tree ;
else if ( ref [ 0 ] = = ' / ' )
2007-12-18 07:06:42 +03:00
return get_node_by_path ( tree , ref ) ;
else
return get_node_by_label ( tree , ref ) ;
}
cell_t get_node_phandle ( struct node * root , struct node * node )
{
static cell_t phandle = 1 ; /* FIXME: ick, static local */
2018-09-13 16:59:25 +03:00
struct data d = empty_data ;
2007-12-18 07:06:42 +03:00
if ( ( node - > phandle ! = 0 ) & & ( node - > phandle ! = - 1 ) )
return node - > phandle ;
while ( get_node_by_phandle ( root , phandle ) )
phandle + + ;
node - > phandle = phandle ;
2010-11-18 02:28:20 +03:00
2018-09-13 16:59:25 +03:00
d = data_add_marker ( d , TYPE_UINT32 , NULL ) ;
d = data_append_cell ( d , phandle ) ;
2010-11-18 02:28:20 +03:00
if ( ! get_property ( node , " linux,phandle " )
& & ( phandle_format & PHANDLE_LEGACY ) )
2018-11-29 03:37:35 +03:00
add_property ( node , build_property ( " linux,phandle " , d , NULL ) ) ;
2010-11-18 02:28:20 +03:00
if ( ! get_property ( node , " phandle " )
& & ( phandle_format & PHANDLE_EPAPR ) )
2018-11-29 03:37:35 +03:00
add_property ( node , build_property ( " phandle " , d , NULL ) ) ;
2010-11-18 02:28:20 +03:00
/* If the node *does* have a phandle property, we must
* be dealing with a self - referencing phandle , which will be
* fixed up momentarily in the caller */
2007-12-18 07:06:42 +03:00
return node - > phandle ;
}
2010-11-18 02:28:20 +03:00
uint32_t guess_boot_cpuid ( struct node * tree )
{
struct node * cpus , * bootcpu ;
struct property * reg ;
cpus = get_node_by_path ( tree , " /cpus " ) ;
if ( ! cpus )
return 0 ;
bootcpu = cpus - > children ;
if ( ! bootcpu )
return 0 ;
reg = get_property ( bootcpu , " reg " ) ;
if ( ! reg | | ( reg - > val . len ! = sizeof ( uint32_t ) ) )
return 0 ;
/* FIXME: Sanity check node? */
return propval_cell ( reg ) ;
}
static int cmp_reserve_info ( const void * ax , const void * bx )
{
const struct reserve_info * a , * b ;
a = * ( ( const struct reserve_info * const * ) ax ) ;
b = * ( ( const struct reserve_info * const * ) bx ) ;
2017-03-21 17:01:08 +03:00
if ( a - > address < b - > address )
2010-11-18 02:28:20 +03:00
return - 1 ;
2017-03-21 17:01:08 +03:00
else if ( a - > address > b - > address )
2010-11-18 02:28:20 +03:00
return 1 ;
2017-03-21 17:01:08 +03:00
else if ( a - > size < b - > size )
2010-11-18 02:28:20 +03:00
return - 1 ;
2017-03-21 17:01:08 +03:00
else if ( a - > size > b - > size )
2010-11-18 02:28:20 +03:00
return 1 ;
else
return 0 ;
}
2017-01-04 19:45:20 +03:00
static void sort_reserve_entries ( struct dt_info * dti )
2010-11-18 02:28:20 +03:00
{
struct reserve_info * ri , * * tbl ;
int n = 0 , i = 0 ;
2017-01-04 19:45:20 +03:00
for ( ri = dti - > reservelist ;
2010-11-18 02:28:20 +03:00
ri ;
ri = ri - > next )
n + + ;
if ( n = = 0 )
return ;
tbl = xmalloc ( n * sizeof ( * tbl ) ) ;
2017-01-04 19:45:20 +03:00
for ( ri = dti - > reservelist ;
2010-11-18 02:28:20 +03:00
ri ;
ri = ri - > next )
tbl [ i + + ] = ri ;
qsort ( tbl , n , sizeof ( * tbl ) , cmp_reserve_info ) ;
2017-01-04 19:45:20 +03:00
dti - > reservelist = tbl [ 0 ] ;
2010-11-18 02:28:20 +03:00
for ( i = 0 ; i < ( n - 1 ) ; i + + )
tbl [ i ] - > next = tbl [ i + 1 ] ;
tbl [ n - 1 ] - > next = NULL ;
free ( tbl ) ;
}
static int cmp_prop ( const void * ax , const void * bx )
{
const struct property * a , * b ;
a = * ( ( const struct property * const * ) ax ) ;
b = * ( ( const struct property * const * ) bx ) ;
return strcmp ( a - > name , b - > name ) ;
}
static void sort_properties ( struct node * node )
{
int n = 0 , i = 0 ;
struct property * prop , * * tbl ;
2012-09-29 01:25:59 +04:00
for_each_property_withdel ( node , prop )
2010-11-18 02:28:20 +03:00
n + + ;
if ( n = = 0 )
return ;
tbl = xmalloc ( n * sizeof ( * tbl ) ) ;
2012-09-29 01:25:59 +04:00
for_each_property_withdel ( node , prop )
2010-11-18 02:28:20 +03:00
tbl [ i + + ] = prop ;
qsort ( tbl , n , sizeof ( * tbl ) , cmp_prop ) ;
node - > proplist = tbl [ 0 ] ;
for ( i = 0 ; i < ( n - 1 ) ; i + + )
tbl [ i ] - > next = tbl [ i + 1 ] ;
tbl [ n - 1 ] - > next = NULL ;
free ( tbl ) ;
}
static int cmp_subnode ( const void * ax , const void * bx )
{
const struct node * a , * b ;
a = * ( ( const struct node * const * ) ax ) ;
b = * ( ( const struct node * const * ) bx ) ;
return strcmp ( a - > name , b - > name ) ;
}
static void sort_subnodes ( struct node * node )
{
int n = 0 , i = 0 ;
struct node * subnode , * * tbl ;
2012-09-29 01:25:59 +04:00
for_each_child_withdel ( node , subnode )
2010-11-18 02:28:20 +03:00
n + + ;
if ( n = = 0 )
return ;
tbl = xmalloc ( n * sizeof ( * tbl ) ) ;
2012-09-29 01:25:59 +04:00
for_each_child_withdel ( node , subnode )
2010-11-18 02:28:20 +03:00
tbl [ i + + ] = subnode ;
qsort ( tbl , n , sizeof ( * tbl ) , cmp_subnode ) ;
node - > children = tbl [ 0 ] ;
for ( i = 0 ; i < ( n - 1 ) ; i + + )
tbl [ i ] - > next_sibling = tbl [ i + 1 ] ;
tbl [ n - 1 ] - > next_sibling = NULL ;
free ( tbl ) ;
}
static void sort_node ( struct node * node )
{
struct node * c ;
sort_properties ( node ) ;
sort_subnodes ( node ) ;
2012-09-29 01:25:59 +04:00
for_each_child_withdel ( node , c )
2010-11-18 02:28:20 +03:00
sort_node ( c ) ;
}
2017-01-04 19:45:20 +03:00
void sort_tree ( struct dt_info * dti )
{
sort_reserve_entries ( dti ) ;
sort_node ( dti - > dt ) ;
}
/* utility helper to avoid code duplication */
static struct node * build_and_name_child_node ( struct node * parent , char * name )
{
struct node * node ;
2018-11-29 03:37:35 +03:00
node = build_node ( NULL , NULL , NULL ) ;
2017-01-04 19:45:20 +03:00
name_node ( node , xstrdup ( name ) ) ;
add_child ( parent , node ) ;
return node ;
}
static struct node * build_root_node ( struct node * dt , char * name )
{
struct node * an ;
an = get_subnode ( dt , name ) ;
if ( ! an )
an = build_and_name_child_node ( dt , name ) ;
if ( ! an )
die ( " Could not build root node /%s \n " , name ) ;
return an ;
}
static bool any_label_tree ( struct dt_info * dti , struct node * node )
{
struct node * c ;
if ( node - > labels )
return true ;
for_each_child ( node , c )
if ( any_label_tree ( dti , c ) )
return true ;
return false ;
}
static void generate_label_tree_internal ( struct dt_info * dti ,
struct node * an , struct node * node ,
bool allocph )
{
struct node * dt = dti - > dt ;
struct node * c ;
struct property * p ;
struct label * l ;
/* if there are labels */
if ( node - > labels ) {
/* now add the label in the node */
for_each_label ( node - > labels , l ) {
/* check whether the label already exists */
p = get_property ( an , l - > label ) ;
if ( p ) {
fprintf ( stderr , " WARNING: label %s already "
" exists in /%s " , l - > label ,
an - > name ) ;
continue ;
}
/* insert it */
p = build_property ( l - > label ,
2019-06-12 16:05:52 +03:00
data_copy_escape_string ( node - > fullpath ,
strlen ( node - > fullpath ) ) ,
2018-11-29 03:37:35 +03:00
NULL ) ;
2017-01-04 19:45:20 +03:00
add_property ( an , p ) ;
}
/* force allocation of a phandle for this node */
if ( allocph )
( void ) get_node_phandle ( dt , node ) ;
}
for_each_child ( node , c )
generate_label_tree_internal ( dti , an , c , allocph ) ;
}
static bool any_fixup_tree ( struct dt_info * dti , struct node * node )
{
struct node * c ;
struct property * prop ;
struct marker * m ;
for_each_property ( node , prop ) {
m = prop - > val . markers ;
for_each_marker_of_type ( m , REF_PHANDLE ) {
if ( ! get_node_by_ref ( dti - > dt , m - > ref ) )
return true ;
}
}
for_each_child ( node , c ) {
if ( any_fixup_tree ( dti , c ) )
return true ;
}
return false ;
}
static void add_fixup_entry ( struct dt_info * dti , struct node * fn ,
struct node * node , struct property * prop ,
struct marker * m )
2010-11-18 02:28:20 +03:00
{
2017-01-04 19:45:20 +03:00
char * entry ;
/* m->ref can only be a REF_PHANDLE, but check anyway */
assert ( m - > type = = REF_PHANDLE ) ;
/* there shouldn't be any ':' in the arguments */
if ( strchr ( node - > fullpath , ' : ' ) | | strchr ( prop - > name , ' : ' ) )
die ( " arguments should not contain ':' \n " ) ;
xasprintf ( & entry , " %s:%s:%u " ,
node - > fullpath , prop - > name , m - > offset ) ;
2019-06-12 16:05:52 +03:00
append_to_property ( fn , m - > ref , entry , strlen ( entry ) + 1 , TYPE_STRING ) ;
2017-03-21 17:01:08 +03:00
free ( entry ) ;
2017-01-04 19:45:20 +03:00
}
static void generate_fixups_tree_internal ( struct dt_info * dti ,
struct node * fn ,
struct node * node )
{
struct node * dt = dti - > dt ;
struct node * c ;
struct property * prop ;
struct marker * m ;
struct node * refnode ;
for_each_property ( node , prop ) {
m = prop - > val . markers ;
for_each_marker_of_type ( m , REF_PHANDLE ) {
refnode = get_node_by_ref ( dt , m - > ref ) ;
if ( ! refnode )
add_fixup_entry ( dti , fn , node , prop , m ) ;
}
}
for_each_child ( node , c )
generate_fixups_tree_internal ( dti , fn , c ) ;
}
static bool any_local_fixup_tree ( struct dt_info * dti , struct node * node )
{
struct node * c ;
struct property * prop ;
struct marker * m ;
for_each_property ( node , prop ) {
m = prop - > val . markers ;
for_each_marker_of_type ( m , REF_PHANDLE ) {
if ( get_node_by_ref ( dti - > dt , m - > ref ) )
return true ;
}
}
for_each_child ( node , c ) {
if ( any_local_fixup_tree ( dti , c ) )
return true ;
}
return false ;
}
static void add_local_fixup_entry ( struct dt_info * dti ,
struct node * lfn , struct node * node ,
struct property * prop , struct marker * m ,
struct node * refnode )
{
struct node * wn , * nwn ; /* local fixup node, walk node, new */
2017-03-21 17:01:08 +03:00
fdt32_t value_32 ;
2017-01-04 19:45:20 +03:00
char * * compp ;
int i , depth ;
2019-06-12 16:05:52 +03:00
/* walk back retrieving depth */
2017-01-04 19:45:20 +03:00
depth = 0 ;
for ( wn = node ; wn ; wn = wn - > parent )
depth + + ;
/* allocate name array */
compp = xmalloc ( sizeof ( * compp ) * depth ) ;
/* store names in the array */
for ( wn = node , i = depth - 1 ; wn ; wn = wn - > parent , i - - )
compp [ i ] = wn - > name ;
/* walk the path components creating nodes if they don't exist */
for ( wn = lfn , i = 1 ; i < depth ; i + + , wn = nwn ) {
/* if no node exists, create it */
nwn = get_subnode ( wn , compp [ i ] ) ;
if ( ! nwn )
nwn = build_and_name_child_node ( wn , compp [ i ] ) ;
}
free ( compp ) ;
value_32 = cpu_to_fdt32 ( m - > offset ) ;
2019-06-12 16:05:52 +03:00
append_to_property ( wn , prop - > name , & value_32 , sizeof ( value_32 ) , TYPE_UINT32 ) ;
2017-01-04 19:45:20 +03:00
}
static void generate_local_fixups_tree_internal ( struct dt_info * dti ,
struct node * lfn ,
struct node * node )
{
struct node * dt = dti - > dt ;
struct node * c ;
struct property * prop ;
struct marker * m ;
struct node * refnode ;
for_each_property ( node , prop ) {
m = prop - > val . markers ;
for_each_marker_of_type ( m , REF_PHANDLE ) {
refnode = get_node_by_ref ( dt , m - > ref ) ;
if ( refnode )
add_local_fixup_entry ( dti , lfn , node , prop , m , refnode ) ;
}
}
for_each_child ( node , c )
generate_local_fixups_tree_internal ( dti , lfn , c ) ;
}
void generate_label_tree ( struct dt_info * dti , char * name , bool allocph )
{
if ( ! any_label_tree ( dti , dti - > dt ) )
return ;
generate_label_tree_internal ( dti , build_root_node ( dti - > dt , name ) ,
dti - > dt , allocph ) ;
}
void generate_fixups_tree ( struct dt_info * dti , char * name )
{
if ( ! any_fixup_tree ( dti , dti - > dt ) )
return ;
generate_fixups_tree_internal ( dti , build_root_node ( dti - > dt , name ) ,
dti - > dt ) ;
}
void generate_local_fixups_tree ( struct dt_info * dti , char * name )
{
if ( ! any_local_fixup_tree ( dti , dti - > dt ) )
return ;
generate_local_fixups_tree_internal ( dti , build_root_node ( dti - > dt , name ) ,
dti - > dt ) ;
2010-11-18 02:28:20 +03:00
}