Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
ezynq
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
ezynq
Commits
7496de94
Commit
7496de94
authored
Dec 27, 2018
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
step2
parent
8d7093dc
Changes
38
Show whitespace changes
Inline
Side-by-side
Showing
38 changed files
with
13569 additions
and
2 deletions
+13569
-2
.gitignore
u-boot-tree/scripts/dtc/.gitignore
+1
-0
Makefile
u-boot-tree/scripts/dtc/Makefile
+32
-0
Makefile.dtc
u-boot-tree/scripts/dtc/Makefile.dtc
+18
-0
checks.c
u-boot-tree/scripts/dtc/checks.c
+1506
-0
data.c
u-boot-tree/scripts/dtc/data.c
+269
-0
dtc-lexer.l
u-boot-tree/scripts/dtc/dtc-lexer.l
+306
-0
dtc-parser.y
u-boot-tree/scripts/dtc/dtc-parser.y
+538
-0
dtc.c
u-boot-tree/scripts/dtc/dtc.c
+364
-0
dtc.h
u-boot-tree/scripts/dtc/dtc.h
+293
-0
flattree.c
u-boot-tree/scripts/dtc/flattree.c
+940
-0
fstree.c
u-boot-tree/scripts/dtc/fstree.c
+90
-0
Makefile.libfdt
u-boot-tree/scripts/dtc/libfdt/Makefile.libfdt
+11
-0
fdt.c
u-boot-tree/scripts/dtc/libfdt/fdt.c
+254
-0
fdt.h
u-boot-tree/scripts/dtc/libfdt/fdt.h
+111
-0
fdt_addresses.c
u-boot-tree/scripts/dtc/libfdt/fdt_addresses.c
+96
-0
fdt_empty_tree.c
u-boot-tree/scripts/dtc/libfdt/fdt_empty_tree.c
+83
-0
fdt_overlay.c
u-boot-tree/scripts/dtc/libfdt/fdt_overlay.c
+912
-0
fdt_ro.c
u-boot-tree/scripts/dtc/libfdt/fdt_ro.c
+773
-0
fdt_rw.c
u-boot-tree/scripts/dtc/libfdt/fdt_rw.c
+505
-0
fdt_strerror.c
u-boot-tree/scripts/dtc/libfdt/fdt_strerror.c
+102
-0
fdt_sw.c
u-boot-tree/scripts/dtc/libfdt/fdt_sw.c
+300
-0
fdt_wip.c
u-boot-tree/scripts/dtc/libfdt/fdt_wip.c
+139
-0
libfdt.h
u-boot-tree/scripts/dtc/libfdt/libfdt.h
+1905
-0
libfdt_env.h
u-boot-tree/scripts/dtc/libfdt/libfdt_env.h
+139
-0
libfdt_internal.h
u-boot-tree/scripts/dtc/libfdt/libfdt_internal.h
+95
-0
livetree.c
u-boot-tree/scripts/dtc/livetree.c
+1013
-0
.gitignore
u-boot-tree/scripts/dtc/pylibfdt/.gitignore
+4
-0
Makefile
u-boot-tree/scripts/dtc/pylibfdt/Makefile
+31
-0
libfdt.i_shipped
u-boot-tree/scripts/dtc/pylibfdt/libfdt.i_shipped
+1097
-0
setup.py
u-boot-tree/scripts/dtc/pylibfdt/setup.py
+123
-0
srcpos.c
u-boot-tree/scripts/dtc/srcpos.c
+297
-0
srcpos.h
u-boot-tree/scripts/dtc/srcpos.h
+117
-0
treesource.c
u-boot-tree/scripts/dtc/treesource.c
+284
-0
update-dtc-source.sh
u-boot-tree/scripts/dtc/update-dtc-source.sh
+79
-0
util.c
u-boot-tree/scripts/dtc/util.c
+474
-0
util.h
u-boot-tree/scripts/dtc/util.h
+266
-0
version_gen.h
u-boot-tree/scripts/dtc/version_gen.h
+1
-0
Makefile
u-boot-tree/tools/Makefile
+1
-2
No files found.
u-boot-tree/scripts/dtc/.gitignore
0 → 100644
View file @
7496de94
/dtc
u-boot-tree/scripts/dtc/Makefile
0 → 100644
View file @
7496de94
# SPDX-License-Identifier: GPL-2.0
# scripts/dtc makefile
hostprogs-y
:=
dtc
always
:=
$
(
hostprogs-y
)
dtc-objs
:=
dtc.o flattree.o fstree.o data.o livetree.o treesource.o
\
srcpos.o checks.o util.o
dtc-objs
+=
dtc-lexer.lex.o dtc-parser.tab.o
# Source files need to get at the userspace version of libfdt_env.h to compile
HOSTCFLAGS_DTC
:=
-I
$(src)
-I
$(src)
/libfdt
HOSTCFLAGS_checks.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_data.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_flattree.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_fstree.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_livetree.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_srcpos.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_treesource.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_util.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-lexer.lex.o
:=
$(HOSTCFLAGS_DTC)
HOSTCFLAGS_dtc-parser.tab.o
:=
$(HOSTCFLAGS_DTC)
# dependencies on generated files need to be listed explicitly
$(obj)/dtc-lexer.lex.o
:
$(obj)/dtc-parser.tab.h
# Added for U-Boot
subdir-$(CONFIG_PYLIBFDT)
+=
pylibfdt
u-boot-tree/scripts/dtc/Makefile.dtc
0 → 100644
View file @
7496de94
# Makefile.dtc
#
# This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles.
#
DTC_SRCS
=
\
checks.c
\
data.c
\
dtc.c
\
flattree.c
\
fstree.c
\
livetree.c
\
srcpos.c
\
treesource.c
\
util.c
DTC_GEN_SRCS
=
dtc-lexer.lex.c dtc-parser.tab.c
DTC_OBJS
=
$
(
DTC_SRCS:%.c
=
%.o
)
$
(
DTC_GEN_SRCS:%.c
=
%.o
)
u-boot-tree/scripts/dtc/checks.c
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2007.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
#ifdef TRACE_CHECKS
#define TRACE(c, ...) \
do { \
fprintf(stderr, "=== %s: ", (c)->name); \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
} while (0)
#else
#define TRACE(c, fmt, ...) do { } while (0)
#endif
enum
checkstatus
{
UNCHECKED
=
0
,
PREREQ
,
PASSED
,
FAILED
,
};
struct
check
;
typedef
void
(
*
check_fn
)(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
);
struct
check
{
const
char
*
name
;
check_fn
fn
;
void
*
data
;
bool
warn
,
error
;
enum
checkstatus
status
;
bool
inprogress
;
int
num_prereqs
;
struct
check
**
prereq
;
};
#define CHECK_ENTRY(nm_, fn_, d_, w_, e_, ...) \
static struct check *nm_##_prereqs[] = { __VA_ARGS__ }; \
static struct check nm_ = { \
.name = #nm_, \
.fn = (fn_), \
.data = (d_), \
.warn = (w_), \
.error = (e_), \
.status = UNCHECKED, \
.num_prereqs = ARRAY_SIZE(nm_##_prereqs), \
.prereq = nm_##_prereqs, \
};
#define WARNING(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, true, false, __VA_ARGS__)
#define ERROR(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, false, true, __VA_ARGS__)
#define CHECK(nm_, fn_, d_, ...) \
CHECK_ENTRY(nm_, fn_, d_, false, false, __VA_ARGS__)
static
inline
void
PRINTF
(
5
,
6
)
check_msg
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
,
struct
property
*
prop
,
const
char
*
fmt
,
...)
{
va_list
ap
;
va_start
(
ap
,
fmt
);
if
((
c
->
warn
&&
(
quiet
<
1
))
||
(
c
->
error
&&
(
quiet
<
2
)))
{
fprintf
(
stderr
,
"%s: %s (%s): "
,
strcmp
(
dti
->
outname
,
"-"
)
?
dti
->
outname
:
"<stdout>"
,
(
c
->
error
)
?
"ERROR"
:
"Warning"
,
c
->
name
);
if
(
node
)
{
fprintf
(
stderr
,
"%s"
,
node
->
fullpath
);
if
(
prop
)
fprintf
(
stderr
,
":%s"
,
prop
->
name
);
fputs
(
": "
,
stderr
);
}
vfprintf
(
stderr
,
fmt
,
ap
);
fprintf
(
stderr
,
"
\n
"
);
}
va_end
(
ap
);
}
#define FAIL(c, dti, node, ...) \
do { \
TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
(c)->status = FAILED; \
check_msg((c), dti, node, NULL, __VA_ARGS__); \
} while (0)
#define FAIL_PROP(c, dti, node, prop, ...) \
do { \
TRACE((c), "\t\tFAILED at %s:%d", __FILE__, __LINE__); \
(c)->status = FAILED; \
check_msg((c), dti, node, prop, __VA_ARGS__); \
} while (0)
static
void
check_nodes_props
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
node
*
child
;
TRACE
(
c
,
"%s"
,
node
->
fullpath
);
if
(
c
->
fn
)
c
->
fn
(
c
,
dti
,
node
);
for_each_child
(
node
,
child
)
check_nodes_props
(
c
,
dti
,
child
);
}
static
bool
run_check
(
struct
check
*
c
,
struct
dt_info
*
dti
)
{
struct
node
*
dt
=
dti
->
dt
;
bool
error
=
false
;
int
i
;
assert
(
!
c
->
inprogress
);
if
(
c
->
status
!=
UNCHECKED
)
goto
out
;
c
->
inprogress
=
true
;
for
(
i
=
0
;
i
<
c
->
num_prereqs
;
i
++
)
{
struct
check
*
prq
=
c
->
prereq
[
i
];
error
=
error
||
run_check
(
prq
,
dti
);
if
(
prq
->
status
!=
PASSED
)
{
c
->
status
=
PREREQ
;
check_msg
(
c
,
dti
,
NULL
,
NULL
,
"Failed prerequisite '%s'"
,
c
->
prereq
[
i
]
->
name
);
}
}
if
(
c
->
status
!=
UNCHECKED
)
goto
out
;
check_nodes_props
(
c
,
dti
,
dt
);
if
(
c
->
status
==
UNCHECKED
)
c
->
status
=
PASSED
;
TRACE
(
c
,
"
\t
Completed, status %d"
,
c
->
status
);
out:
c
->
inprogress
=
false
;
if
((
c
->
status
!=
PASSED
)
&&
(
c
->
error
))
error
=
true
;
return
error
;
}
/*
* Utility check functions
*/
/* A check which always fails, for testing purposes only */
static
inline
void
check_always_fail
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
FAIL
(
c
,
dti
,
node
,
"always_fail check"
);
}
CHECK
(
always_fail
,
check_always_fail
,
NULL
);
static
void
check_is_string
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
char
*
propname
=
c
->
data
;
prop
=
get_property
(
node
,
propname
);
if
(
!
prop
)
return
;
/* Not present, assumed ok */
if
(
!
data_is_one_string
(
prop
->
val
))
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"property is not a string"
);
}
#define WARNING_IF_NOT_STRING(nm, propname) \
WARNING(nm, check_is_string, (propname))
#define ERROR_IF_NOT_STRING(nm, propname) \
ERROR(nm, check_is_string, (propname))
static
void
check_is_string_list
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
int
rem
,
l
;
struct
property
*
prop
;
char
*
propname
=
c
->
data
;
char
*
str
;
prop
=
get_property
(
node
,
propname
);
if
(
!
prop
)
return
;
/* Not present, assumed ok */
str
=
prop
->
val
.
val
;
rem
=
prop
->
val
.
len
;
while
(
rem
>
0
)
{
l
=
strnlen
(
str
,
rem
);
if
(
l
==
rem
)
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"property is not a string list"
);
break
;
}
rem
-=
l
+
1
;
str
+=
l
+
1
;
}
}
#define WARNING_IF_NOT_STRING_LIST(nm, propname) \
WARNING(nm, check_is_string_list, (propname))
#define ERROR_IF_NOT_STRING_LIST(nm, propname) \
ERROR(nm, check_is_string_list, (propname))
static
void
check_is_cell
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
char
*
propname
=
c
->
data
;
prop
=
get_property
(
node
,
propname
);
if
(
!
prop
)
return
;
/* Not present, assumed ok */
if
(
prop
->
val
.
len
!=
sizeof
(
cell_t
))
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"property is not a single cell"
);
}
#define WARNING_IF_NOT_CELL(nm, propname) \
WARNING(nm, check_is_cell, (propname))
#define ERROR_IF_NOT_CELL(nm, propname) \
ERROR(nm, check_is_cell, (propname))
/*
* Structural check functions
*/
static
void
check_duplicate_node_names
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
node
*
child
,
*
child2
;
for_each_child
(
node
,
child
)
for
(
child2
=
child
->
next_sibling
;
child2
;
child2
=
child2
->
next_sibling
)
if
(
streq
(
child
->
name
,
child2
->
name
))
FAIL
(
c
,
dti
,
node
,
"Duplicate node name"
);
}
ERROR
(
duplicate_node_names
,
check_duplicate_node_names
,
NULL
);
static
void
check_duplicate_property_names
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
,
*
prop2
;
for_each_property
(
node
,
prop
)
{
for
(
prop2
=
prop
->
next
;
prop2
;
prop2
=
prop2
->
next
)
{
if
(
prop2
->
deleted
)
continue
;
if
(
streq
(
prop
->
name
,
prop2
->
name
))
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"Duplicate property name"
);
}
}
}
ERROR
(
duplicate_property_names
,
check_duplicate_property_names
,
NULL
);
#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define DIGITS "0123456789"
#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
#define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-"
static
void
check_node_name_chars
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
int
n
=
strspn
(
node
->
name
,
c
->
data
);
if
(
n
<
strlen
(
node
->
name
))
FAIL
(
c
,
dti
,
node
,
"Bad character '%c' in node name"
,
node
->
name
[
n
]);
}
ERROR
(
node_name_chars
,
check_node_name_chars
,
PROPNODECHARS
"@"
);
static
void
check_node_name_chars_strict
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
int
n
=
strspn
(
node
->
name
,
c
->
data
);
if
(
n
<
node
->
basenamelen
)
FAIL
(
c
,
dti
,
node
,
"Character '%c' not recommended in node name"
,
node
->
name
[
n
]);
}
CHECK
(
node_name_chars_strict
,
check_node_name_chars_strict
,
PROPNODECHARSSTRICT
);
static
void
check_node_name_format
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
if
(
strchr
(
get_unitname
(
node
),
'@'
))
FAIL
(
c
,
dti
,
node
,
"multiple '@' characters in node name"
);
}
ERROR
(
node_name_format
,
check_node_name_format
,
NULL
,
&
node_name_chars
);
static
void
check_unit_address_vs_reg
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
const
char
*
unitname
=
get_unitname
(
node
);
struct
property
*
prop
=
get_property
(
node
,
"reg"
);
if
(
!
prop
)
{
prop
=
get_property
(
node
,
"ranges"
);
if
(
prop
&&
!
prop
->
val
.
len
)
prop
=
NULL
;
}
if
(
prop
)
{
if
(
!
unitname
[
0
])
FAIL
(
c
,
dti
,
node
,
"node has a reg or ranges property, but no unit name"
);
}
else
{
if
(
unitname
[
0
])
FAIL
(
c
,
dti
,
node
,
"node has a unit name, but no reg property"
);
}
}
WARNING
(
unit_address_vs_reg
,
check_unit_address_vs_reg
,
NULL
);
static
void
check_property_name_chars
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
for_each_property
(
node
,
prop
)
{
int
n
=
strspn
(
prop
->
name
,
c
->
data
);
if
(
n
<
strlen
(
prop
->
name
))
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"Bad character '%c' in property name"
,
prop
->
name
[
n
]);
}
}
ERROR
(
property_name_chars
,
check_property_name_chars
,
PROPNODECHARS
);
static
void
check_property_name_chars_strict
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
for_each_property
(
node
,
prop
)
{
const
char
*
name
=
prop
->
name
;
int
n
=
strspn
(
name
,
c
->
data
);
if
(
n
==
strlen
(
prop
->
name
))
continue
;
/* Certain names are whitelisted */
if
(
streq
(
name
,
"device_type"
))
continue
;
/*
* # is only allowed at the beginning of property names not counting
* the vendor prefix.
*/
if
(
name
[
n
]
==
'#'
&&
((
n
==
0
)
||
(
name
[
n
-
1
]
==
','
)))
{
name
+=
n
+
1
;
n
=
strspn
(
name
,
c
->
data
);
}
if
(
n
<
strlen
(
name
))
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"Character '%c' not recommended in property name"
,
name
[
n
]);
}
}
CHECK
(
property_name_chars_strict
,
check_property_name_chars_strict
,
PROPNODECHARSSTRICT
);
#define DESCLABEL_FMT "%s%s%s%s%s"
#define DESCLABEL_ARGS(node,prop,mark) \
((mark) ? "value of " : ""), \
((prop) ? "'" : ""), \
((prop) ? (prop)->name : ""), \
((prop) ? "' in " : ""), (node)->fullpath
static
void
check_duplicate_label
(
struct
check
*
c
,
struct
dt_info
*
dti
,
const
char
*
label
,
struct
node
*
node
,
struct
property
*
prop
,
struct
marker
*
mark
)
{
struct
node
*
dt
=
dti
->
dt
;
struct
node
*
othernode
=
NULL
;
struct
property
*
otherprop
=
NULL
;
struct
marker
*
othermark
=
NULL
;
othernode
=
get_node_by_label
(
dt
,
label
);
if
(
!
othernode
)
otherprop
=
get_property_by_label
(
dt
,
label
,
&
othernode
);
if
(
!
othernode
)
othermark
=
get_marker_label
(
dt
,
label
,
&
othernode
,
&
otherprop
);
if
(
!
othernode
)
return
;
if
((
othernode
!=
node
)
||
(
otherprop
!=
prop
)
||
(
othermark
!=
mark
))
FAIL
(
c
,
dti
,
node
,
"Duplicate label '%s' on "
DESCLABEL_FMT
" and "
DESCLABEL_FMT
,
label
,
DESCLABEL_ARGS
(
node
,
prop
,
mark
),
DESCLABEL_ARGS
(
othernode
,
otherprop
,
othermark
));
}
static
void
check_duplicate_label_node
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
label
*
l
;
struct
property
*
prop
;
for_each_label
(
node
->
labels
,
l
)
check_duplicate_label
(
c
,
dti
,
l
->
label
,
node
,
NULL
,
NULL
);
for_each_property
(
node
,
prop
)
{
struct
marker
*
m
=
prop
->
val
.
markers
;
for_each_label
(
prop
->
labels
,
l
)
check_duplicate_label
(
c
,
dti
,
l
->
label
,
node
,
prop
,
NULL
);
for_each_marker_of_type
(
m
,
LABEL
)
check_duplicate_label
(
c
,
dti
,
m
->
ref
,
node
,
prop
,
m
);
}
}
ERROR
(
duplicate_label
,
check_duplicate_label_node
,
NULL
);
static
cell_t
check_phandle_prop
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
,
const
char
*
propname
)
{
struct
node
*
root
=
dti
->
dt
;
struct
property
*
prop
;
struct
marker
*
m
;
cell_t
phandle
;
prop
=
get_property
(
node
,
propname
);
if
(
!
prop
)
return
0
;
if
(
prop
->
val
.
len
!=
sizeof
(
cell_t
))
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"bad length (%d) %s property"
,
prop
->
val
.
len
,
prop
->
name
);
return
0
;
}
m
=
prop
->
val
.
markers
;
for_each_marker_of_type
(
m
,
REF_PHANDLE
)
{
assert
(
m
->
offset
==
0
);
if
(
node
!=
get_node_by_ref
(
root
,
m
->
ref
))
/* "Set this node's phandle equal to some
* other node's phandle". That's nonsensical
* by construction. */
{
FAIL
(
c
,
dti
,
node
,
"%s is a reference to another node"
,
prop
->
name
);
}
/* But setting this node's phandle equal to its own
* phandle is allowed - that means allocate a unique
* phandle for this node, even if it's not otherwise
* referenced. The value will be filled in later, so
* we treat it as having no phandle data for now. */
return
0
;
}
phandle
=
propval_cell
(
prop
);
if
((
phandle
==
0
)
||
(
phandle
==
-
1
))
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"bad value (0x%x) in %s property"
,
phandle
,
prop
->
name
);
return
0
;
}
return
phandle
;
}
static
void
check_explicit_phandles
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
node
*
root
=
dti
->
dt
;
struct
node
*
other
;
cell_t
phandle
,
linux_phandle
;
/* Nothing should have assigned phandles yet */
assert
(
!
node
->
phandle
);
phandle
=
check_phandle_prop
(
c
,
dti
,
node
,
"phandle"
);
linux_phandle
=
check_phandle_prop
(
c
,
dti
,
node
,
"linux,phandle"
);
if
(
!
phandle
&&
!
linux_phandle
)
/* No valid phandles; nothing further to check */
return
;
if
(
linux_phandle
&&
phandle
&&
(
phandle
!=
linux_phandle
))
FAIL
(
c
,
dti
,
node
,
"mismatching 'phandle' and 'linux,phandle'"
" properties"
);
if
(
linux_phandle
&&
!
phandle
)
phandle
=
linux_phandle
;
other
=
get_node_by_phandle
(
root
,
phandle
);
if
(
other
&&
(
other
!=
node
))
{
FAIL
(
c
,
dti
,
node
,
"duplicated phandle 0x%x (seen before at %s)"
,
phandle
,
other
->
fullpath
);
return
;
}
node
->
phandle
=
phandle
;
}
ERROR
(
explicit_phandles
,
check_explicit_phandles
,
NULL
);
static
void
check_name_properties
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
**
pp
,
*
prop
=
NULL
;
for
(
pp
=
&
node
->
proplist
;
*
pp
;
pp
=
&
((
*
pp
)
->
next
))
if
(
streq
((
*
pp
)
->
name
,
"name"
))
{
prop
=
*
pp
;
break
;
}
if
(
!
prop
)
return
;
/* No name property, that's fine */
if
((
prop
->
val
.
len
!=
node
->
basenamelen
+
1
)
||
(
memcmp
(
prop
->
val
.
val
,
node
->
name
,
node
->
basenamelen
)
!=
0
))
{
FAIL
(
c
,
dti
,
node
,
"
\"
name
\"
property is incorrect (
\"
%s
\"
instead"
" of base node name)"
,
prop
->
val
.
val
);
}
else
{
/* The name property is correct, and therefore redundant.
* Delete it */
*
pp
=
prop
->
next
;
free
(
prop
->
name
);
data_free
(
prop
->
val
);
free
(
prop
);
}
}
ERROR_IF_NOT_STRING
(
name_is_string
,
"name"
);
ERROR
(
name_properties
,
check_name_properties
,
NULL
,
&
name_is_string
);
/*
* Reference fixup functions
*/
static
void
fixup_phandle_references
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
node
*
dt
=
dti
->
dt
;
struct
property
*
prop
;
for_each_property
(
node
,
prop
)
{
struct
marker
*
m
=
prop
->
val
.
markers
;
struct
node
*
refnode
;
cell_t
phandle
;
for_each_marker_of_type
(
m
,
REF_PHANDLE
)
{
assert
(
m
->
offset
+
sizeof
(
cell_t
)
<=
prop
->
val
.
len
);
refnode
=
get_node_by_ref
(
dt
,
m
->
ref
);
if
(
!
refnode
)
{
if
(
!
(
dti
->
dtsflags
&
DTSF_PLUGIN
))
FAIL
(
c
,
dti
,
node
,
"Reference to non-existent node or "
"label
\"
%s
\"\n
"
,
m
->
ref
);
else
/* mark the entry as unresolved */
*
((
fdt32_t
*
)(
prop
->
val
.
val
+
m
->
offset
))
=
cpu_to_fdt32
(
0xffffffff
);
continue
;
}
phandle
=
get_node_phandle
(
dt
,
refnode
);
*
((
fdt32_t
*
)(
prop
->
val
.
val
+
m
->
offset
))
=
cpu_to_fdt32
(
phandle
);
}
}
}
ERROR
(
phandle_references
,
fixup_phandle_references
,
NULL
,
&
duplicate_node_names
,
&
explicit_phandles
);
static
void
fixup_path_references
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
node
*
dt
=
dti
->
dt
;
struct
property
*
prop
;
for_each_property
(
node
,
prop
)
{
struct
marker
*
m
=
prop
->
val
.
markers
;
struct
node
*
refnode
;
char
*
path
;
for_each_marker_of_type
(
m
,
REF_PATH
)
{
assert
(
m
->
offset
<=
prop
->
val
.
len
);
refnode
=
get_node_by_ref
(
dt
,
m
->
ref
);
if
(
!
refnode
)
{
FAIL
(
c
,
dti
,
node
,
"Reference to non-existent node or label
\"
%s
\"\n
"
,
m
->
ref
);
continue
;
}
path
=
refnode
->
fullpath
;
prop
->
val
=
data_insert_at_marker
(
prop
->
val
,
m
,
path
,
strlen
(
path
)
+
1
);
}
}
}
ERROR
(
path_references
,
fixup_path_references
,
NULL
,
&
duplicate_node_names
);
/*
* Semantic checks
*/
WARNING_IF_NOT_CELL
(
address_cells_is_cell
,
"#address-cells"
);
WARNING_IF_NOT_CELL
(
size_cells_is_cell
,
"#size-cells"
);
WARNING_IF_NOT_CELL
(
interrupt_cells_is_cell
,
"#interrupt-cells"
);
WARNING_IF_NOT_STRING
(
device_type_is_string
,
"device_type"
);
WARNING_IF_NOT_STRING
(
model_is_string
,
"model"
);
WARNING_IF_NOT_STRING
(
status_is_string
,
"status"
);
WARNING_IF_NOT_STRING
(
label_is_string
,
"label"
);
WARNING_IF_NOT_STRING_LIST
(
compatible_is_string_list
,
"compatible"
);
static
void
check_names_is_string_list
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
for_each_property
(
node
,
prop
)
{
const
char
*
s
=
strrchr
(
prop
->
name
,
'-'
);
if
(
!
s
||
!
streq
(
s
,
"-names"
))
continue
;
c
->
data
=
prop
->
name
;
check_is_string_list
(
c
,
dti
,
node
);
}
}
WARNING
(
names_is_string_list
,
check_names_is_string_list
,
NULL
);
static
void
check_alias_paths
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
if
(
!
streq
(
node
->
name
,
"aliases"
))
return
;
for_each_property
(
node
,
prop
)
{
if
(
!
prop
->
val
.
val
||
!
get_node_by_path
(
dti
->
dt
,
prop
->
val
.
val
))
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"aliases property is not a valid node (%s)"
,
prop
->
val
.
val
);
continue
;
}
if
(
strspn
(
prop
->
name
,
LOWERCASE
DIGITS
"-"
)
!=
strlen
(
prop
->
name
))
FAIL
(
c
,
dti
,
node
,
"aliases property name must include only lowercase and '-'"
);
}
}
WARNING
(
alias_paths
,
check_alias_paths
,
NULL
);
static
void
fixup_addr_size_cells
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
node
->
addr_cells
=
-
1
;
node
->
size_cells
=
-
1
;
prop
=
get_property
(
node
,
"#address-cells"
);
if
(
prop
)
node
->
addr_cells
=
propval_cell
(
prop
);
prop
=
get_property
(
node
,
"#size-cells"
);
if
(
prop
)
node
->
size_cells
=
propval_cell
(
prop
);
}
WARNING
(
addr_size_cells
,
fixup_addr_size_cells
,
NULL
,
&
address_cells_is_cell
,
&
size_cells_is_cell
);
#define node_addr_cells(n) \
(((n)->addr_cells == -1) ? 2 : (n)->addr_cells)
#define node_size_cells(n) \
(((n)->size_cells == -1) ? 1 : (n)->size_cells)
static
void
check_reg_format
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
int
addr_cells
,
size_cells
,
entrylen
;
prop
=
get_property
(
node
,
"reg"
);
if
(
!
prop
)
return
;
/* No "reg", that's fine */
if
(
!
node
->
parent
)
{
FAIL
(
c
,
dti
,
node
,
"Root node has a
\"
reg
\"
property"
);
return
;
}
if
(
prop
->
val
.
len
==
0
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"property is empty"
);
addr_cells
=
node_addr_cells
(
node
->
parent
);
size_cells
=
node_size_cells
(
node
->
parent
);
entrylen
=
(
addr_cells
+
size_cells
)
*
sizeof
(
cell_t
);
if
(
!
entrylen
||
(
prop
->
val
.
len
%
entrylen
)
!=
0
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"property has invalid length (%d bytes) "
"(#address-cells == %d, #size-cells == %d)"
,
prop
->
val
.
len
,
addr_cells
,
size_cells
);
}
WARNING
(
reg_format
,
check_reg_format
,
NULL
,
&
addr_size_cells
);
static
void
check_ranges_format
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
int
c_addr_cells
,
p_addr_cells
,
c_size_cells
,
p_size_cells
,
entrylen
;
prop
=
get_property
(
node
,
"ranges"
);
if
(
!
prop
)
return
;
if
(
!
node
->
parent
)
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"Root node has a
\"
ranges
\"
property"
);
return
;
}
p_addr_cells
=
node_addr_cells
(
node
->
parent
);
p_size_cells
=
node_size_cells
(
node
->
parent
);
c_addr_cells
=
node_addr_cells
(
node
);
c_size_cells
=
node_size_cells
(
node
);
entrylen
=
(
p_addr_cells
+
c_addr_cells
+
c_size_cells
)
*
sizeof
(
cell_t
);
if
(
prop
->
val
.
len
==
0
)
{
if
(
p_addr_cells
!=
c_addr_cells
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"empty
\"
ranges
\"
property but its "
"#address-cells (%d) differs from %s (%d)"
,
c_addr_cells
,
node
->
parent
->
fullpath
,
p_addr_cells
);
if
(
p_size_cells
!=
c_size_cells
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"empty
\"
ranges
\"
property but its "
"#size-cells (%d) differs from %s (%d)"
,
c_size_cells
,
node
->
parent
->
fullpath
,
p_size_cells
);
}
else
if
((
prop
->
val
.
len
%
entrylen
)
!=
0
)
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"
\"
ranges
\"
property has invalid length (%d bytes) "
"(parent #address-cells == %d, child #address-cells == %d, "
"#size-cells == %d)"
,
prop
->
val
.
len
,
p_addr_cells
,
c_addr_cells
,
c_size_cells
);
}
}
WARNING
(
ranges_format
,
check_ranges_format
,
NULL
,
&
addr_size_cells
);
static
const
struct
bus_type
pci_bus
=
{
.
name
=
"PCI"
,
};
static
void
check_pci_bridge
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
cell_t
*
cells
;
prop
=
get_property
(
node
,
"device_type"
);
if
(
!
prop
||
!
streq
(
prop
->
val
.
val
,
"pci"
))
return
;
node
->
bus
=
&
pci_bus
;
if
(
!
strprefixeq
(
node
->
name
,
node
->
basenamelen
,
"pci"
)
&&
!
strprefixeq
(
node
->
name
,
node
->
basenamelen
,
"pcie"
))
FAIL
(
c
,
dti
,
node
,
"node name is not
\"
pci
\"
or
\"
pcie
\"
"
);
prop
=
get_property
(
node
,
"ranges"
);
if
(
!
prop
)
FAIL
(
c
,
dti
,
node
,
"missing ranges for PCI bridge (or not a bridge)"
);
if
(
node_addr_cells
(
node
)
!=
3
)
FAIL
(
c
,
dti
,
node
,
"incorrect #address-cells for PCI bridge"
);
if
(
node_size_cells
(
node
)
!=
2
)
FAIL
(
c
,
dti
,
node
,
"incorrect #size-cells for PCI bridge"
);
prop
=
get_property
(
node
,
"bus-range"
);
if
(
!
prop
)
{
FAIL
(
c
,
dti
,
node
,
"missing bus-range for PCI bridge"
);
return
;
}
if
(
prop
->
val
.
len
!=
(
sizeof
(
cell_t
)
*
2
))
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"value must be 2 cells"
);
return
;
}
cells
=
(
cell_t
*
)
prop
->
val
.
val
;
if
(
fdt32_to_cpu
(
cells
[
0
])
>
fdt32_to_cpu
(
cells
[
1
]))
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"1st cell must be less than or equal to 2nd cell"
);
if
(
fdt32_to_cpu
(
cells
[
1
])
>
0xff
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"maximum bus number must be less than 256"
);
}
WARNING
(
pci_bridge
,
check_pci_bridge
,
NULL
,
&
device_type_is_string
,
&
addr_size_cells
);
static
void
check_pci_device_bus_num
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
unsigned
int
bus_num
,
min_bus
,
max_bus
;
cell_t
*
cells
;
if
(
!
node
->
parent
||
(
node
->
parent
->
bus
!=
&
pci_bus
))
return
;
prop
=
get_property
(
node
,
"reg"
);
if
(
!
prop
)
return
;
cells
=
(
cell_t
*
)
prop
->
val
.
val
;
bus_num
=
(
fdt32_to_cpu
(
cells
[
0
])
&
0x00ff0000
)
>>
16
;
prop
=
get_property
(
node
->
parent
,
"bus-range"
);
if
(
!
prop
)
{
min_bus
=
max_bus
=
0
;
}
else
{
cells
=
(
cell_t
*
)
prop
->
val
.
val
;
min_bus
=
fdt32_to_cpu
(
cells
[
0
]);
max_bus
=
fdt32_to_cpu
(
cells
[
0
]);
}
if
((
bus_num
<
min_bus
)
||
(
bus_num
>
max_bus
))
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"PCI bus number %d out of range, expected (%d - %d)"
,
bus_num
,
min_bus
,
max_bus
);
}
WARNING
(
pci_device_bus_num
,
check_pci_device_bus_num
,
NULL
,
&
reg_format
,
&
pci_bridge
);
static
void
check_pci_device_reg
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
const
char
*
unitname
=
get_unitname
(
node
);
char
unit_addr
[
5
];
unsigned
int
dev
,
func
,
reg
;
cell_t
*
cells
;
if
(
!
node
->
parent
||
(
node
->
parent
->
bus
!=
&
pci_bus
))
return
;
prop
=
get_property
(
node
,
"reg"
);
if
(
!
prop
)
{
FAIL
(
c
,
dti
,
node
,
"missing PCI reg property"
);
return
;
}
cells
=
(
cell_t
*
)
prop
->
val
.
val
;
if
(
cells
[
1
]
||
cells
[
2
])
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"PCI reg config space address cells 2 and 3 must be 0"
);
reg
=
fdt32_to_cpu
(
cells
[
0
]);
dev
=
(
reg
&
0xf800
)
>>
11
;
func
=
(
reg
&
0x700
)
>>
8
;
if
(
reg
&
0xff000000
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"PCI reg address is not configuration space"
);
if
(
reg
&
0x000000ff
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"PCI reg config space address register number must be 0"
);
if
(
func
==
0
)
{
snprintf
(
unit_addr
,
sizeof
(
unit_addr
),
"%x"
,
dev
);
if
(
streq
(
unitname
,
unit_addr
))
return
;
}
snprintf
(
unit_addr
,
sizeof
(
unit_addr
),
"%x,%x"
,
dev
,
func
);
if
(
streq
(
unitname
,
unit_addr
))
return
;
FAIL
(
c
,
dti
,
node
,
"PCI unit address format error, expected
\"
%s
\"
"
,
unit_addr
);
}
WARNING
(
pci_device_reg
,
check_pci_device_reg
,
NULL
,
&
reg_format
,
&
pci_bridge
);
static
const
struct
bus_type
simple_bus
=
{
.
name
=
"simple-bus"
,
};
static
bool
node_is_compatible
(
struct
node
*
node
,
const
char
*
compat
)
{
struct
property
*
prop
;
const
char
*
str
,
*
end
;
prop
=
get_property
(
node
,
"compatible"
);
if
(
!
prop
)
return
false
;
for
(
str
=
prop
->
val
.
val
,
end
=
str
+
prop
->
val
.
len
;
str
<
end
;
str
+=
strnlen
(
str
,
end
-
str
)
+
1
)
{
if
(
strprefixeq
(
str
,
end
-
str
,
compat
))
return
true
;
}
return
false
;
}
static
void
check_simple_bus_bridge
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
if
(
node_is_compatible
(
node
,
"simple-bus"
))
node
->
bus
=
&
simple_bus
;
}
WARNING
(
simple_bus_bridge
,
check_simple_bus_bridge
,
NULL
,
&
addr_size_cells
);
static
void
check_simple_bus_reg
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
const
char
*
unitname
=
get_unitname
(
node
);
char
unit_addr
[
17
];
unsigned
int
size
;
uint64_t
reg
=
0
;
cell_t
*
cells
=
NULL
;
if
(
!
node
->
parent
||
(
node
->
parent
->
bus
!=
&
simple_bus
))
return
;
prop
=
get_property
(
node
,
"reg"
);
if
(
prop
)
cells
=
(
cell_t
*
)
prop
->
val
.
val
;
else
{
prop
=
get_property
(
node
,
"ranges"
);
if
(
prop
&&
prop
->
val
.
len
)
/* skip of child address */
cells
=
((
cell_t
*
)
prop
->
val
.
val
)
+
node_addr_cells
(
node
);
}
if
(
!
cells
)
{
if
(
node
->
parent
->
parent
&&
!
(
node
->
bus
==
&
simple_bus
))
FAIL
(
c
,
dti
,
node
,
"missing or empty reg/ranges property"
);
return
;
}
size
=
node_addr_cells
(
node
->
parent
);
while
(
size
--
)
reg
=
(
reg
<<
32
)
|
fdt32_to_cpu
(
*
(
cells
++
));
snprintf
(
unit_addr
,
sizeof
(
unit_addr
),
"%"
PRIx64
,
reg
);
if
(
!
streq
(
unitname
,
unit_addr
))
FAIL
(
c
,
dti
,
node
,
"simple-bus unit address format error, expected
\"
%s
\"
"
,
unit_addr
);
}
WARNING
(
simple_bus_reg
,
check_simple_bus_reg
,
NULL
,
&
reg_format
,
&
simple_bus_bridge
);
static
void
check_unit_address_format
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
const
char
*
unitname
=
get_unitname
(
node
);
if
(
node
->
parent
&&
node
->
parent
->
bus
)
return
;
if
(
!
unitname
[
0
])
return
;
if
(
!
strncmp
(
unitname
,
"0x"
,
2
))
{
FAIL
(
c
,
dti
,
node
,
"unit name should not have leading
\"
0x
\"
"
);
/* skip over 0x for next test */
unitname
+=
2
;
}
if
(
unitname
[
0
]
==
'0'
&&
isxdigit
(
unitname
[
1
]))
FAIL
(
c
,
dti
,
node
,
"unit name should not have leading 0s"
);
}
WARNING
(
unit_address_format
,
check_unit_address_format
,
NULL
,
&
node_name_format
,
&
pci_bridge
,
&
simple_bus_bridge
);
/*
* Style checks
*/
static
void
check_avoid_default_addr_size
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
reg
,
*
ranges
;
if
(
!
node
->
parent
)
return
;
/* Ignore root node */
reg
=
get_property
(
node
,
"reg"
);
ranges
=
get_property
(
node
,
"ranges"
);
if
(
!
reg
&&
!
ranges
)
return
;
if
(
node
->
parent
->
addr_cells
==
-
1
)
FAIL
(
c
,
dti
,
node
,
"Relying on default #address-cells value"
);
if
(
node
->
parent
->
size_cells
==
-
1
)
FAIL
(
c
,
dti
,
node
,
"Relying on default #size-cells value"
);
}
WARNING
(
avoid_default_addr_size
,
check_avoid_default_addr_size
,
NULL
,
&
addr_size_cells
);
static
void
check_avoid_unnecessary_addr_size
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
struct
node
*
child
;
bool
has_reg
=
false
;
if
(
!
node
->
parent
||
node
->
addr_cells
<
0
||
node
->
size_cells
<
0
)
return
;
if
(
get_property
(
node
,
"ranges"
)
||
!
node
->
children
)
return
;
for_each_child
(
node
,
child
)
{
prop
=
get_property
(
child
,
"reg"
);
if
(
prop
)
has_reg
=
true
;
}
if
(
!
has_reg
)
FAIL
(
c
,
dti
,
node
,
"unnecessary #address-cells/#size-cells without
\"
ranges
\"
or child
\"
reg
\"
property"
);
}
WARNING
(
avoid_unnecessary_addr_size
,
check_avoid_unnecessary_addr_size
,
NULL
,
&
avoid_default_addr_size
);
static
void
check_obsolete_chosen_interrupt_controller
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
node
*
dt
=
dti
->
dt
;
struct
node
*
chosen
;
struct
property
*
prop
;
if
(
node
!=
dt
)
return
;
chosen
=
get_node_by_path
(
dt
,
"/chosen"
);
if
(
!
chosen
)
return
;
prop
=
get_property
(
chosen
,
"interrupt-controller"
);
if
(
prop
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"/chosen has obsolete
\"
interrupt-controller
\"
property"
);
}
WARNING
(
obsolete_chosen_interrupt_controller
,
check_obsolete_chosen_interrupt_controller
,
NULL
);
static
void
check_chosen_node_is_root
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
if
(
!
streq
(
node
->
name
,
"chosen"
))
return
;
if
(
node
->
parent
!=
dti
->
dt
)
FAIL
(
c
,
dti
,
node
,
"chosen node must be at root node"
);
}
WARNING
(
chosen_node_is_root
,
check_chosen_node_is_root
,
NULL
);
static
void
check_chosen_node_bootargs
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
if
(
!
streq
(
node
->
name
,
"chosen"
))
return
;
prop
=
get_property
(
node
,
"bootargs"
);
if
(
!
prop
)
return
;
c
->
data
=
prop
->
name
;
check_is_string
(
c
,
dti
,
node
);
}
WARNING
(
chosen_node_bootargs
,
check_chosen_node_bootargs
,
NULL
);
static
void
check_chosen_node_stdout_path
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
if
(
!
streq
(
node
->
name
,
"chosen"
))
return
;
prop
=
get_property
(
node
,
"stdout-path"
);
if
(
!
prop
)
{
prop
=
get_property
(
node
,
"linux,stdout-path"
);
if
(
!
prop
)
return
;
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"Use 'stdout-path' instead"
);
}
c
->
data
=
prop
->
name
;
check_is_string
(
c
,
dti
,
node
);
}
WARNING
(
chosen_node_stdout_path
,
check_chosen_node_stdout_path
,
NULL
);
struct
provider
{
const
char
*
prop_name
;
const
char
*
cell_name
;
bool
optional
;
};
static
void
check_property_phandle_args
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
,
struct
property
*
prop
,
const
struct
provider
*
provider
)
{
struct
node
*
root
=
dti
->
dt
;
int
cell
,
cellsize
=
0
;
if
(
prop
->
val
.
len
%
sizeof
(
cell_t
))
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"property size (%d) is invalid, expected multiple of %zu"
,
prop
->
val
.
len
,
sizeof
(
cell_t
));
return
;
}
for
(
cell
=
0
;
cell
<
prop
->
val
.
len
/
sizeof
(
cell_t
);
cell
+=
cellsize
+
1
)
{
struct
node
*
provider_node
;
struct
property
*
cellprop
;
int
phandle
;
phandle
=
propval_cell_n
(
prop
,
cell
);
/*
* Some bindings use a cell value 0 or -1 to skip over optional
* entries when each index position has a specific definition.
*/
if
(
phandle
==
0
||
phandle
==
-
1
)
{
/* Give up if this is an overlay with external references */
if
(
dti
->
dtsflags
&
DTSF_PLUGIN
)
break
;
cellsize
=
0
;
continue
;
}
/* If we have markers, verify the current cell is a phandle */
if
(
prop
->
val
.
markers
)
{
struct
marker
*
m
=
prop
->
val
.
markers
;
for_each_marker_of_type
(
m
,
REF_PHANDLE
)
{
if
(
m
->
offset
==
(
cell
*
sizeof
(
cell_t
)))
break
;
}
if
(
!
m
)
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"cell %d is not a phandle reference"
,
cell
);
}
provider_node
=
get_node_by_phandle
(
root
,
phandle
);
if
(
!
provider_node
)
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"Could not get phandle node for (cell %d)"
,
cell
);
break
;
}
cellprop
=
get_property
(
provider_node
,
provider
->
cell_name
);
if
(
cellprop
)
{
cellsize
=
propval_cell
(
cellprop
);
}
else
if
(
provider
->
optional
)
{
cellsize
=
0
;
}
else
{
FAIL
(
c
,
dti
,
node
,
"Missing property '%s' in node %s or bad phandle (referred from %s[%d])"
,
provider
->
cell_name
,
provider_node
->
fullpath
,
prop
->
name
,
cell
);
break
;
}
if
(
prop
->
val
.
len
<
((
cell
+
cellsize
+
1
)
*
sizeof
(
cell_t
)))
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"property size (%d) too small for cell size %d"
,
prop
->
val
.
len
,
cellsize
);
}
}
}
static
void
check_provider_cells_property
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
provider
*
provider
=
c
->
data
;
struct
property
*
prop
;
prop
=
get_property
(
node
,
provider
->
prop_name
);
if
(
!
prop
)
return
;
check_property_phandle_args
(
c
,
dti
,
node
,
prop
,
provider
);
}
#define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \
static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \
WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references);
WARNING_PROPERTY_PHANDLE_CELLS
(
clocks
,
"clocks"
,
"#clock-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
cooling_device
,
"cooling-device"
,
"#cooling-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
dmas
,
"dmas"
,
"#dma-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
hwlocks
,
"hwlocks"
,
"#hwlock-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
interrupts_extended
,
"interrupts-extended"
,
"#interrupt-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
io_channels
,
"io-channels"
,
"#io-channel-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
iommus
,
"iommus"
,
"#iommu-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
mboxes
,
"mboxes"
,
"#mbox-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
msi_parent
,
"msi-parent"
,
"#msi-cells"
,
true
);
WARNING_PROPERTY_PHANDLE_CELLS
(
mux_controls
,
"mux-controls"
,
"#mux-control-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
phys
,
"phys"
,
"#phy-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
power_domains
,
"power-domains"
,
"#power-domain-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
pwms
,
"pwms"
,
"#pwm-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
resets
,
"resets"
,
"#reset-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
sound_dai
,
"sound-dai"
,
"#sound-dai-cells"
);
WARNING_PROPERTY_PHANDLE_CELLS
(
thermal_sensors
,
"thermal-sensors"
,
"#thermal-sensor-cells"
);
static
bool
prop_is_gpio
(
struct
property
*
prop
)
{
char
*
str
;
/*
* *-gpios and *-gpio can appear in property names,
* so skip over any false matches (only one known ATM)
*/
if
(
strstr
(
prop
->
name
,
"nr-gpio"
))
return
false
;
str
=
strrchr
(
prop
->
name
,
'-'
);
if
(
str
)
str
++
;
else
str
=
prop
->
name
;
if
(
!
(
streq
(
str
,
"gpios"
)
||
streq
(
str
,
"gpio"
)))
return
false
;
return
true
;
}
static
void
check_gpios_property
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
/* Skip GPIO hog nodes which have 'gpios' property */
if
(
get_property
(
node
,
"gpio-hog"
))
return
;
for_each_property
(
node
,
prop
)
{
struct
provider
provider
;
if
(
!
prop_is_gpio
(
prop
))
continue
;
provider
.
prop_name
=
prop
->
name
;
provider
.
cell_name
=
"#gpio-cells"
;
provider
.
optional
=
false
;
check_property_phandle_args
(
c
,
dti
,
node
,
prop
,
&
provider
);
}
}
WARNING
(
gpios_property
,
check_gpios_property
,
NULL
,
&
phandle_references
);
static
void
check_deprecated_gpio_property
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
property
*
prop
;
for_each_property
(
node
,
prop
)
{
char
*
str
;
if
(
!
prop_is_gpio
(
prop
))
continue
;
str
=
strstr
(
prop
->
name
,
"gpio"
);
if
(
!
streq
(
str
,
"gpio"
))
continue
;
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"'[*-]gpio' is deprecated, use '[*-]gpios' instead"
);
}
}
CHECK
(
deprecated_gpio_property
,
check_deprecated_gpio_property
,
NULL
);
static
bool
node_is_interrupt_provider
(
struct
node
*
node
)
{
struct
property
*
prop
;
prop
=
get_property
(
node
,
"interrupt-controller"
);
if
(
prop
)
return
true
;
prop
=
get_property
(
node
,
"interrupt-map"
);
if
(
prop
)
return
true
;
return
false
;
}
static
void
check_interrupts_property
(
struct
check
*
c
,
struct
dt_info
*
dti
,
struct
node
*
node
)
{
struct
node
*
root
=
dti
->
dt
;
struct
node
*
irq_node
=
NULL
,
*
parent
=
node
;
struct
property
*
irq_prop
,
*
prop
=
NULL
;
int
irq_cells
,
phandle
;
irq_prop
=
get_property
(
node
,
"interrupts"
);
if
(
!
irq_prop
)
return
;
if
(
irq_prop
->
val
.
len
%
sizeof
(
cell_t
))
FAIL_PROP
(
c
,
dti
,
node
,
irq_prop
,
"size (%d) is invalid, expected multiple of %zu"
,
irq_prop
->
val
.
len
,
sizeof
(
cell_t
));
while
(
parent
&&
!
prop
)
{
if
(
parent
!=
node
&&
node_is_interrupt_provider
(
parent
))
{
irq_node
=
parent
;
break
;
}
prop
=
get_property
(
parent
,
"interrupt-parent"
);
if
(
prop
)
{
phandle
=
propval_cell
(
prop
);
/* Give up if this is an overlay with external references */
if
((
phandle
==
0
||
phandle
==
-
1
)
&&
(
dti
->
dtsflags
&
DTSF_PLUGIN
))
return
;
irq_node
=
get_node_by_phandle
(
root
,
phandle
);
if
(
!
irq_node
)
{
FAIL_PROP
(
c
,
dti
,
parent
,
prop
,
"Bad phandle"
);
return
;
}
if
(
!
node_is_interrupt_provider
(
irq_node
))
FAIL
(
c
,
dti
,
irq_node
,
"Missing interrupt-controller or interrupt-map property"
);
break
;
}
parent
=
parent
->
parent
;
}
if
(
!
irq_node
)
{
FAIL
(
c
,
dti
,
node
,
"Missing interrupt-parent"
);
return
;
}
prop
=
get_property
(
irq_node
,
"#interrupt-cells"
);
if
(
!
prop
)
{
FAIL
(
c
,
dti
,
irq_node
,
"Missing #interrupt-cells in interrupt-parent"
);
return
;
}
irq_cells
=
propval_cell
(
prop
);
if
(
irq_prop
->
val
.
len
%
(
irq_cells
*
sizeof
(
cell_t
)))
{
FAIL_PROP
(
c
,
dti
,
node
,
prop
,
"size is (%d), expected multiple of %d"
,
irq_prop
->
val
.
len
,
(
int
)(
irq_cells
*
sizeof
(
cell_t
)));
}
}
WARNING
(
interrupts_property
,
check_interrupts_property
,
&
phandle_references
);
static
struct
check
*
check_table
[]
=
{
&
duplicate_node_names
,
&
duplicate_property_names
,
&
node_name_chars
,
&
node_name_format
,
&
property_name_chars
,
&
name_is_string
,
&
name_properties
,
&
duplicate_label
,
&
explicit_phandles
,
&
phandle_references
,
&
path_references
,
&
address_cells_is_cell
,
&
size_cells_is_cell
,
&
interrupt_cells_is_cell
,
&
device_type_is_string
,
&
model_is_string
,
&
status_is_string
,
&
label_is_string
,
&
compatible_is_string_list
,
&
names_is_string_list
,
&
property_name_chars_strict
,
&
node_name_chars_strict
,
&
addr_size_cells
,
&
reg_format
,
&
ranges_format
,
&
unit_address_vs_reg
,
&
unit_address_format
,
&
pci_bridge
,
&
pci_device_reg
,
&
pci_device_bus_num
,
&
simple_bus_bridge
,
&
simple_bus_reg
,
&
avoid_default_addr_size
,
&
avoid_unnecessary_addr_size
,
&
obsolete_chosen_interrupt_controller
,
&
chosen_node_is_root
,
&
chosen_node_bootargs
,
&
chosen_node_stdout_path
,
&
clocks_property
,
&
cooling_device_property
,
&
dmas_property
,
&
hwlocks_property
,
&
interrupts_extended_property
,
&
io_channels_property
,
&
iommus_property
,
&
mboxes_property
,
&
msi_parent_property
,
&
mux_controls_property
,
&
phys_property
,
&
power_domains_property
,
&
pwms_property
,
&
resets_property
,
&
sound_dai_property
,
&
thermal_sensors_property
,
&
deprecated_gpio_property
,
&
gpios_property
,
&
interrupts_property
,
&
alias_paths
,
&
always_fail
,
};
static
void
enable_warning_error
(
struct
check
*
c
,
bool
warn
,
bool
error
)
{
int
i
;
/* Raising level, also raise it for prereqs */
if
((
warn
&&
!
c
->
warn
)
||
(
error
&&
!
c
->
error
))
for
(
i
=
0
;
i
<
c
->
num_prereqs
;
i
++
)
enable_warning_error
(
c
->
prereq
[
i
],
warn
,
error
);
c
->
warn
=
c
->
warn
||
warn
;
c
->
error
=
c
->
error
||
error
;
}
static
void
disable_warning_error
(
struct
check
*
c
,
bool
warn
,
bool
error
)
{
int
i
;
/* Lowering level, also lower it for things this is the prereq
* for */
if
((
warn
&&
c
->
warn
)
||
(
error
&&
c
->
error
))
{
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
check_table
);
i
++
)
{
struct
check
*
cc
=
check_table
[
i
];
int
j
;
for
(
j
=
0
;
j
<
cc
->
num_prereqs
;
j
++
)
if
(
cc
->
prereq
[
j
]
==
c
)
disable_warning_error
(
cc
,
warn
,
error
);
}
}
c
->
warn
=
c
->
warn
&&
!
warn
;
c
->
error
=
c
->
error
&&
!
error
;
}
void
parse_checks_option
(
bool
warn
,
bool
error
,
const
char
*
arg
)
{
int
i
;
const
char
*
name
=
arg
;
bool
enable
=
true
;
if
((
strncmp
(
arg
,
"no-"
,
3
)
==
0
)
||
(
strncmp
(
arg
,
"no_"
,
3
)
==
0
))
{
name
=
arg
+
3
;
enable
=
false
;
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
check_table
);
i
++
)
{
struct
check
*
c
=
check_table
[
i
];
if
(
streq
(
c
->
name
,
name
))
{
if
(
enable
)
enable_warning_error
(
c
,
warn
,
error
);
else
disable_warning_error
(
c
,
warn
,
error
);
return
;
}
}
die
(
"Unrecognized check name
\"
%s
\"\n
"
,
name
);
}
void
process_checks
(
bool
force
,
struct
dt_info
*
dti
)
{
int
i
;
int
error
=
0
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
check_table
);
i
++
)
{
struct
check
*
c
=
check_table
[
i
];
if
(
c
->
warn
||
c
->
error
)
error
=
error
||
run_check
(
c
,
dti
);
}
if
(
error
)
{
if
(
!
force
)
{
fprintf
(
stderr
,
"ERROR: Input tree has errors, aborting "
"(use -f to force output)
\n
"
);
exit
(
2
);
}
else
if
(
quiet
<
3
)
{
fprintf
(
stderr
,
"Warning: Input tree has errors, "
"output forced
\n
"
);
}
}
}
u-boot-tree/scripts/dtc/data.c
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
void
data_free
(
struct
data
d
)
{
struct
marker
*
m
,
*
nm
;
m
=
d
.
markers
;
while
(
m
)
{
nm
=
m
->
next
;
free
(
m
->
ref
);
free
(
m
);
m
=
nm
;
}
if
(
d
.
val
)
free
(
d
.
val
);
}
struct
data
data_grow_for
(
struct
data
d
,
int
xlen
)
{
struct
data
nd
;
int
newsize
;
if
(
xlen
==
0
)
return
d
;
nd
=
d
;
newsize
=
xlen
;
while
((
d
.
len
+
xlen
)
>
newsize
)
newsize
*=
2
;
nd
.
val
=
xrealloc
(
d
.
val
,
newsize
);
return
nd
;
}
struct
data
data_copy_mem
(
const
char
*
mem
,
int
len
)
{
struct
data
d
;
d
=
data_grow_for
(
empty_data
,
len
);
d
.
len
=
len
;
memcpy
(
d
.
val
,
mem
,
len
);
return
d
;
}
struct
data
data_copy_escape_string
(
const
char
*
s
,
int
len
)
{
int
i
=
0
;
struct
data
d
;
char
*
q
;
d
=
data_grow_for
(
empty_data
,
len
+
1
);
q
=
d
.
val
;
while
(
i
<
len
)
{
char
c
=
s
[
i
++
];
if
(
c
==
'\\'
)
c
=
get_escape_char
(
s
,
&
i
);
q
[
d
.
len
++
]
=
c
;
}
q
[
d
.
len
++
]
=
'\0'
;
return
d
;
}
struct
data
data_copy_file
(
FILE
*
f
,
size_t
maxlen
)
{
struct
data
d
=
empty_data
;
while
(
!
feof
(
f
)
&&
(
d
.
len
<
maxlen
))
{
size_t
chunksize
,
ret
;
if
(
maxlen
==
-
1
)
chunksize
=
4096
;
else
chunksize
=
maxlen
-
d
.
len
;
d
=
data_grow_for
(
d
,
chunksize
);
ret
=
fread
(
d
.
val
+
d
.
len
,
1
,
chunksize
,
f
);
if
(
ferror
(
f
))
die
(
"Error reading file into data: %s"
,
strerror
(
errno
));
if
(
d
.
len
+
ret
<
d
.
len
)
die
(
"Overflow reading file into data
\n
"
);
d
.
len
+=
ret
;
}
return
d
;
}
struct
data
data_append_data
(
struct
data
d
,
const
void
*
p
,
int
len
)
{
d
=
data_grow_for
(
d
,
len
);
memcpy
(
d
.
val
+
d
.
len
,
p
,
len
);
d
.
len
+=
len
;
return
d
;
}
struct
data
data_insert_at_marker
(
struct
data
d
,
struct
marker
*
m
,
const
void
*
p
,
int
len
)
{
d
=
data_grow_for
(
d
,
len
);
memmove
(
d
.
val
+
m
->
offset
+
len
,
d
.
val
+
m
->
offset
,
d
.
len
-
m
->
offset
);
memcpy
(
d
.
val
+
m
->
offset
,
p
,
len
);
d
.
len
+=
len
;
/* Adjust all markers after the one we're inserting at */
m
=
m
->
next
;
for_each_marker
(
m
)
m
->
offset
+=
len
;
return
d
;
}
static
struct
data
data_append_markers
(
struct
data
d
,
struct
marker
*
m
)
{
struct
marker
**
mp
=
&
d
.
markers
;
/* Find the end of the markerlist */
while
(
*
mp
)
mp
=
&
((
*
mp
)
->
next
);
*
mp
=
m
;
return
d
;
}
struct
data
data_merge
(
struct
data
d1
,
struct
data
d2
)
{
struct
data
d
;
struct
marker
*
m2
=
d2
.
markers
;
d
=
data_append_markers
(
data_append_data
(
d1
,
d2
.
val
,
d2
.
len
),
m2
);
/* Adjust for the length of d1 */
for_each_marker
(
m2
)
m2
->
offset
+=
d1
.
len
;
d2
.
markers
=
NULL
;
/* So data_free() doesn't clobber them */
data_free
(
d2
);
return
d
;
}
struct
data
data_append_integer
(
struct
data
d
,
uint64_t
value
,
int
bits
)
{
uint8_t
value_8
;
fdt16_t
value_16
;
fdt32_t
value_32
;
fdt64_t
value_64
;
switch
(
bits
)
{
case
8
:
value_8
=
value
;
return
data_append_data
(
d
,
&
value_8
,
1
);
case
16
:
value_16
=
cpu_to_fdt16
(
value
);
return
data_append_data
(
d
,
&
value_16
,
2
);
case
32
:
value_32
=
cpu_to_fdt32
(
value
);
return
data_append_data
(
d
,
&
value_32
,
4
);
case
64
:
value_64
=
cpu_to_fdt64
(
value
);
return
data_append_data
(
d
,
&
value_64
,
8
);
default:
die
(
"Invalid literal size (%d)
\n
"
,
bits
);
}
}
struct
data
data_append_re
(
struct
data
d
,
uint64_t
address
,
uint64_t
size
)
{
struct
fdt_reserve_entry
re
;
re
.
address
=
cpu_to_fdt64
(
address
);
re
.
size
=
cpu_to_fdt64
(
size
);
return
data_append_data
(
d
,
&
re
,
sizeof
(
re
));
}
struct
data
data_append_cell
(
struct
data
d
,
cell_t
word
)
{
return
data_append_integer
(
d
,
word
,
sizeof
(
word
)
*
8
);
}
struct
data
data_append_addr
(
struct
data
d
,
uint64_t
addr
)
{
return
data_append_integer
(
d
,
addr
,
sizeof
(
addr
)
*
8
);
}
struct
data
data_append_byte
(
struct
data
d
,
uint8_t
byte
)
{
return
data_append_data
(
d
,
&
byte
,
1
);
}
struct
data
data_append_zeroes
(
struct
data
d
,
int
len
)
{
d
=
data_grow_for
(
d
,
len
);
memset
(
d
.
val
+
d
.
len
,
0
,
len
);
d
.
len
+=
len
;
return
d
;
}
struct
data
data_append_align
(
struct
data
d
,
int
align
)
{
int
newlen
=
ALIGN
(
d
.
len
,
align
);
return
data_append_zeroes
(
d
,
newlen
-
d
.
len
);
}
struct
data
data_add_marker
(
struct
data
d
,
enum
markertype
type
,
char
*
ref
)
{
struct
marker
*
m
;
m
=
xmalloc
(
sizeof
(
*
m
));
m
->
offset
=
d
.
len
;
m
->
type
=
type
;
m
->
ref
=
ref
;
m
->
next
=
NULL
;
return
data_append_markers
(
d
,
m
);
}
bool
data_is_one_string
(
struct
data
d
)
{
int
i
;
int
len
=
d
.
len
;
if
(
len
==
0
)
return
false
;
for
(
i
=
0
;
i
<
len
-
1
;
i
++
)
if
(
d
.
val
[
i
]
==
'\0'
)
return
false
;
if
(
d
.
val
[
len
-
1
]
!=
'\0'
)
return
false
;
return
true
;
}
u-boot-tree/scripts/dtc/dtc-lexer.l
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%option noyywrap nounput noinput never-interactive
%x BYTESTRING
%x PROPNODENAME
%s V1
PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
PATHCHAR ({PROPNODECHAR}|[/])
LABEL [a-zA-Z_][a-zA-Z0-9_]*
STRING \"([^\\"]|\\.)*\"
CHAR_LITERAL '([^']|\\')*'
WS [[:space:]]
COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
LINECOMMENT "//".*\n
%{
#include "dtc.h"
#include "srcpos.h"
#include "dtc-parser.tab.h"
YYLTYPE yylloc;
extern bool treesource_error;
/* CAUTION: this will stop working if we ever use yyless() or yyunput() */
#define YY_USER_ACTION \
{ \
srcpos_update(&yylloc, yytext, yyleng); \
}
/*#define LEXDEBUG 1*/
#ifdef LEXDEBUG
#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#else
#define DPRINT(fmt, ...) do { } while (0)
#endif
static int dts_version = 1;
#define BEGIN_DEFAULT() DPRINT("<V1>\n"); \
BEGIN(V1); \
static void push_input_file(const char *filename);
static bool pop_input_file(void);
static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
%}
%%
<*>"/include/"{WS}*{STRING} {
char *name = strchr(yytext, '\"') + 1;
yytext[yyleng-1] = '\0';
push_input_file(name);
}
<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? {
char *line, *fnstart, *fnend;
struct data fn;
/* skip text before line # */
line = yytext;
while (!isdigit((unsigned char)*line))
line++;
/* regexp ensures that first and list "
* in the whole yytext are those at
* beginning and end of the filename string */
fnstart = memchr(yytext, '"', yyleng);
for (fnend = yytext + yyleng - 1;
*fnend != '"'; fnend--)
;
assert(fnstart && fnend && (fnend > fnstart));
fn = data_copy_escape_string(fnstart + 1,
fnend - fnstart - 1);
/* Don't allow nuls in filenames */
if (memchr(fn.val, '\0', fn.len - 1))
lexical_error("nul in line number directive");
/* -1 since #line is the number of the next line */
srcpos_set_line(xstrdup(fn.val), atoi(line) - 1);
data_free(fn);
}
<*><<EOF>> {
if (!pop_input_file()) {
yyterminate();
}
}
<*>{STRING} {
DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1,
yyleng-2);
return DT_STRING;
}
<*>"/dts-v1/" {
DPRINT("Keyword: /dts-v1/\n");
dts_version = 1;
BEGIN_DEFAULT();
return DT_V1;
}
<*>"/plugin/" {
DPRINT("Keyword: /plugin/\n");
return DT_PLUGIN;
}
<*>"/memreserve/" {
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
return DT_MEMRESERVE;
}
<*>"/bits/" {
DPRINT("Keyword: /bits/\n");
BEGIN_DEFAULT();
return DT_BITS;
}
<*>"/delete-property/" {
DPRINT("Keyword: /delete-property/\n");
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
return DT_DEL_PROP;
}
<*>"/delete-node/" {
DPRINT("Keyword: /delete-node/\n");
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
return DT_DEL_NODE;
}
<*>{LABEL}: {
DPRINT("Label: %s\n", yytext);
yylval.labelref = xstrdup(yytext);
yylval.labelref[yyleng-1] = '\0';
return DT_LABEL;
}
<V1>([0-9]+|0[xX][0-9a-fA-F]+)(U|L|UL|LL|ULL)? {
char *e;
DPRINT("Integer Literal: '%s'\n", yytext);
errno = 0;
yylval.integer = strtoull(yytext, &e, 0);
if (*e && e[strspn(e, "UL")]) {
lexical_error("Bad integer literal '%s'",
yytext);
}
if (errno == ERANGE)
lexical_error("Integer literal '%s' out of range",
yytext);
else
/* ERANGE is the only strtoull error triggerable
* by strings matching the pattern */
assert(errno == 0);
return DT_LITERAL;
}
<*>{CHAR_LITERAL} {
struct data d;
DPRINT("Character literal: %s\n", yytext);
d = data_copy_escape_string(yytext+1, yyleng-2);
if (d.len == 1) {
lexical_error("Empty character literal");
yylval.integer = 0;
} else {
yylval.integer = (unsigned char)d.val[0];
if (d.len > 2)
lexical_error("Character literal has %d"
" characters instead of 1",
d.len - 1);
}
data_free(d);
return DT_CHAR_LITERAL;
}
<*>\&{LABEL} { /* label reference */
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = xstrdup(yytext+1);
return DT_REF;
}
<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
yylval.labelref = xstrdup(yytext+2);
return DT_REF;
}
<BYTESTRING>[0-9a-fA-F]{2} {
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE;
}
<BYTESTRING>"]" {
DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT();
return ']';
}
<PROPNODENAME>\\?{PROPNODECHAR}+ {
DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = xstrdup((yytext[0] == '\\') ?
yytext + 1 : yytext);
BEGIN_DEFAULT();
return DT_PROPNODENAME;
}
"/incbin/" {
DPRINT("Binary Include\n");
return DT_INCBIN;
}
<*>{WS}+ /* eat whitespace */
<*>{COMMENT}+ /* eat C-style comments */
<*>{LINECOMMENT}+ /* eat C++-style comments */
<*>"<<" { return DT_LSHIFT; };
<*>">>" { return DT_RSHIFT; };
<*>"<=" { return DT_LE; };
<*>">=" { return DT_GE; };
<*>"==" { return DT_EQ; };
<*>"!=" { return DT_NE; };
<*>"&&" { return DT_AND; };
<*>"||" { return DT_OR; };
<*>. {
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
if (yytext[0] == '[') {
DPRINT("<BYTESTRING>\n");
BEGIN(BYTESTRING);
}
if ((yytext[0] == '{')
|| (yytext[0] == ';')) {
DPRINT("<PROPNODENAME>\n");
BEGIN(PROPNODENAME);
}
return yytext[0];
}
%%
static void push_input_file(const char *filename)
{
assert(filename);
srcfile_push(filename);
yyin = current_srcfile->f;
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
}
static bool pop_input_file(void)
{
if (srcfile_pop() == 0)
return false;
yypop_buffer_state();
yyin = current_srcfile->f;
return true;
}
static void lexical_error(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
srcpos_verror(&yylloc, "Lexical error", fmt, ap);
va_end(ap);
treesource_error = true;
}
u-boot-tree/scripts/dtc/dtc-parser.y
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
%{
#include <stdio.h>
#include <inttypes.h>
#include "dtc.h"
#include "srcpos.h"
extern int yylex(void);
extern void yyerror(char const *s);
#define ERROR(loc, ...) \
do { \
srcpos_error((loc), "Error", __VA_ARGS__); \
treesource_error = true; \
} while (0)
extern struct dt_info *parser_output;
extern bool treesource_error;
%}
%union {
char *propnodename;
char *labelref;
uint8_t byte;
struct data data;
struct {
struct data data;
int bits;
} array;
struct property *prop;
struct property *proplist;
struct node *node;
struct node *nodelist;
struct reserve_info *re;
uint64_t integer;
unsigned int flags;
}
%token DT_V1
%token DT_PLUGIN
%token DT_MEMRESERVE
%token DT_LSHIFT DT_RSHIFT DT_LE DT_GE DT_EQ DT_NE DT_AND DT_OR
%token DT_BITS
%token DT_DEL_PROP
%token DT_DEL_NODE
%token <propnodename> DT_PROPNODENAME
%token <integer> DT_LITERAL
%token <integer> DT_CHAR_LITERAL
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_REF
%token DT_INCBIN
%type <data> propdata
%type <data> propdataprefix
%type <flags> header
%type <flags> headers
%type <re> memreserve
%type <re> memreserves
%type <array> arrayprefix
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
%type <node> devicetree
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes
%type <integer> integer_prim
%type <integer> integer_unary
%type <integer> integer_mul
%type <integer> integer_add
%type <integer> integer_shift
%type <integer> integer_rela
%type <integer> integer_eq
%type <integer> integer_bitand
%type <integer> integer_bitxor
%type <integer> integer_bitor
%type <integer> integer_and
%type <integer> integer_or
%type <integer> integer_trinary
%type <integer> integer_expr
%%
sourcefile:
headers memreserves devicetree
{
parser_output = build_dt_info($1, $2, $3,
guess_boot_cpuid($3));
}
;
header:
DT_V1 ';'
{
$$ = DTSF_V1;
}
| DT_V1 ';' DT_PLUGIN ';'
{
$$ = DTSF_V1 | DTSF_PLUGIN;
}
;
headers:
header
| header headers
{
if ($2 != $1)
ERROR(&@2, "Header flags don't match earlier ones");
$$ = $1;
}
;
memreserves:
/* empty */
{
$$ = NULL;
}
| memreserve memreserves
{
$$ = chain_reserve_entry($1, $2);
}
;
memreserve:
DT_MEMRESERVE integer_prim integer_prim ';'
{
$$ = build_reserve_entry($2, $3);
}
| DT_LABEL memreserve
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
devicetree:
'/' nodedef
{
$$ = name_node($2, "");
}
| devicetree '/' nodedef
{
$$ = merge_nodes($1, $3);
}
| DT_REF nodedef
{
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if (!($<flags>-1 & DTSF_PLUGIN))
ERROR(&@2, "Label or path %s not found", $1);
$$ = add_orphan_node(name_node(build_node(NULL, NULL), ""), $2, $1);
}
| devicetree DT_LABEL DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $3);
if (target) {
add_label(&target->labels, $2);
merge_nodes(target, $4);
} else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
| devicetree DT_REF nodedef
{
struct node *target = get_node_by_ref($1, $2);
if (target) {
merge_nodes(target, $3);
} else {
/*
* We rely on the rule being always:
* versioninfo plugindecl memreserves devicetree
* so $-1 is what we want (plugindecl)
*/
if ($<flags>-1 & DTSF_PLUGIN)
add_orphan_node($1, $3, $2);
else
ERROR(&@2, "Label or path %s not found", $2);
}
$$ = $1;
}
| devicetree DT_DEL_NODE DT_REF ';'
{
struct node *target = get_node_by_ref($1, $3);
if (target)
delete_node(target);
else
ERROR(&@3, "Label or path %s not found", $3);
$$ = $1;
}
;
nodedef:
'{' proplist subnodes '}' ';'
{
$$ = build_node($2, $3);
}
;
proplist:
/* empty */
{
$$ = NULL;
}
| proplist propdef
{
$$ = chain_property($2, $1);
}
;
propdef:
DT_PROPNODENAME '=' propdata ';'
{
$$ = build_property($1, $3);
}
| DT_PROPNODENAME ';'
{
$$ = build_property($1, empty_data);
}
| DT_DEL_PROP DT_PROPNODENAME ';'
{
$$ = build_property_delete($2);
}
| DT_LABEL propdef
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
propdata:
propdataprefix DT_STRING
{
$$ = data_merge($1, $2);
}
| propdataprefix arrayprefix '>'
{
$$ = data_merge($1, $2.data);
}
| propdataprefix '[' bytestring ']'
{
$$ = data_merge($1, $3);
}
| propdataprefix DT_REF
{
$$ = data_add_marker($1, REF_PATH, $2);
}
| propdataprefix DT_INCBIN '(' DT_STRING ',' integer_prim ',' integer_prim ')'
{
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d;
if ($6 != 0)
if (fseek(f, $6, SEEK_SET) != 0)
die("Couldn't seek to offset %llu in \"%s\": %s",
(unsigned long long)$6, $4.val,
strerror(errno));
d = data_copy_file(f, $8);
$$ = data_merge($1, d);
fclose(f);
}
| propdataprefix DT_INCBIN '(' DT_STRING ')'
{
FILE *f = srcfile_relative_open($4.val, NULL);
struct data d = empty_data;
d = data_copy_file(f, -1);
$$ = data_merge($1, d);
fclose(f);
}
| propdata DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
propdataprefix:
/* empty */
{
$$ = empty_data;
}
| propdata ','
{
$$ = $1;
}
| propdataprefix DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
arrayprefix:
DT_BITS DT_LITERAL '<'
{
unsigned long long bits;
bits = $2;
if ((bits != 8) && (bits != 16) &&
(bits != 32) && (bits != 64)) {
ERROR(&@2, "Array elements must be"
" 8, 16, 32 or 64-bits");
bits = 32;
}
$$.data = empty_data;
$$.bits = bits;
}
| '<'
{
$$.data = empty_data;
$$.bits = 32;
}
| arrayprefix integer_prim
{
if ($1.bits < 64) {
uint64_t mask = (1ULL << $1.bits) - 1;
/*
* Bits above mask must either be all zero
* (positive within range of mask) or all one
* (negative and sign-extended). The second
* condition is true if when we set all bits
* within the mask to one (i.e. | in the
* mask), all bits are one.
*/
if (($2 > mask) && (($2 | mask) != -1ULL))
ERROR(&@2, "Value out of range for"
" %d-bit array element", $1.bits);
}
$$.data = data_append_integer($1.data, $2, $1.bits);
}
| arrayprefix DT_REF
{
uint64_t val = ~0ULL >> (64 - $1.bits);
if ($1.bits == 32)
$1.data = data_add_marker($1.data,
REF_PHANDLE,
$2);
else
ERROR(&@2, "References are only allowed in "
"arrays with 32-bit elements.");
$$.data = data_append_integer($1.data, val, $1.bits);
}
| arrayprefix DT_LABEL
{
$$.data = data_add_marker($1.data, LABEL, $2);
}
;
integer_prim:
DT_LITERAL
| DT_CHAR_LITERAL
| '(' integer_expr ')'
{
$$ = $2;
}
;
integer_expr:
integer_trinary
;
integer_trinary:
integer_or
| integer_or '?' integer_expr ':' integer_trinary { $$ = $1 ? $3 : $5; }
;
integer_or:
integer_and
| integer_or DT_OR integer_and { $$ = $1 || $3; }
;
integer_and:
integer_bitor
| integer_and DT_AND integer_bitor { $$ = $1 && $3; }
;
integer_bitor:
integer_bitxor
| integer_bitor '|' integer_bitxor { $$ = $1 | $3; }
;
integer_bitxor:
integer_bitand
| integer_bitxor '^' integer_bitand { $$ = $1 ^ $3; }
;
integer_bitand:
integer_eq
| integer_bitand '&' integer_eq { $$ = $1 & $3; }
;
integer_eq:
integer_rela
| integer_eq DT_EQ integer_rela { $$ = $1 == $3; }
| integer_eq DT_NE integer_rela { $$ = $1 != $3; }
;
integer_rela:
integer_shift
| integer_rela '<' integer_shift { $$ = $1 < $3; }
| integer_rela '>' integer_shift { $$ = $1 > $3; }
| integer_rela DT_LE integer_shift { $$ = $1 <= $3; }
| integer_rela DT_GE integer_shift { $$ = $1 >= $3; }
;
integer_shift:
integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; }
| integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; }
| integer_add
;
integer_add:
integer_add '+' integer_mul { $$ = $1 + $3; }
| integer_add '-' integer_mul { $$ = $1 - $3; }
| integer_mul
;
integer_mul:
integer_mul '*' integer_unary { $$ = $1 * $3; }
| integer_mul '/' integer_unary
{
if ($3 != 0) {
$$ = $1 / $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_mul '%' integer_unary
{
if ($3 != 0) {
$$ = $1 % $3;
} else {
ERROR(&@$, "Division by zero");
$$ = 0;
}
}
| integer_unary
;
integer_unary:
integer_prim
| '-' integer_unary { $$ = -$2; }
| '~' integer_unary { $$ = ~$2; }
| '!' integer_unary { $$ = !$2; }
;
bytestring:
/* empty */
{
$$ = empty_data;
}
| bytestring DT_BYTE
{
$$ = data_append_byte($1, $2);
}
| bytestring DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
}
;
subnodes:
/* empty */
{
$$ = NULL;
}
| subnode subnodes
{
$$ = chain_node($1, $2);
}
| subnode propdef
{
ERROR(&@2, "Properties must precede subnodes");
YYERROR;
}
;
subnode:
DT_PROPNODENAME nodedef
{
$$ = name_node($2, $1);
}
| DT_DEL_NODE DT_PROPNODENAME ';'
{
$$ = name_node(build_node_delete(), $2);
}
| DT_LABEL subnode
{
add_label(&$2->labels, $1);
$$ = $2;
}
;
%%
void yyerror(char const *s)
{
ERROR(&yylloc, "%s", s);
}
u-boot-tree/scripts/dtc/dtc.c
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <sys/stat.h>
#include "dtc.h"
#include "srcpos.h"
/*
* Command line options
*/
int
quiet
;
/* Level of quietness */
int
reservenum
;
/* Number of memory reservation slots */
int
minsize
;
/* Minimum blob size */
int
padsize
;
/* Additional padding to blob */
int
alignsize
;
/* Additional padding to blob accroding to the alignsize */
int
phandle_format
=
PHANDLE_EPAPR
;
/* Use linux,phandle or phandle properties */
int
generate_symbols
;
/* enable symbols & fixup support */
int
generate_fixups
;
/* suppress generation of fixups on symbol support */
int
auto_label_aliases
;
/* auto generate labels -> aliases */
static
int
is_power_of_2
(
int
x
)
{
return
(
x
>
0
)
&&
((
x
&
(
x
-
1
))
==
0
);
}
static
void
fill_fullpaths
(
struct
node
*
tree
,
const
char
*
prefix
)
{
struct
node
*
child
;
const
char
*
unit
;
tree
->
fullpath
=
join_path
(
prefix
,
tree
->
name
);
unit
=
strchr
(
tree
->
name
,
'@'
);
if
(
unit
)
tree
->
basenamelen
=
unit
-
tree
->
name
;
else
tree
->
basenamelen
=
strlen
(
tree
->
name
);
for_each_child
(
tree
,
child
)
fill_fullpaths
(
child
,
tree
->
fullpath
);
}
/* Usage related data. */
static
const
char
usage_synopsis
[]
=
"dtc [options] <input file>"
;
static
const
char
usage_short_opts
[]
=
"qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv"
;
static
struct
option
const
usage_long_opts
[]
=
{
{
"quiet"
,
no_argument
,
NULL
,
'q'
},
{
"in-format"
,
a_argument
,
NULL
,
'I'
},
{
"out"
,
a_argument
,
NULL
,
'o'
},
{
"out-format"
,
a_argument
,
NULL
,
'O'
},
{
"out-version"
,
a_argument
,
NULL
,
'V'
},
{
"out-dependency"
,
a_argument
,
NULL
,
'd'
},
{
"reserve"
,
a_argument
,
NULL
,
'R'
},
{
"space"
,
a_argument
,
NULL
,
'S'
},
{
"pad"
,
a_argument
,
NULL
,
'p'
},
{
"align"
,
a_argument
,
NULL
,
'a'
},
{
"boot-cpu"
,
a_argument
,
NULL
,
'b'
},
{
"force"
,
no_argument
,
NULL
,
'f'
},
{
"include"
,
a_argument
,
NULL
,
'i'
},
{
"sort"
,
no_argument
,
NULL
,
's'
},
{
"phandle"
,
a_argument
,
NULL
,
'H'
},
{
"warning"
,
a_argument
,
NULL
,
'W'
},
{
"error"
,
a_argument
,
NULL
,
'E'
},
{
"symbols"
,
no_argument
,
NULL
,
'@'
},
{
"auto-alias"
,
no_argument
,
NULL
,
'A'
},
{
"help"
,
no_argument
,
NULL
,
'h'
},
{
"version"
,
no_argument
,
NULL
,
'v'
},
{
NULL
,
no_argument
,
NULL
,
0x0
},
};
static
const
char
*
const
usage_opts_help
[]
=
{
"
\n\t
Quiet: -q suppress warnings, -qq errors, -qqq all"
,
"
\n\t
Input formats are:
\n
"
"
\t\t
dts - device tree source text
\n
"
"
\t\t
dtb - device tree blob
\n
"
"
\t\t
fs - /proc/device-tree style directory"
,
"
\n\t
Output file"
,
"
\n\t
Output formats are:
\n
"
"
\t\t
dts - device tree source text
\n
"
"
\t\t
dtb - device tree blob
\n
"
"
\t\t
asm - assembler source"
,
"
\n\t
Blob version to produce, defaults to "
stringify
(
DEFAULT_FDT_VERSION
)
" (for dtb and asm output)"
,
"
\n\t
Output dependency file"
,
"
\n\t
Make space for <number> reserve map entries (for dtb and asm output)"
,
"
\n\t
Make the blob at least <bytes> long (extra space)"
,
"
\n\t
Add padding to the blob of <bytes> long (extra space)"
,
"
\n\t
Make the blob align to the <bytes> (extra space)"
,
"
\n\t
Set the physical boot cpu"
,
"
\n\t
Try to produce output even if the input tree has errors"
,
"
\n\t
Add a path to search for include files"
,
"
\n\t
Sort nodes and properties before outputting (useful for comparing trees)"
,
"
\n\t
Valid phandle formats are:
\n
"
"
\t\t
legacy -
\"
linux,phandle
\"
properties only
\n
"
"
\t\t
epapr -
\"
phandle
\"
properties only
\n
"
"
\t\t
both - Both
\"
linux,phandle
\"
and
\"
phandle
\"
properties"
,
"
\n\t
Enable/disable warnings (prefix with
\"
no-
\"
)"
,
"
\n\t
Enable/disable errors (prefix with
\"
no-
\"
)"
,
"
\n\t
Enable generation of symbols"
,
"
\n\t
Enable auto-alias of labels"
,
"
\n\t
Print this help and exit"
,
"
\n\t
Print version and exit"
,
NULL
,
};
static
const
char
*
guess_type_by_name
(
const
char
*
fname
,
const
char
*
fallback
)
{
const
char
*
s
;
s
=
strrchr
(
fname
,
'.'
);
if
(
s
==
NULL
)
return
fallback
;
if
(
!
strcasecmp
(
s
,
".dts"
))
return
"dts"
;
if
(
!
strcasecmp
(
s
,
".dtb"
))
return
"dtb"
;
return
fallback
;
}
static
const
char
*
guess_input_format
(
const
char
*
fname
,
const
char
*
fallback
)
{
struct
stat
statbuf
;
fdt32_t
magic
;
FILE
*
f
;
if
(
stat
(
fname
,
&
statbuf
)
!=
0
)
return
fallback
;
if
(
S_ISDIR
(
statbuf
.
st_mode
))
return
"fs"
;
if
(
!
S_ISREG
(
statbuf
.
st_mode
))
return
fallback
;
f
=
fopen
(
fname
,
"r"
);
if
(
f
==
NULL
)
return
fallback
;
if
(
fread
(
&
magic
,
4
,
1
,
f
)
!=
1
)
{
fclose
(
f
);
return
fallback
;
}
fclose
(
f
);
if
(
fdt32_to_cpu
(
magic
)
==
FDT_MAGIC
)
return
"dtb"
;
return
guess_type_by_name
(
fname
,
fallback
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
struct
dt_info
*
dti
;
const
char
*
inform
=
NULL
;
const
char
*
outform
=
NULL
;
const
char
*
outname
=
"-"
;
const
char
*
depname
=
NULL
;
bool
force
=
false
,
sort
=
false
;
const
char
*
arg
;
int
opt
;
FILE
*
outf
=
NULL
;
int
outversion
=
DEFAULT_FDT_VERSION
;
long
long
cmdline_boot_cpuid
=
-
1
;
quiet
=
0
;
reservenum
=
0
;
minsize
=
0
;
padsize
=
0
;
alignsize
=
0
;
while
((
opt
=
util_getopt_long
())
!=
EOF
)
{
switch
(
opt
)
{
case
'I'
:
inform
=
optarg
;
break
;
case
'O'
:
outform
=
optarg
;
break
;
case
'o'
:
outname
=
optarg
;
break
;
case
'V'
:
outversion
=
strtol
(
optarg
,
NULL
,
0
);
break
;
case
'd'
:
depname
=
optarg
;
break
;
case
'R'
:
reservenum
=
strtol
(
optarg
,
NULL
,
0
);
break
;
case
'S'
:
minsize
=
strtol
(
optarg
,
NULL
,
0
);
break
;
case
'p'
:
padsize
=
strtol
(
optarg
,
NULL
,
0
);
break
;
case
'a'
:
alignsize
=
strtol
(
optarg
,
NULL
,
0
);
if
(
!
is_power_of_2
(
alignsize
))
die
(
"Invalid argument
\"
%d
\"
to -a option
\n
"
,
alignsize
);
break
;
case
'f'
:
force
=
true
;
break
;
case
'q'
:
quiet
++
;
break
;
case
'b'
:
cmdline_boot_cpuid
=
strtoll
(
optarg
,
NULL
,
0
);
break
;
case
'i'
:
srcfile_add_search_path
(
optarg
);
break
;
case
'v'
:
util_version
();
case
'H'
:
if
(
streq
(
optarg
,
"legacy"
))
phandle_format
=
PHANDLE_LEGACY
;
else
if
(
streq
(
optarg
,
"epapr"
))
phandle_format
=
PHANDLE_EPAPR
;
else
if
(
streq
(
optarg
,
"both"
))
phandle_format
=
PHANDLE_BOTH
;
else
die
(
"Invalid argument
\"
%s
\"
to -H option
\n
"
,
optarg
);
break
;
case
's'
:
sort
=
true
;
break
;
case
'W'
:
parse_checks_option
(
true
,
false
,
optarg
);
break
;
case
'E'
:
parse_checks_option
(
false
,
true
,
optarg
);
break
;
case
'@'
:
generate_symbols
=
1
;
break
;
case
'A'
:
auto_label_aliases
=
1
;
break
;
case
'h'
:
usage
(
NULL
);
default:
usage
(
"unknown option"
);
}
}
if
(
argc
>
(
optind
+
1
))
usage
(
"missing files"
);
else
if
(
argc
<
(
optind
+
1
))
arg
=
"-"
;
else
arg
=
argv
[
optind
];
/* minsize and padsize are mutually exclusive */
if
(
minsize
&&
padsize
)
die
(
"Can't set both -p and -S
\n
"
);
if
(
depname
)
{
depfile
=
fopen
(
depname
,
"w"
);
if
(
!
depfile
)
die
(
"Couldn't open dependency file %s: %s
\n
"
,
depname
,
strerror
(
errno
));
fprintf
(
depfile
,
"%s:"
,
outname
);
}
if
(
inform
==
NULL
)
inform
=
guess_input_format
(
arg
,
"dts"
);
if
(
outform
==
NULL
)
{
outform
=
guess_type_by_name
(
outname
,
NULL
);
if
(
outform
==
NULL
)
{
if
(
streq
(
inform
,
"dts"
))
outform
=
"dtb"
;
else
outform
=
"dts"
;
}
}
if
(
streq
(
inform
,
"dts"
))
dti
=
dt_from_source
(
arg
);
else
if
(
streq
(
inform
,
"fs"
))
dti
=
dt_from_fs
(
arg
);
else
if
(
streq
(
inform
,
"dtb"
))
dti
=
dt_from_blob
(
arg
);
else
die
(
"Unknown input format
\"
%s
\"\n
"
,
inform
);
dti
->
outname
=
outname
;
if
(
depfile
)
{
fputc
(
'\n'
,
depfile
);
fclose
(
depfile
);
}
if
(
cmdline_boot_cpuid
!=
-
1
)
dti
->
boot_cpuid_phys
=
cmdline_boot_cpuid
;
fill_fullpaths
(
dti
->
dt
,
""
);
/* on a plugin, generate by default */
if
(
dti
->
dtsflags
&
DTSF_PLUGIN
)
{
generate_fixups
=
1
;
}
process_checks
(
force
,
dti
);
if
(
auto_label_aliases
)
generate_label_tree
(
dti
,
"aliases"
,
false
);
if
(
generate_symbols
)
generate_label_tree
(
dti
,
"__symbols__"
,
true
);
if
(
generate_fixups
)
{
generate_fixups_tree
(
dti
,
"__fixups__"
);
generate_local_fixups_tree
(
dti
,
"__local_fixups__"
);
}
if
(
sort
)
sort_tree
(
dti
);
if
(
streq
(
outname
,
"-"
))
{
outf
=
stdout
;
}
else
{
outf
=
fopen
(
outname
,
"wb"
);
if
(
!
outf
)
die
(
"Couldn't open output file %s: %s
\n
"
,
outname
,
strerror
(
errno
));
}
if
(
streq
(
outform
,
"dts"
))
{
dt_to_source
(
outf
,
dti
);
}
else
if
(
streq
(
outform
,
"dtb"
))
{
dt_to_blob
(
outf
,
dti
,
outversion
);
}
else
if
(
streq
(
outform
,
"asm"
))
{
dt_to_asm
(
outf
,
dti
,
outversion
);
}
else
if
(
streq
(
outform
,
"null"
))
{
/* do nothing */
}
else
{
die
(
"Unknown output format
\"
%s
\"\n
"
,
outform
);
}
exit
(
0
);
}
u-boot-tree/scripts/dtc/dtc.h
0 → 100644
View file @
7496de94
#ifndef DTC_H
#define DTC_H
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <inttypes.h>
#include <libfdt_env.h>
#include <fdt.h>
#include "util.h"
#ifdef DEBUG
#define debug(...) printf(__VA_ARGS__)
#else
#define debug(...)
#endif
#define DEFAULT_FDT_VERSION 17
/*
* Command line options
*/
extern
int
quiet
;
/* Level of quietness */
extern
int
reservenum
;
/* Number of memory reservation slots */
extern
int
minsize
;
/* Minimum blob size */
extern
int
padsize
;
/* Additional padding to blob */
extern
int
alignsize
;
/* Additional padding to blob accroding to the alignsize */
extern
int
phandle_format
;
/* Use linux,phandle or phandle properties */
extern
int
generate_symbols
;
/* generate symbols for nodes with labels */
extern
int
generate_fixups
;
/* generate fixups */
extern
int
auto_label_aliases
;
/* auto generate labels -> aliases */
#define PHANDLE_LEGACY 0x1
#define PHANDLE_EPAPR 0x2
#define PHANDLE_BOTH 0x3
typedef
uint32_t
cell_t
;
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0)
#define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0))
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
/* Data blobs */
enum
markertype
{
REF_PHANDLE
,
REF_PATH
,
LABEL
,
};
struct
marker
{
enum
markertype
type
;
int
offset
;
char
*
ref
;
struct
marker
*
next
;
};
struct
data
{
int
len
;
char
*
val
;
struct
marker
*
markers
;
};
#define empty_data ((struct data){ 0
/* all .members = 0 or NULL */
})
#define for_each_marker(m) \
for (; (m); (m) = (m)->next)
#define for_each_marker_of_type(m, t) \
for_each_marker(m) \
if ((m)->type == (t))
void
data_free
(
struct
data
d
);
struct
data
data_grow_for
(
struct
data
d
,
int
xlen
);
struct
data
data_copy_mem
(
const
char
*
mem
,
int
len
);
struct
data
data_copy_escape_string
(
const
char
*
s
,
int
len
);
struct
data
data_copy_file
(
FILE
*
f
,
size_t
len
);
struct
data
data_append_data
(
struct
data
d
,
const
void
*
p
,
int
len
);
struct
data
data_insert_at_marker
(
struct
data
d
,
struct
marker
*
m
,
const
void
*
p
,
int
len
);
struct
data
data_merge
(
struct
data
d1
,
struct
data
d2
);
struct
data
data_append_cell
(
struct
data
d
,
cell_t
word
);
struct
data
data_append_integer
(
struct
data
d
,
uint64_t
word
,
int
bits
);
struct
data
data_append_re
(
struct
data
d
,
uint64_t
address
,
uint64_t
size
);
struct
data
data_append_addr
(
struct
data
d
,
uint64_t
addr
);
struct
data
data_append_byte
(
struct
data
d
,
uint8_t
byte
);
struct
data
data_append_zeroes
(
struct
data
d
,
int
len
);
struct
data
data_append_align
(
struct
data
d
,
int
align
);
struct
data
data_add_marker
(
struct
data
d
,
enum
markertype
type
,
char
*
ref
);
bool
data_is_one_string
(
struct
data
d
);
/* DT constraints */
#define MAX_PROPNAME_LEN 31
#define MAX_NODENAME_LEN 31
/* Live trees */
struct
label
{
bool
deleted
;
char
*
label
;
struct
label
*
next
;
};
struct
bus_type
{
const
char
*
name
;
};
struct
property
{
bool
deleted
;
char
*
name
;
struct
data
val
;
struct
property
*
next
;
struct
label
*
labels
;
};
struct
node
{
bool
deleted
;
char
*
name
;
struct
property
*
proplist
;
struct
node
*
children
;
struct
node
*
parent
;
struct
node
*
next_sibling
;
char
*
fullpath
;
int
basenamelen
;
cell_t
phandle
;
int
addr_cells
,
size_cells
;
struct
label
*
labels
;
const
struct
bus_type
*
bus
;
};
#define for_each_label_withdel(l0, l) \
for ((l) = (l0); (l); (l) = (l)->next)
#define for_each_label(l0, l) \
for_each_label_withdel(l0, l) \
if (!(l)->deleted)
#define for_each_property_withdel(n, p) \
for ((p) = (n)->proplist; (p); (p) = (p)->next)
#define for_each_property(n, p) \
for_each_property_withdel(n, p) \
if (!(p)->deleted)
#define for_each_child_withdel(n, c) \
for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
#define for_each_child(n, c) \
for_each_child_withdel(n, c) \
if (!(c)->deleted)
void
add_label
(
struct
label
**
labels
,
char
*
label
);
void
delete_labels
(
struct
label
**
labels
);
struct
property
*
build_property
(
char
*
name
,
struct
data
val
);
struct
property
*
build_property_delete
(
char
*
name
);
struct
property
*
chain_property
(
struct
property
*
first
,
struct
property
*
list
);
struct
property
*
reverse_properties
(
struct
property
*
first
);
struct
node
*
build_node
(
struct
property
*
proplist
,
struct
node
*
children
);
struct
node
*
build_node_delete
(
void
);
struct
node
*
name_node
(
struct
node
*
node
,
char
*
name
);
struct
node
*
chain_node
(
struct
node
*
first
,
struct
node
*
list
);
struct
node
*
merge_nodes
(
struct
node
*
old_node
,
struct
node
*
new_node
);
struct
node
*
add_orphan_node
(
struct
node
*
old_node
,
struct
node
*
new_node
,
char
*
ref
);
void
add_property
(
struct
node
*
node
,
struct
property
*
prop
);
void
delete_property_by_name
(
struct
node
*
node
,
char
*
name
);
void
delete_property
(
struct
property
*
prop
);
void
add_child
(
struct
node
*
parent
,
struct
node
*
child
);
void
delete_node_by_name
(
struct
node
*
parent
,
char
*
name
);
void
delete_node
(
struct
node
*
node
);
void
append_to_property
(
struct
node
*
node
,
char
*
name
,
const
void
*
data
,
int
len
);
const
char
*
get_unitname
(
struct
node
*
node
);
struct
property
*
get_property
(
struct
node
*
node
,
const
char
*
propname
);
cell_t
propval_cell
(
struct
property
*
prop
);
cell_t
propval_cell_n
(
struct
property
*
prop
,
int
n
);
struct
property
*
get_property_by_label
(
struct
node
*
tree
,
const
char
*
label
,
struct
node
**
node
);
struct
marker
*
get_marker_label
(
struct
node
*
tree
,
const
char
*
label
,
struct
node
**
node
,
struct
property
**
prop
);
struct
node
*
get_subnode
(
struct
node
*
node
,
const
char
*
nodename
);
struct
node
*
get_node_by_path
(
struct
node
*
tree
,
const
char
*
path
);
struct
node
*
get_node_by_label
(
struct
node
*
tree
,
const
char
*
label
);
struct
node
*
get_node_by_phandle
(
struct
node
*
tree
,
cell_t
phandle
);
struct
node
*
get_node_by_ref
(
struct
node
*
tree
,
const
char
*
ref
);
cell_t
get_node_phandle
(
struct
node
*
root
,
struct
node
*
node
);
uint32_t
guess_boot_cpuid
(
struct
node
*
tree
);
/* Boot info (tree plus memreserve information */
struct
reserve_info
{
uint64_t
address
,
size
;
struct
reserve_info
*
next
;
struct
label
*
labels
;
};
struct
reserve_info
*
build_reserve_entry
(
uint64_t
start
,
uint64_t
len
);
struct
reserve_info
*
chain_reserve_entry
(
struct
reserve_info
*
first
,
struct
reserve_info
*
list
);
struct
reserve_info
*
add_reserve_entry
(
struct
reserve_info
*
list
,
struct
reserve_info
*
new
);
struct
dt_info
{
unsigned
int
dtsflags
;
struct
reserve_info
*
reservelist
;
uint32_t
boot_cpuid_phys
;
struct
node
*
dt
;
/* the device tree */
const
char
*
outname
;
/* filename being written to, "-" for stdout */
};
/* DTS version flags definitions */
#define DTSF_V1 0x0001
/* /dts-v1/ */
#define DTSF_PLUGIN 0x0002
/* /plugin/ */
struct
dt_info
*
build_dt_info
(
unsigned
int
dtsflags
,
struct
reserve_info
*
reservelist
,
struct
node
*
tree
,
uint32_t
boot_cpuid_phys
);
void
sort_tree
(
struct
dt_info
*
dti
);
void
generate_label_tree
(
struct
dt_info
*
dti
,
char
*
name
,
bool
allocph
);
void
generate_fixups_tree
(
struct
dt_info
*
dti
,
char
*
name
);
void
generate_local_fixups_tree
(
struct
dt_info
*
dti
,
char
*
name
);
/* Checks */
void
parse_checks_option
(
bool
warn
,
bool
error
,
const
char
*
arg
);
void
process_checks
(
bool
force
,
struct
dt_info
*
dti
);
/* Flattened trees */
void
dt_to_blob
(
FILE
*
f
,
struct
dt_info
*
dti
,
int
version
);
void
dt_to_asm
(
FILE
*
f
,
struct
dt_info
*
dti
,
int
version
);
struct
dt_info
*
dt_from_blob
(
const
char
*
fname
);
/* Tree source */
void
dt_to_source
(
FILE
*
f
,
struct
dt_info
*
dti
);
struct
dt_info
*
dt_from_source
(
const
char
*
f
);
/* FS trees */
struct
dt_info
*
dt_from_fs
(
const
char
*
dirname
);
#endif
/* DTC_H */
u-boot-tree/scripts/dtc/flattree.c
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
#include "srcpos.h"
#define FTF_FULLPATH 0x1
#define FTF_VARALIGN 0x2
#define FTF_NAMEPROPS 0x4
#define FTF_BOOTCPUID 0x8
#define FTF_STRTABSIZE 0x10
#define FTF_STRUCTSIZE 0x20
#define FTF_NOPS 0x40
static
struct
version_info
{
int
version
;
int
last_comp_version
;
int
hdr_size
;
int
flags
;
}
version_table
[]
=
{
{
1
,
1
,
FDT_V1_SIZE
,
FTF_FULLPATH
|
FTF_VARALIGN
|
FTF_NAMEPROPS
},
{
2
,
1
,
FDT_V2_SIZE
,
FTF_FULLPATH
|
FTF_VARALIGN
|
FTF_NAMEPROPS
|
FTF_BOOTCPUID
},
{
3
,
1
,
FDT_V3_SIZE
,
FTF_FULLPATH
|
FTF_VARALIGN
|
FTF_NAMEPROPS
|
FTF_BOOTCPUID
|
FTF_STRTABSIZE
},
{
16
,
16
,
FDT_V3_SIZE
,
FTF_BOOTCPUID
|
FTF_STRTABSIZE
|
FTF_NOPS
},
{
17
,
16
,
FDT_V17_SIZE
,
FTF_BOOTCPUID
|
FTF_STRTABSIZE
|
FTF_STRUCTSIZE
|
FTF_NOPS
},
};
struct
emitter
{
void
(
*
cell
)(
void
*
,
cell_t
);
void
(
*
string
)(
void
*
,
const
char
*
,
int
);
void
(
*
align
)(
void
*
,
int
);
void
(
*
data
)(
void
*
,
struct
data
);
void
(
*
beginnode
)(
void
*
,
struct
label
*
labels
);
void
(
*
endnode
)(
void
*
,
struct
label
*
labels
);
void
(
*
property
)(
void
*
,
struct
label
*
labels
);
};
static
void
bin_emit_cell
(
void
*
e
,
cell_t
val
)
{
struct
data
*
dtbuf
=
e
;
*
dtbuf
=
data_append_cell
(
*
dtbuf
,
val
);
}
static
void
bin_emit_string
(
void
*
e
,
const
char
*
str
,
int
len
)
{
struct
data
*
dtbuf
=
e
;
if
(
len
==
0
)
len
=
strlen
(
str
);
*
dtbuf
=
data_append_data
(
*
dtbuf
,
str
,
len
);
*
dtbuf
=
data_append_byte
(
*
dtbuf
,
'\0'
);
}
static
void
bin_emit_align
(
void
*
e
,
int
a
)
{
struct
data
*
dtbuf
=
e
;
*
dtbuf
=
data_append_align
(
*
dtbuf
,
a
);
}
static
void
bin_emit_data
(
void
*
e
,
struct
data
d
)
{
struct
data
*
dtbuf
=
e
;
*
dtbuf
=
data_append_data
(
*
dtbuf
,
d
.
val
,
d
.
len
);
}
static
void
bin_emit_beginnode
(
void
*
e
,
struct
label
*
labels
)
{
bin_emit_cell
(
e
,
FDT_BEGIN_NODE
);
}
static
void
bin_emit_endnode
(
void
*
e
,
struct
label
*
labels
)
{
bin_emit_cell
(
e
,
FDT_END_NODE
);
}
static
void
bin_emit_property
(
void
*
e
,
struct
label
*
labels
)
{
bin_emit_cell
(
e
,
FDT_PROP
);
}
static
struct
emitter
bin_emitter
=
{
.
cell
=
bin_emit_cell
,
.
string
=
bin_emit_string
,
.
align
=
bin_emit_align
,
.
data
=
bin_emit_data
,
.
beginnode
=
bin_emit_beginnode
,
.
endnode
=
bin_emit_endnode
,
.
property
=
bin_emit_property
,
};
static
void
emit_label
(
FILE
*
f
,
const
char
*
prefix
,
const
char
*
label
)
{
fprintf
(
f
,
"
\t
.globl
\t
%s_%s
\n
"
,
prefix
,
label
);
fprintf
(
f
,
"%s_%s:
\n
"
,
prefix
,
label
);
fprintf
(
f
,
"_%s_%s:
\n
"
,
prefix
,
label
);
}
static
void
emit_offset_label
(
FILE
*
f
,
const
char
*
label
,
int
offset
)
{
fprintf
(
f
,
"
\t
.globl
\t
%s
\n
"
,
label
);
fprintf
(
f
,
"%s
\t
= . + %d
\n
"
,
label
,
offset
);
}
#define ASM_EMIT_BELONG(f, fmt, ...) \
{ \
fprintf((f), "\t.byte\t((" fmt ") >> 24) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t((" fmt ") >> 16) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t((" fmt ") >> 8) & 0xff\n", __VA_ARGS__); \
fprintf((f), "\t.byte\t(" fmt ") & 0xff\n", __VA_ARGS__); \
}
static
void
asm_emit_cell
(
void
*
e
,
cell_t
val
)
{
FILE
*
f
=
e
;
fprintf
(
f
,
"
\t
.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x
\n
"
,
(
val
>>
24
)
&
0xff
,
(
val
>>
16
)
&
0xff
,
(
val
>>
8
)
&
0xff
,
val
&
0xff
);
}
static
void
asm_emit_string
(
void
*
e
,
const
char
*
str
,
int
len
)
{
FILE
*
f
=
e
;
if
(
len
!=
0
)
fprintf
(
f
,
"
\t
.string
\t\"
%.*s
\"\n
"
,
len
,
str
);
else
fprintf
(
f
,
"
\t
.string
\t\"
%s
\"\n
"
,
str
);
}
static
void
asm_emit_align
(
void
*
e
,
int
a
)
{
FILE
*
f
=
e
;
fprintf
(
f
,
"
\t
.balign
\t
%d, 0
\n
"
,
a
);
}
static
void
asm_emit_data
(
void
*
e
,
struct
data
d
)
{
FILE
*
f
=
e
;
int
off
=
0
;
struct
marker
*
m
=
d
.
markers
;
for_each_marker_of_type
(
m
,
LABEL
)
emit_offset_label
(
f
,
m
->
ref
,
m
->
offset
);
while
((
d
.
len
-
off
)
>=
sizeof
(
uint32_t
))
{
asm_emit_cell
(
e
,
fdt32_to_cpu
(
*
((
fdt32_t
*
)(
d
.
val
+
off
))));
off
+=
sizeof
(
uint32_t
);
}
while
((
d
.
len
-
off
)
>=
1
)
{
fprintf
(
f
,
"
\t
.byte
\t
0x%hhx
\n
"
,
d
.
val
[
off
]);
off
+=
1
;
}
assert
(
off
==
d
.
len
);
}
static
void
asm_emit_beginnode
(
void
*
e
,
struct
label
*
labels
)
{
FILE
*
f
=
e
;
struct
label
*
l
;
for_each_label
(
labels
,
l
)
{
fprintf
(
f
,
"
\t
.globl
\t
%s
\n
"
,
l
->
label
);
fprintf
(
f
,
"%s:
\n
"
,
l
->
label
);
}
fprintf
(
f
,
"
\t
/* FDT_BEGIN_NODE */
\n
"
);
asm_emit_cell
(
e
,
FDT_BEGIN_NODE
);
}
static
void
asm_emit_endnode
(
void
*
e
,
struct
label
*
labels
)
{
FILE
*
f
=
e
;
struct
label
*
l
;
fprintf
(
f
,
"
\t
/* FDT_END_NODE */
\n
"
);
asm_emit_cell
(
e
,
FDT_END_NODE
);
for_each_label
(
labels
,
l
)
{
fprintf
(
f
,
"
\t
.globl
\t
%s_end
\n
"
,
l
->
label
);
fprintf
(
f
,
"%s_end:
\n
"
,
l
->
label
);
}
}
static
void
asm_emit_property
(
void
*
e
,
struct
label
*
labels
)
{
FILE
*
f
=
e
;
struct
label
*
l
;
for_each_label
(
labels
,
l
)
{
fprintf
(
f
,
"
\t
.globl
\t
%s
\n
"
,
l
->
label
);
fprintf
(
f
,
"%s:
\n
"
,
l
->
label
);
}
fprintf
(
f
,
"
\t
/* FDT_PROP */
\n
"
);
asm_emit_cell
(
e
,
FDT_PROP
);
}
static
struct
emitter
asm_emitter
=
{
.
cell
=
asm_emit_cell
,
.
string
=
asm_emit_string
,
.
align
=
asm_emit_align
,
.
data
=
asm_emit_data
,
.
beginnode
=
asm_emit_beginnode
,
.
endnode
=
asm_emit_endnode
,
.
property
=
asm_emit_property
,
};
static
int
stringtable_insert
(
struct
data
*
d
,
const
char
*
str
)
{
int
i
;
/* FIXME: do this more efficiently? */
for
(
i
=
0
;
i
<
d
->
len
;
i
++
)
{
if
(
streq
(
str
,
d
->
val
+
i
))
return
i
;
}
*
d
=
data_append_data
(
*
d
,
str
,
strlen
(
str
)
+
1
);
return
i
;
}
static
void
flatten_tree
(
struct
node
*
tree
,
struct
emitter
*
emit
,
void
*
etarget
,
struct
data
*
strbuf
,
struct
version_info
*
vi
)
{
struct
property
*
prop
;
struct
node
*
child
;
bool
seen_name_prop
=
false
;
if
(
tree
->
deleted
)
return
;
emit
->
beginnode
(
etarget
,
tree
->
labels
);
if
(
vi
->
flags
&
FTF_FULLPATH
)
emit
->
string
(
etarget
,
tree
->
fullpath
,
0
);
else
emit
->
string
(
etarget
,
tree
->
name
,
0
);
emit
->
align
(
etarget
,
sizeof
(
cell_t
));
for_each_property
(
tree
,
prop
)
{
int
nameoff
;
if
(
streq
(
prop
->
name
,
"name"
))
seen_name_prop
=
true
;
nameoff
=
stringtable_insert
(
strbuf
,
prop
->
name
);
emit
->
property
(
etarget
,
prop
->
labels
);
emit
->
cell
(
etarget
,
prop
->
val
.
len
);
emit
->
cell
(
etarget
,
nameoff
);
if
((
vi
->
flags
&
FTF_VARALIGN
)
&&
(
prop
->
val
.
len
>=
8
))
emit
->
align
(
etarget
,
8
);
emit
->
data
(
etarget
,
prop
->
val
);
emit
->
align
(
etarget
,
sizeof
(
cell_t
));
}
if
((
vi
->
flags
&
FTF_NAMEPROPS
)
&&
!
seen_name_prop
)
{
emit
->
property
(
etarget
,
NULL
);
emit
->
cell
(
etarget
,
tree
->
basenamelen
+
1
);
emit
->
cell
(
etarget
,
stringtable_insert
(
strbuf
,
"name"
));
if
((
vi
->
flags
&
FTF_VARALIGN
)
&&
((
tree
->
basenamelen
+
1
)
>=
8
))
emit
->
align
(
etarget
,
8
);
emit
->
string
(
etarget
,
tree
->
name
,
tree
->
basenamelen
);
emit
->
align
(
etarget
,
sizeof
(
cell_t
));
}
for_each_child
(
tree
,
child
)
{
flatten_tree
(
child
,
emit
,
etarget
,
strbuf
,
vi
);
}
emit
->
endnode
(
etarget
,
tree
->
labels
);
}
static
struct
data
flatten_reserve_list
(
struct
reserve_info
*
reservelist
,
struct
version_info
*
vi
)
{
struct
reserve_info
*
re
;
struct
data
d
=
empty_data
;
int
j
;
for
(
re
=
reservelist
;
re
;
re
=
re
->
next
)
{
d
=
data_append_re
(
d
,
re
->
address
,
re
->
size
);
}
/*
* Add additional reserved slots if the user asked for them.
*/
for
(
j
=
0
;
j
<
reservenum
;
j
++
)
{
d
=
data_append_re
(
d
,
0
,
0
);
}
return
d
;
}
static
void
make_fdt_header
(
struct
fdt_header
*
fdt
,
struct
version_info
*
vi
,
int
reservesize
,
int
dtsize
,
int
strsize
,
int
boot_cpuid_phys
)
{
int
reserve_off
;
reservesize
+=
sizeof
(
struct
fdt_reserve_entry
);
memset
(
fdt
,
0xff
,
sizeof
(
*
fdt
));
fdt
->
magic
=
cpu_to_fdt32
(
FDT_MAGIC
);
fdt
->
version
=
cpu_to_fdt32
(
vi
->
version
);
fdt
->
last_comp_version
=
cpu_to_fdt32
(
vi
->
last_comp_version
);
/* Reserve map should be doubleword aligned */
reserve_off
=
ALIGN
(
vi
->
hdr_size
,
8
);
fdt
->
off_mem_rsvmap
=
cpu_to_fdt32
(
reserve_off
);
fdt
->
off_dt_struct
=
cpu_to_fdt32
(
reserve_off
+
reservesize
);
fdt
->
off_dt_strings
=
cpu_to_fdt32
(
reserve_off
+
reservesize
+
dtsize
);
fdt
->
totalsize
=
cpu_to_fdt32
(
reserve_off
+
reservesize
+
dtsize
+
strsize
);
if
(
vi
->
flags
&
FTF_BOOTCPUID
)
fdt
->
boot_cpuid_phys
=
cpu_to_fdt32
(
boot_cpuid_phys
);
if
(
vi
->
flags
&
FTF_STRTABSIZE
)
fdt
->
size_dt_strings
=
cpu_to_fdt32
(
strsize
);
if
(
vi
->
flags
&
FTF_STRUCTSIZE
)
fdt
->
size_dt_struct
=
cpu_to_fdt32
(
dtsize
);
}
void
dt_to_blob
(
FILE
*
f
,
struct
dt_info
*
dti
,
int
version
)
{
struct
version_info
*
vi
=
NULL
;
int
i
;
struct
data
blob
=
empty_data
;
struct
data
reservebuf
=
empty_data
;
struct
data
dtbuf
=
empty_data
;
struct
data
strbuf
=
empty_data
;
struct
fdt_header
fdt
;
int
padlen
=
0
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
version_table
);
i
++
)
{
if
(
version_table
[
i
].
version
==
version
)
vi
=
&
version_table
[
i
];
}
if
(
!
vi
)
die
(
"Unknown device tree blob version %d
\n
"
,
version
);
flatten_tree
(
dti
->
dt
,
&
bin_emitter
,
&
dtbuf
,
&
strbuf
,
vi
);
bin_emit_cell
(
&
dtbuf
,
FDT_END
);
reservebuf
=
flatten_reserve_list
(
dti
->
reservelist
,
vi
);
/* Make header */
make_fdt_header
(
&
fdt
,
vi
,
reservebuf
.
len
,
dtbuf
.
len
,
strbuf
.
len
,
dti
->
boot_cpuid_phys
);
/*
* If the user asked for more space than is used, adjust the totalsize.
*/
if
(
minsize
>
0
)
{
padlen
=
minsize
-
fdt32_to_cpu
(
fdt
.
totalsize
);
if
(
padlen
<
0
)
{
padlen
=
0
;
if
(
quiet
<
1
)
fprintf
(
stderr
,
"Warning: blob size %d >= minimum size %d
\n
"
,
fdt32_to_cpu
(
fdt
.
totalsize
),
minsize
);
}
}
if
(
padsize
>
0
)
padlen
=
padsize
;
if
(
alignsize
>
0
)
padlen
=
ALIGN
(
fdt32_to_cpu
(
fdt
.
totalsize
)
+
padlen
,
alignsize
)
-
fdt32_to_cpu
(
fdt
.
totalsize
);
if
(
padlen
>
0
)
{
int
tsize
=
fdt32_to_cpu
(
fdt
.
totalsize
);
tsize
+=
padlen
;
fdt
.
totalsize
=
cpu_to_fdt32
(
tsize
);
}
/*
* Assemble the blob: start with the header, add with alignment
* the reserve buffer, add the reserve map terminating zeroes,
* the device tree itself, and finally the strings.
*/
blob
=
data_append_data
(
blob
,
&
fdt
,
vi
->
hdr_size
);
blob
=
data_append_align
(
blob
,
8
);
blob
=
data_merge
(
blob
,
reservebuf
);
blob
=
data_append_zeroes
(
blob
,
sizeof
(
struct
fdt_reserve_entry
));
blob
=
data_merge
(
blob
,
dtbuf
);
blob
=
data_merge
(
blob
,
strbuf
);
/*
* If the user asked for more space than is used, pad out the blob.
*/
if
(
padlen
>
0
)
blob
=
data_append_zeroes
(
blob
,
padlen
);
if
(
fwrite
(
blob
.
val
,
blob
.
len
,
1
,
f
)
!=
1
)
{
if
(
ferror
(
f
))
die
(
"Error writing device tree blob: %s
\n
"
,
strerror
(
errno
));
else
die
(
"Short write on device tree blob
\n
"
);
}
/*
* data_merge() frees the right-hand element so only the blob
* remains to be freed.
*/
data_free
(
blob
);
}
static
void
dump_stringtable_asm
(
FILE
*
f
,
struct
data
strbuf
)
{
const
char
*
p
;
int
len
;
p
=
strbuf
.
val
;
while
(
p
<
(
strbuf
.
val
+
strbuf
.
len
))
{
len
=
strlen
(
p
);
fprintf
(
f
,
"
\t
.string
\"
%s
\"\n
"
,
p
);
p
+=
len
+
1
;
}
}
void
dt_to_asm
(
FILE
*
f
,
struct
dt_info
*
dti
,
int
version
)
{
struct
version_info
*
vi
=
NULL
;
int
i
;
struct
data
strbuf
=
empty_data
;
struct
reserve_info
*
re
;
const
char
*
symprefix
=
"dt"
;
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
version_table
);
i
++
)
{
if
(
version_table
[
i
].
version
==
version
)
vi
=
&
version_table
[
i
];
}
if
(
!
vi
)
die
(
"Unknown device tree blob version %d
\n
"
,
version
);
fprintf
(
f
,
"/* autogenerated by dtc, do not edit */
\n\n
"
);
emit_label
(
f
,
symprefix
,
"blob_start"
);
emit_label
(
f
,
symprefix
,
"header"
);
fprintf
(
f
,
"
\t
/* magic */
\n
"
);
asm_emit_cell
(
f
,
FDT_MAGIC
);
fprintf
(
f
,
"
\t
/* totalsize */
\n
"
);
ASM_EMIT_BELONG
(
f
,
"_%s_blob_abs_end - _%s_blob_start"
,
symprefix
,
symprefix
);
fprintf
(
f
,
"
\t
/* off_dt_struct */
\n
"
);
ASM_EMIT_BELONG
(
f
,
"_%s_struct_start - _%s_blob_start"
,
symprefix
,
symprefix
);
fprintf
(
f
,
"
\t
/* off_dt_strings */
\n
"
);
ASM_EMIT_BELONG
(
f
,
"_%s_strings_start - _%s_blob_start"
,
symprefix
,
symprefix
);
fprintf
(
f
,
"
\t
/* off_mem_rsvmap */
\n
"
);
ASM_EMIT_BELONG
(
f
,
"_%s_reserve_map - _%s_blob_start"
,
symprefix
,
symprefix
);
fprintf
(
f
,
"
\t
/* version */
\n
"
);
asm_emit_cell
(
f
,
vi
->
version
);
fprintf
(
f
,
"
\t
/* last_comp_version */
\n
"
);
asm_emit_cell
(
f
,
vi
->
last_comp_version
);
if
(
vi
->
flags
&
FTF_BOOTCPUID
)
{
fprintf
(
f
,
"
\t
/* boot_cpuid_phys */
\n
"
);
asm_emit_cell
(
f
,
dti
->
boot_cpuid_phys
);
}
if
(
vi
->
flags
&
FTF_STRTABSIZE
)
{
fprintf
(
f
,
"
\t
/* size_dt_strings */
\n
"
);
ASM_EMIT_BELONG
(
f
,
"_%s_strings_end - _%s_strings_start"
,
symprefix
,
symprefix
);
}
if
(
vi
->
flags
&
FTF_STRUCTSIZE
)
{
fprintf
(
f
,
"
\t
/* size_dt_struct */
\n
"
);
ASM_EMIT_BELONG
(
f
,
"_%s_struct_end - _%s_struct_start"
,
symprefix
,
symprefix
);
}
/*
* Reserve map entries.
* Align the reserve map to a doubleword boundary.
* Each entry is an (address, size) pair of u64 values.
* Always supply a zero-sized temination entry.
*/
asm_emit_align
(
f
,
8
);
emit_label
(
f
,
symprefix
,
"reserve_map"
);
fprintf
(
f
,
"/* Memory reserve map from source file */
\n
"
);
/*
* Use .long on high and low halfs of u64s to avoid .quad
* as it appears .quad isn't available in some assemblers.
*/
for
(
re
=
dti
->
reservelist
;
re
;
re
=
re
->
next
)
{
struct
label
*
l
;
for_each_label
(
re
->
labels
,
l
)
{
fprintf
(
f
,
"
\t
.globl
\t
%s
\n
"
,
l
->
label
);
fprintf
(
f
,
"%s:
\n
"
,
l
->
label
);
}
ASM_EMIT_BELONG
(
f
,
"0x%08x"
,
(
unsigned
int
)(
re
->
address
>>
32
));
ASM_EMIT_BELONG
(
f
,
"0x%08x"
,
(
unsigned
int
)(
re
->
address
&
0xffffffff
));
ASM_EMIT_BELONG
(
f
,
"0x%08x"
,
(
unsigned
int
)(
re
->
size
>>
32
));
ASM_EMIT_BELONG
(
f
,
"0x%08x"
,
(
unsigned
int
)(
re
->
size
&
0xffffffff
));
}
for
(
i
=
0
;
i
<
reservenum
;
i
++
)
{
fprintf
(
f
,
"
\t
.long
\t
0, 0
\n\t
.long
\t
0, 0
\n
"
);
}
fprintf
(
f
,
"
\t
.long
\t
0, 0
\n\t
.long
\t
0, 0
\n
"
);
emit_label
(
f
,
symprefix
,
"struct_start"
);
flatten_tree
(
dti
->
dt
,
&
asm_emitter
,
f
,
&
strbuf
,
vi
);
fprintf
(
f
,
"
\t
/* FDT_END */
\n
"
);
asm_emit_cell
(
f
,
FDT_END
);
emit_label
(
f
,
symprefix
,
"struct_end"
);
emit_label
(
f
,
symprefix
,
"strings_start"
);
dump_stringtable_asm
(
f
,
strbuf
);
emit_label
(
f
,
symprefix
,
"strings_end"
);
emit_label
(
f
,
symprefix
,
"blob_end"
);
/*
* If the user asked for more space than is used, pad it out.
*/
if
(
minsize
>
0
)
{
fprintf
(
f
,
"
\t
.space
\t
%d - (_%s_blob_end - _%s_blob_start), 0
\n
"
,
minsize
,
symprefix
,
symprefix
);
}
if
(
padsize
>
0
)
{
fprintf
(
f
,
"
\t
.space
\t
%d, 0
\n
"
,
padsize
);
}
if
(
alignsize
>
0
)
asm_emit_align
(
f
,
alignsize
);
emit_label
(
f
,
symprefix
,
"blob_abs_end"
);
data_free
(
strbuf
);
}
struct
inbuf
{
char
*
base
,
*
limit
,
*
ptr
;
};
static
void
inbuf_init
(
struct
inbuf
*
inb
,
void
*
base
,
void
*
limit
)
{
inb
->
base
=
base
;
inb
->
limit
=
limit
;
inb
->
ptr
=
inb
->
base
;
}
static
void
flat_read_chunk
(
struct
inbuf
*
inb
,
void
*
p
,
int
len
)
{
if
((
inb
->
ptr
+
len
)
>
inb
->
limit
)
die
(
"Premature end of data parsing flat device tree
\n
"
);
memcpy
(
p
,
inb
->
ptr
,
len
);
inb
->
ptr
+=
len
;
}
static
uint32_t
flat_read_word
(
struct
inbuf
*
inb
)
{
fdt32_t
val
;
assert
(((
inb
->
ptr
-
inb
->
base
)
%
sizeof
(
val
))
==
0
);
flat_read_chunk
(
inb
,
&
val
,
sizeof
(
val
));
return
fdt32_to_cpu
(
val
);
}
static
void
flat_realign
(
struct
inbuf
*
inb
,
int
align
)
{
int
off
=
inb
->
ptr
-
inb
->
base
;
inb
->
ptr
=
inb
->
base
+
ALIGN
(
off
,
align
);
if
(
inb
->
ptr
>
inb
->
limit
)
die
(
"Premature end of data parsing flat device tree
\n
"
);
}
static
char
*
flat_read_string
(
struct
inbuf
*
inb
)
{
int
len
=
0
;
const
char
*
p
=
inb
->
ptr
;
char
*
str
;
do
{
if
(
p
>=
inb
->
limit
)
die
(
"Premature end of data parsing flat device tree
\n
"
);
len
++
;
}
while
((
*
p
++
)
!=
'\0'
);
str
=
xstrdup
(
inb
->
ptr
);
inb
->
ptr
+=
len
;
flat_realign
(
inb
,
sizeof
(
uint32_t
));
return
str
;
}
static
struct
data
flat_read_data
(
struct
inbuf
*
inb
,
int
len
)
{
struct
data
d
=
empty_data
;
if
(
len
==
0
)
return
empty_data
;
d
=
data_grow_for
(
d
,
len
);
d
.
len
=
len
;
flat_read_chunk
(
inb
,
d
.
val
,
len
);
flat_realign
(
inb
,
sizeof
(
uint32_t
));
return
d
;
}
static
char
*
flat_read_stringtable
(
struct
inbuf
*
inb
,
int
offset
)
{
const
char
*
p
;
p
=
inb
->
base
+
offset
;
while
(
1
)
{
if
(
p
>=
inb
->
limit
||
p
<
inb
->
base
)
die
(
"String offset %d overruns string table
\n
"
,
offset
);
if
(
*
p
==
'\0'
)
break
;
p
++
;
}
return
xstrdup
(
inb
->
base
+
offset
);
}
static
struct
property
*
flat_read_property
(
struct
inbuf
*
dtbuf
,
struct
inbuf
*
strbuf
,
int
flags
)
{
uint32_t
proplen
,
stroff
;
char
*
name
;
struct
data
val
;
proplen
=
flat_read_word
(
dtbuf
);
stroff
=
flat_read_word
(
dtbuf
);
name
=
flat_read_stringtable
(
strbuf
,
stroff
);
if
((
flags
&
FTF_VARALIGN
)
&&
(
proplen
>=
8
))
flat_realign
(
dtbuf
,
8
);
val
=
flat_read_data
(
dtbuf
,
proplen
);
return
build_property
(
name
,
val
);
}
static
struct
reserve_info
*
flat_read_mem_reserve
(
struct
inbuf
*
inb
)
{
struct
reserve_info
*
reservelist
=
NULL
;
struct
reserve_info
*
new
;
struct
fdt_reserve_entry
re
;
/*
* Each entry is a pair of u64 (addr, size) values for 4 cell_t's.
* List terminates at an entry with size equal to zero.
*
* First pass, count entries.
*/
while
(
1
)
{
uint64_t
address
,
size
;
flat_read_chunk
(
inb
,
&
re
,
sizeof
(
re
));
address
=
fdt64_to_cpu
(
re
.
address
);
size
=
fdt64_to_cpu
(
re
.
size
);
if
(
size
==
0
)
break
;
new
=
build_reserve_entry
(
address
,
size
);
reservelist
=
add_reserve_entry
(
reservelist
,
new
);
}
return
reservelist
;
}
static
char
*
nodename_from_path
(
const
char
*
ppath
,
const
char
*
cpath
)
{
int
plen
;
plen
=
strlen
(
ppath
);
if
(
!
strstarts
(
cpath
,
ppath
))
die
(
"Path
\"
%s
\"
is not valid as a child of
\"
%s
\"\n
"
,
cpath
,
ppath
);
/* root node is a special case */
if
(
!
streq
(
ppath
,
"/"
))
plen
++
;
return
xstrdup
(
cpath
+
plen
);
}
static
struct
node
*
unflatten_tree
(
struct
inbuf
*
dtbuf
,
struct
inbuf
*
strbuf
,
const
char
*
parent_flatname
,
int
flags
)
{
struct
node
*
node
;
char
*
flatname
;
uint32_t
val
;
node
=
build_node
(
NULL
,
NULL
);
flatname
=
flat_read_string
(
dtbuf
);
if
(
flags
&
FTF_FULLPATH
)
node
->
name
=
nodename_from_path
(
parent_flatname
,
flatname
);
else
node
->
name
=
flatname
;
do
{
struct
property
*
prop
;
struct
node
*
child
;
val
=
flat_read_word
(
dtbuf
);
switch
(
val
)
{
case
FDT_PROP
:
if
(
node
->
children
)
fprintf
(
stderr
,
"Warning: Flat tree input has "
"subnodes preceding a property.
\n
"
);
prop
=
flat_read_property
(
dtbuf
,
strbuf
,
flags
);
add_property
(
node
,
prop
);
break
;
case
FDT_BEGIN_NODE
:
child
=
unflatten_tree
(
dtbuf
,
strbuf
,
flatname
,
flags
);
add_child
(
node
,
child
);
break
;
case
FDT_END_NODE
:
break
;
case
FDT_END
:
die
(
"Premature FDT_END in device tree blob
\n
"
);
break
;
case
FDT_NOP
:
if
(
!
(
flags
&
FTF_NOPS
))
fprintf
(
stderr
,
"Warning: NOP tag found in flat tree"
" version <16
\n
"
);
/* Ignore */
break
;
default:
die
(
"Invalid opcode word %08x in device tree blob
\n
"
,
val
);
}
}
while
(
val
!=
FDT_END_NODE
);
if
(
node
->
name
!=
flatname
)
{
free
(
flatname
);
}
return
node
;
}
struct
dt_info
*
dt_from_blob
(
const
char
*
fname
)
{
FILE
*
f
;
fdt32_t
magic_buf
,
totalsize_buf
;
uint32_t
magic
,
totalsize
,
version
,
size_dt
,
boot_cpuid_phys
;
uint32_t
off_dt
,
off_str
,
off_mem_rsvmap
;
int
rc
;
char
*
blob
;
struct
fdt_header
*
fdt
;
char
*
p
;
struct
inbuf
dtbuf
,
strbuf
;
struct
inbuf
memresvbuf
;
int
sizeleft
;
struct
reserve_info
*
reservelist
;
struct
node
*
tree
;
uint32_t
val
;
int
flags
=
0
;
f
=
srcfile_relative_open
(
fname
,
NULL
);
rc
=
fread
(
&
magic_buf
,
sizeof
(
magic_buf
),
1
,
f
);
if
(
ferror
(
f
))
die
(
"Error reading DT blob magic number: %s
\n
"
,
strerror
(
errno
));
if
(
rc
<
1
)
{
if
(
feof
(
f
))
die
(
"EOF reading DT blob magic number
\n
"
);
else
die
(
"Mysterious short read reading magic number
\n
"
);
}
magic
=
fdt32_to_cpu
(
magic_buf
);
if
(
magic
!=
FDT_MAGIC
)
die
(
"Blob has incorrect magic number
\n
"
);
rc
=
fread
(
&
totalsize_buf
,
sizeof
(
totalsize_buf
),
1
,
f
);
if
(
ferror
(
f
))
die
(
"Error reading DT blob size: %s
\n
"
,
strerror
(
errno
));
if
(
rc
<
1
)
{
if
(
feof
(
f
))
die
(
"EOF reading DT blob size
\n
"
);
else
die
(
"Mysterious short read reading blob size
\n
"
);
}
totalsize
=
fdt32_to_cpu
(
totalsize_buf
);
if
(
totalsize
<
FDT_V1_SIZE
)
die
(
"DT blob size (%d) is too small
\n
"
,
totalsize
);
blob
=
xmalloc
(
totalsize
);
fdt
=
(
struct
fdt_header
*
)
blob
;
fdt
->
magic
=
cpu_to_fdt32
(
magic
);
fdt
->
totalsize
=
cpu_to_fdt32
(
totalsize
);
sizeleft
=
totalsize
-
sizeof
(
magic
)
-
sizeof
(
totalsize
);
p
=
blob
+
sizeof
(
magic
)
+
sizeof
(
totalsize
);
while
(
sizeleft
)
{
if
(
feof
(
f
))
die
(
"EOF before reading %d bytes of DT blob
\n
"
,
totalsize
);
rc
=
fread
(
p
,
1
,
sizeleft
,
f
);
if
(
ferror
(
f
))
die
(
"Error reading DT blob: %s
\n
"
,
strerror
(
errno
));
sizeleft
-=
rc
;
p
+=
rc
;
}
off_dt
=
fdt32_to_cpu
(
fdt
->
off_dt_struct
);
off_str
=
fdt32_to_cpu
(
fdt
->
off_dt_strings
);
off_mem_rsvmap
=
fdt32_to_cpu
(
fdt
->
off_mem_rsvmap
);
version
=
fdt32_to_cpu
(
fdt
->
version
);
boot_cpuid_phys
=
fdt32_to_cpu
(
fdt
->
boot_cpuid_phys
);
if
(
off_mem_rsvmap
>=
totalsize
)
die
(
"Mem Reserve structure offset exceeds total size
\n
"
);
if
(
off_dt
>=
totalsize
)
die
(
"DT structure offset exceeds total size
\n
"
);
if
(
off_str
>
totalsize
)
die
(
"String table offset exceeds total size
\n
"
);
if
(
version
>=
3
)
{
uint32_t
size_str
=
fdt32_to_cpu
(
fdt
->
size_dt_strings
);
if
((
off_str
+
size_str
<
off_str
)
||
(
off_str
+
size_str
>
totalsize
))
die
(
"String table extends past total size
\n
"
);
inbuf_init
(
&
strbuf
,
blob
+
off_str
,
blob
+
off_str
+
size_str
);
}
else
{
inbuf_init
(
&
strbuf
,
blob
+
off_str
,
blob
+
totalsize
);
}
if
(
version
>=
17
)
{
size_dt
=
fdt32_to_cpu
(
fdt
->
size_dt_struct
);
if
((
off_dt
+
size_dt
<
off_dt
)
||
(
off_dt
+
size_dt
>
totalsize
))
die
(
"Structure block extends past total size
\n
"
);
}
if
(
version
<
16
)
{
flags
|=
FTF_FULLPATH
|
FTF_NAMEPROPS
|
FTF_VARALIGN
;
}
else
{
flags
|=
FTF_NOPS
;
}
inbuf_init
(
&
memresvbuf
,
blob
+
off_mem_rsvmap
,
blob
+
totalsize
);
inbuf_init
(
&
dtbuf
,
blob
+
off_dt
,
blob
+
totalsize
);
reservelist
=
flat_read_mem_reserve
(
&
memresvbuf
);
val
=
flat_read_word
(
&
dtbuf
);
if
(
val
!=
FDT_BEGIN_NODE
)
die
(
"Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)
\n
"
,
val
);
tree
=
unflatten_tree
(
&
dtbuf
,
&
strbuf
,
""
,
flags
);
val
=
flat_read_word
(
&
dtbuf
);
if
(
val
!=
FDT_END
)
die
(
"Device tree blob doesn't end with FDT_END
\n
"
);
free
(
blob
);
fclose
(
f
);
return
build_dt_info
(
DTSF_V1
,
reservelist
,
tree
,
boot_cpuid_phys
);
}
u-boot-tree/scripts/dtc/fstree.c
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
#include <dirent.h>
#include <sys/stat.h>
static
struct
node
*
read_fstree
(
const
char
*
dirname
)
{
DIR
*
d
;
struct
dirent
*
de
;
struct
stat
st
;
struct
node
*
tree
;
d
=
opendir
(
dirname
);
if
(
!
d
)
die
(
"Couldn't opendir()
\"
%s
\"
: %s
\n
"
,
dirname
,
strerror
(
errno
));
tree
=
build_node
(
NULL
,
NULL
);
while
((
de
=
readdir
(
d
))
!=
NULL
)
{
char
*
tmpname
;
if
(
streq
(
de
->
d_name
,
"."
)
||
streq
(
de
->
d_name
,
".."
))
continue
;
tmpname
=
join_path
(
dirname
,
de
->
d_name
);
if
(
lstat
(
tmpname
,
&
st
)
<
0
)
die
(
"stat(%s): %s
\n
"
,
tmpname
,
strerror
(
errno
));
if
(
S_ISREG
(
st
.
st_mode
))
{
struct
property
*
prop
;
FILE
*
pfile
;
pfile
=
fopen
(
tmpname
,
"rb"
);
if
(
!
pfile
)
{
fprintf
(
stderr
,
"WARNING: Cannot open %s: %s
\n
"
,
tmpname
,
strerror
(
errno
));
}
else
{
prop
=
build_property
(
xstrdup
(
de
->
d_name
),
data_copy_file
(
pfile
,
st
.
st_size
));
add_property
(
tree
,
prop
);
fclose
(
pfile
);
}
}
else
if
(
S_ISDIR
(
st
.
st_mode
))
{
struct
node
*
newchild
;
newchild
=
read_fstree
(
tmpname
);
newchild
=
name_node
(
newchild
,
xstrdup
(
de
->
d_name
));
add_child
(
tree
,
newchild
);
}
free
(
tmpname
);
}
closedir
(
d
);
return
tree
;
}
struct
dt_info
*
dt_from_fs
(
const
char
*
dirname
)
{
struct
node
*
tree
;
tree
=
read_fstree
(
dirname
);
tree
=
name_node
(
tree
,
""
);
return
build_dt_info
(
DTSF_V1
,
NULL
,
tree
,
guess_boot_cpuid
(
tree
));
}
u-boot-tree/scripts/dtc/libfdt/Makefile.libfdt
0 → 100644
View file @
7496de94
# Makefile.libfdt
#
# This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles.
#
LIBFDT_soname
=
libfdt.
$(SHAREDLIB_EXT)
.1
LIBFDT_INCLUDES
=
fdt.h libfdt.h libfdt_env.h
LIBFDT_VERSION
=
version.lds
LIBFDT_SRCS
=
fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c
\
fdt_addresses.c fdt_overlay.c
LIBFDT_OBJS
=
$
(
LIBFDT_SRCS:%.c
=
%.o
)
u-boot-tree/scripts/dtc/libfdt/fdt.c
0 → 100644
View file @
7496de94
/*
* 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
;
}
else
if
(
fdt_magic
(
fdt
)
==
FDT_SW_MAGIC
)
{
/* Unfinished sequential-write blob */
if
(
fdt_size_dt_struct
(
fdt
)
==
0
)
return
-
FDT_ERR_BADSTATE
;
}
else
{
return
-
FDT_ERR_BADMAGIC
;
}
return
0
;
}
const
void
*
fdt_offset_ptr
(
const
void
*
fdt
,
int
offset
,
unsigned
int
len
)
{
unsigned
absoffset
=
offset
+
fdt_off_dt_struct
(
fdt
);
if
((
absoffset
<
offset
)
||
((
absoffset
+
len
)
<
absoffset
)
||
(
absoffset
+
len
)
>
fdt_totalsize
(
fdt
))
return
NULL
;
if
(
fdt_version
(
fdt
)
>=
0x11
)
if
(((
offset
+
len
)
<
offset
)
||
((
offset
+
len
)
>
fdt_size_dt_struct
(
fdt
)))
return
NULL
;
return
fdt_offset_ptr_
(
fdt
,
offset
);
}
uint32_t
fdt_next_tag
(
const
void
*
fdt
,
int
startoffset
,
int
*
nextoffset
)
{
const
fdt32_t
*
tagp
,
*
lenp
;
uint32_t
tag
;
int
offset
=
startoffset
;
const
char
*
p
;
*
nextoffset
=
-
FDT_ERR_TRUNCATED
;
tagp
=
fdt_offset_ptr
(
fdt
,
offset
,
FDT_TAGSIZE
);
if
(
!
tagp
)
return
FDT_END
;
/* premature end */
tag
=
fdt32_to_cpu
(
*
tagp
);
offset
+=
FDT_TAGSIZE
;
*
nextoffset
=
-
FDT_ERR_BADSTRUCTURE
;
switch
(
tag
)
{
case
FDT_BEGIN_NODE
:
/* skip name */
do
{
p
=
fdt_offset_ptr
(
fdt
,
offset
++
,
1
);
}
while
(
p
&&
(
*
p
!=
'\0'
));
if
(
!
p
)
return
FDT_END
;
/* premature end */
break
;
case
FDT_PROP
:
lenp
=
fdt_offset_ptr
(
fdt
,
offset
,
sizeof
(
*
lenp
));
if
(
!
lenp
)
return
FDT_END
;
/* premature end */
/* skip-name offset, length and value */
offset
+=
sizeof
(
struct
fdt_property
)
-
FDT_TAGSIZE
+
fdt32_to_cpu
(
*
lenp
);
if
(
fdt_version
(
fdt
)
<
0x10
&&
fdt32_to_cpu
(
*
lenp
)
>=
8
&&
((
offset
-
fdt32_to_cpu
(
*
lenp
))
%
8
)
!=
0
)
offset
+=
4
;
break
;
case
FDT_END
:
case
FDT_END_NODE
:
case
FDT_NOP
:
break
;
default:
return
FDT_END
;
}
if
(
!
fdt_offset_ptr
(
fdt
,
startoffset
,
offset
-
startoffset
))
return
FDT_END
;
/* premature end */
*
nextoffset
=
FDT_TAGALIGN
(
offset
);
return
tag
;
}
int
fdt_check_node_offset_
(
const
void
*
fdt
,
int
offset
)
{
if
((
offset
<
0
)
||
(
offset
%
FDT_TAGSIZE
)
||
(
fdt_next_tag
(
fdt
,
offset
,
&
offset
)
!=
FDT_BEGIN_NODE
))
return
-
FDT_ERR_BADOFFSET
;
return
offset
;
}
int
fdt_check_prop_offset_
(
const
void
*
fdt
,
int
offset
)
{
if
((
offset
<
0
)
||
(
offset
%
FDT_TAGSIZE
)
||
(
fdt_next_tag
(
fdt
,
offset
,
&
offset
)
!=
FDT_PROP
))
return
-
FDT_ERR_BADOFFSET
;
return
offset
;
}
int
fdt_next_node
(
const
void
*
fdt
,
int
offset
,
int
*
depth
)
{
int
nextoffset
=
0
;
uint32_t
tag
;
if
(
offset
>=
0
)
if
((
nextoffset
=
fdt_check_node_offset_
(
fdt
,
offset
))
<
0
)
return
nextoffset
;
do
{
offset
=
nextoffset
;
tag
=
fdt_next_tag
(
fdt
,
offset
,
&
nextoffset
);
switch
(
tag
)
{
case
FDT_PROP
:
case
FDT_NOP
:
break
;
case
FDT_BEGIN_NODE
:
if
(
depth
)
(
*
depth
)
++
;
break
;
case
FDT_END_NODE
:
if
(
depth
&&
((
--
(
*
depth
))
<
0
))
return
nextoffset
;
break
;
case
FDT_END
:
if
((
nextoffset
>=
0
)
||
((
nextoffset
==
-
FDT_ERR_TRUNCATED
)
&&
!
depth
))
return
-
FDT_ERR_NOTFOUND
;
else
return
nextoffset
;
}
}
while
(
tag
!=
FDT_BEGIN_NODE
);
return
offset
;
}
int
fdt_first_subnode
(
const
void
*
fdt
,
int
offset
)
{
int
depth
=
0
;
offset
=
fdt_next_node
(
fdt
,
offset
,
&
depth
);
if
(
offset
<
0
||
depth
!=
1
)
return
-
FDT_ERR_NOTFOUND
;
return
offset
;
}
int
fdt_next_subnode
(
const
void
*
fdt
,
int
offset
)
{
int
depth
=
1
;
/*
* With respect to the parent, the depth of the next subnode will be
* the same as the last.
*/
do
{
offset
=
fdt_next_node
(
fdt
,
offset
,
&
depth
);
if
(
offset
<
0
||
depth
<
1
)
return
-
FDT_ERR_NOTFOUND
;
}
while
(
depth
>
1
);
return
offset
;
}
const
char
*
fdt_find_string_
(
const
char
*
strtab
,
int
tabsize
,
const
char
*
s
)
{
int
len
=
strlen
(
s
)
+
1
;
const
char
*
last
=
strtab
+
tabsize
-
len
;
const
char
*
p
;
for
(
p
=
strtab
;
p
<=
last
;
p
++
)
if
(
memcmp
(
p
,
s
,
len
)
==
0
)
return
p
;
return
NULL
;
}
int
fdt_move
(
const
void
*
fdt
,
void
*
buf
,
int
bufsize
)
{
FDT_CHECK_HEADER
(
fdt
);
if
(
fdt_totalsize
(
fdt
)
>
bufsize
)
return
-
FDT_ERR_NOSPACE
;
memmove
(
buf
,
fdt
,
fdt_totalsize
(
fdt
));
return
0
;
}
u-boot-tree/scripts/dtc/libfdt/fdt.h
0 → 100644
View file @
7496de94
#ifndef FDT_H
#define FDT_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* 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.
*/
#ifndef __ASSEMBLY__
struct
fdt_header
{
fdt32_t
magic
;
/* magic word FDT_MAGIC */
fdt32_t
totalsize
;
/* total size of DT block */
fdt32_t
off_dt_struct
;
/* offset to structure */
fdt32_t
off_dt_strings
;
/* offset to strings */
fdt32_t
off_mem_rsvmap
;
/* offset to memory reserve map */
fdt32_t
version
;
/* format version */
fdt32_t
last_comp_version
;
/* last compatible version */
/* version 2 fields below */
fdt32_t
boot_cpuid_phys
;
/* Which physical CPU id we're
booting on */
/* version 3 fields below */
fdt32_t
size_dt_strings
;
/* size of the strings block */
/* version 17 fields below */
fdt32_t
size_dt_struct
;
/* size of the structure block */
};
struct
fdt_reserve_entry
{
fdt64_t
address
;
fdt64_t
size
;
};
struct
fdt_node_header
{
fdt32_t
tag
;
char
name
[
0
];
};
struct
fdt_property
{
fdt32_t
tag
;
fdt32_t
len
;
fdt32_t
nameoff
;
char
data
[
0
];
};
#endif
/* !__ASSEMBLY */
#define FDT_MAGIC 0xd00dfeed
/* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(fdt32_t)
#define FDT_BEGIN_NODE 0x1
/* Start node: full name */
#define FDT_END_NODE 0x2
/* End node */
#define FDT_PROP 0x3
/* Property: name off,
size, content */
#define FDT_NOP 0x4
/* nop */
#define FDT_END 0x9
#define FDT_V1_SIZE (7*sizeof(fdt32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t))
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t))
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t))
#endif
/* FDT_H */
u-boot-tree/scripts/dtc/libfdt/fdt_addresses.c
0 → 100644
View file @
7496de94
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
*
* 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_address_cells
(
const
void
*
fdt
,
int
nodeoffset
)
{
const
fdt32_t
*
ac
;
int
val
;
int
len
;
ac
=
fdt_getprop
(
fdt
,
nodeoffset
,
"#address-cells"
,
&
len
);
if
(
!
ac
)
return
2
;
if
(
len
!=
sizeof
(
*
ac
))
return
-
FDT_ERR_BADNCELLS
;
val
=
fdt32_to_cpu
(
*
ac
);
if
((
val
<=
0
)
||
(
val
>
FDT_MAX_NCELLS
))
return
-
FDT_ERR_BADNCELLS
;
return
val
;
}
int
fdt_size_cells
(
const
void
*
fdt
,
int
nodeoffset
)
{
const
fdt32_t
*
sc
;
int
val
;
int
len
;
sc
=
fdt_getprop
(
fdt
,
nodeoffset
,
"#size-cells"
,
&
len
);
if
(
!
sc
)
return
2
;
if
(
len
!=
sizeof
(
*
sc
))
return
-
FDT_ERR_BADNCELLS
;
val
=
fdt32_to_cpu
(
*
sc
);
if
((
val
<
0
)
||
(
val
>
FDT_MAX_NCELLS
))
return
-
FDT_ERR_BADNCELLS
;
return
val
;
}
u-boot-tree/scripts/dtc/libfdt/fdt_empty_tree.c
0 → 100644
View file @
7496de94
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2012 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_create_empty_tree
(
void
*
buf
,
int
bufsize
)
{
int
err
;
err
=
fdt_create
(
buf
,
bufsize
);
if
(
err
)
return
err
;
err
=
fdt_finish_reservemap
(
buf
);
if
(
err
)
return
err
;
err
=
fdt_begin_node
(
buf
,
""
);
if
(
err
)
return
err
;
err
=
fdt_end_node
(
buf
);
if
(
err
)
return
err
;
err
=
fdt_finish
(
buf
);
if
(
err
)
return
err
;
return
fdt_open_into
(
buf
,
buf
,
bufsize
);
}
u-boot-tree/scripts/dtc/libfdt/fdt_overlay.c
0 → 100644
View file @
7496de94
/*
* 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_CHECK_HEADER
(
fdt
);
for
(;;)
{
name
=
fdt_get_name
(
fdt
,
nodeoffset
,
&
namelen
);
if
(
!
name
)
return
namelen
;
/* root? we're done */
if
(
namelen
==
0
)
break
;
nodeoffset
=
fdt_parent_offset
(
fdt
,
nodeoffset
);
if
(
nodeoffset
<
0
)
return
nodeoffset
;
len
+=
namelen
+
1
;
}
/* in case of root pretend it's "/" */
if
(
len
==
0
)
len
++
;
return
len
;
}
/**
* overlay_symbol_update - Update the symbols of base tree after a merge
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
*
* overlay_symbol_update() updates the symbols of the base tree with the
* symbols of the applied overlay
*
* This is the last step in the device tree overlay application
* process, allowing the reference of overlay symbols by subsequent
* overlay operations.
*
* returns:
* 0 on success
* Negative error code on failure
*/
static
int
overlay_symbol_update
(
void
*
fdt
,
void
*
fdto
)
{
int
root_sym
,
ov_sym
,
prop
,
path_len
,
fragment
,
target
;
int
len
,
frag_name_len
,
ret
,
rel_path_len
;
const
char
*
s
,
*
e
;
const
char
*
path
;
const
char
*
name
;
const
char
*
frag_name
;
const
char
*
rel_path
;
const
char
*
target_path
;
char
*
buf
;
void
*
p
;
ov_sym
=
fdt_subnode_offset
(
fdto
,
0
,
"__symbols__"
);
/* if no overlay symbols exist no problem */
if
(
ov_sym
<
0
)
return
0
;
root_sym
=
fdt_subnode_offset
(
fdt
,
0
,
"__symbols__"
);
/* it no root symbols exist we should create them */
if
(
root_sym
==
-
FDT_ERR_NOTFOUND
)
root_sym
=
fdt_add_subnode
(
fdt
,
0
,
"__symbols__"
);
/* any error is fatal now */
if
(
root_sym
<
0
)
return
root_sym
;
/* iterate over each overlay symbol */
fdt_for_each_property_offset
(
prop
,
fdto
,
ov_sym
)
{
path
=
fdt_getprop_by_offset
(
fdto
,
prop
,
&
name
,
&
path_len
);
if
(
!
path
)
return
path_len
;
/* verify it's a string property (terminated by a single \0) */
if
(
path_len
<
1
||
memchr
(
path
,
'\0'
,
path_len
)
!=
&
path
[
path_len
-
1
])
return
-
FDT_ERR_BADVALUE
;
/* keep end marker to avoid strlen() */
e
=
path
+
path_len
;
/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
if
(
*
path
!=
'/'
)
return
-
FDT_ERR_BADVALUE
;
/* get fragment name first */
s
=
strchr
(
path
+
1
,
'/'
);
if
(
!
s
)
return
-
FDT_ERR_BADOVERLAY
;
frag_name
=
path
+
1
;
frag_name_len
=
s
-
path
-
1
;
/* verify format; safe since "s" lies in \0 terminated prop */
len
=
sizeof
(
"/__overlay__/"
)
-
1
;
if
((
e
-
s
)
<
len
||
memcmp
(
s
,
"/__overlay__/"
,
len
))
return
-
FDT_ERR_BADOVERLAY
;
rel_path
=
s
+
len
;
rel_path_len
=
e
-
rel_path
;
/* find the fragment index in which the symbol lies */
ret
=
fdt_subnode_offset_namelen
(
fdto
,
0
,
frag_name
,
frag_name_len
);
/* not found? */
if
(
ret
<
0
)
return
-
FDT_ERR_BADOVERLAY
;
fragment
=
ret
;
/* an __overlay__ subnode must exist */
ret
=
fdt_subnode_offset
(
fdto
,
fragment
,
"__overlay__"
);
if
(
ret
<
0
)
return
-
FDT_ERR_BADOVERLAY
;
/* get the target of the fragment */
ret
=
overlay_get_target
(
fdt
,
fdto
,
fragment
,
&
target_path
);
if
(
ret
<
0
)
return
ret
;
target
=
ret
;
/* if we have a target path use */
if
(
!
target_path
)
{
ret
=
get_path_len
(
fdt
,
target
);
if
(
ret
<
0
)
return
ret
;
len
=
ret
;
}
else
{
len
=
strlen
(
target_path
);
}
ret
=
fdt_setprop_placeholder
(
fdt
,
root_sym
,
name
,
len
+
(
len
>
1
)
+
rel_path_len
+
1
,
&
p
);
if
(
ret
<
0
)
return
ret
;
if
(
!
target_path
)
{
/* again in case setprop_placeholder changed it */
ret
=
overlay_get_target
(
fdt
,
fdto
,
fragment
,
&
target_path
);
if
(
ret
<
0
)
return
ret
;
target
=
ret
;
}
buf
=
p
;
if
(
len
>
1
)
{
/* target is not root */
if
(
!
target_path
)
{
ret
=
fdt_get_path
(
fdt
,
target
,
buf
,
len
+
1
);
if
(
ret
<
0
)
return
ret
;
}
else
memcpy
(
buf
,
target_path
,
len
+
1
);
}
else
len
--
;
buf
[
len
]
=
'/'
;
memcpy
(
buf
+
len
+
1
,
rel_path
,
rel_path_len
);
buf
[
len
+
1
+
rel_path_len
]
=
'\0'
;
}
return
0
;
}
int
fdt_overlay_apply
(
void
*
fdt
,
void
*
fdto
)
{
uint32_t
delta
=
fdt_get_max_phandle
(
fdt
);
int
ret
;
FDT_CHECK_HEADER
(
fdt
);
FDT_CHECK_HEADER
(
fdto
);
ret
=
overlay_adjust_local_phandles
(
fdto
,
delta
);
if
(
ret
)
goto
err
;
ret
=
overlay_update_local_references
(
fdto
,
delta
);
if
(
ret
)
goto
err
;
ret
=
overlay_fixup_phandles
(
fdt
,
fdto
);
if
(
ret
)
goto
err
;
ret
=
overlay_merge
(
fdt
,
fdto
);
if
(
ret
)
goto
err
;
ret
=
overlay_symbol_update
(
fdt
,
fdto
);
if
(
ret
)
goto
err
;
/*
* The overlay has been damaged, erase its magic.
*/
fdt_set_magic
(
fdto
,
~
0
);
return
0
;
err:
/*
* The overlay might have been damaged, erase its magic.
*/
fdt_set_magic
(
fdto
,
~
0
);
/*
* The base device tree might have been damaged, erase its
* magic.
*/
fdt_set_magic
(
fdt
,
~
0
);
return
ret
;
}
u-boot-tree/scripts/dtc/libfdt/fdt_ro.c
0 → 100644
View file @
7496de94
/*
* 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"
static
int
fdt_nodename_eq_
(
const
void
*
fdt
,
int
offset
,
const
char
*
s
,
int
len
)
{
int
olen
;
const
char
*
p
=
fdt_get_name
(
fdt
,
offset
,
&
olen
);
if
(
!
p
||
olen
<
len
)
/* short match */
return
0
;
if
(
memcmp
(
p
,
s
,
len
)
!=
0
)
return
0
;
if
(
p
[
len
]
==
'\0'
)
return
1
;
else
if
(
!
memchr
(
s
,
'@'
,
len
)
&&
(
p
[
len
]
==
'@'
))
return
1
;
else
return
0
;
}
const
char
*
fdt_string
(
const
void
*
fdt
,
int
stroffset
)
{
return
(
const
char
*
)
fdt
+
fdt_off_dt_strings
(
fdt
)
+
stroffset
;
}
static
int
fdt_string_eq_
(
const
void
*
fdt
,
int
stroffset
,
const
char
*
s
,
int
len
)
{
const
char
*
p
=
fdt_string
(
fdt
,
stroffset
);
return
(
strlen
(
p
)
==
len
)
&&
(
memcmp
(
p
,
s
,
len
)
==
0
);
}
uint32_t
fdt_get_max_phandle
(
const
void
*
fdt
)
{
uint32_t
max_phandle
=
0
;
int
offset
;
for
(
offset
=
fdt_next_node
(
fdt
,
-
1
,
NULL
);;
offset
=
fdt_next_node
(
fdt
,
offset
,
NULL
))
{
uint32_t
phandle
;
if
(
offset
==
-
FDT_ERR_NOTFOUND
)
return
max_phandle
;
if
(
offset
<
0
)
return
(
uint32_t
)
-
1
;
phandle
=
fdt_get_phandle
(
fdt
,
offset
);
if
(
phandle
==
(
uint32_t
)
-
1
)
continue
;
if
(
phandle
>
max_phandle
)
max_phandle
=
phandle
;
}
return
0
;
}
int
fdt_get_mem_rsv
(
const
void
*
fdt
,
int
n
,
uint64_t
*
address
,
uint64_t
*
size
)
{
FDT_CHECK_HEADER
(
fdt
);
*
address
=
fdt64_to_cpu
(
fdt_mem_rsv_
(
fdt
,
n
)
->
address
);
*
size
=
fdt64_to_cpu
(
fdt_mem_rsv_
(
fdt
,
n
)
->
size
);
return
0
;
}
int
fdt_num_mem_rsv
(
const
void
*
fdt
)
{
int
i
=
0
;
while
(
fdt64_to_cpu
(
fdt_mem_rsv_
(
fdt
,
i
)
->
size
)
!=
0
)
i
++
;
return
i
;
}
static
int
nextprop_
(
const
void
*
fdt
,
int
offset
)
{
uint32_t
tag
;
int
nextoffset
;
do
{
tag
=
fdt_next_tag
(
fdt
,
offset
,
&
nextoffset
);
switch
(
tag
)
{
case
FDT_END
:
if
(
nextoffset
>=
0
)
return
-
FDT_ERR_BADSTRUCTURE
;
else
return
nextoffset
;
case
FDT_PROP
:
return
offset
;
}
offset
=
nextoffset
;
}
while
(
tag
==
FDT_NOP
);
return
-
FDT_ERR_NOTFOUND
;
}
int
fdt_subnode_offset_namelen
(
const
void
*
fdt
,
int
offset
,
const
char
*
name
,
int
namelen
)
{
int
depth
;
FDT_CHECK_HEADER
(
fdt
);
for
(
depth
=
0
;
(
offset
>=
0
)
&&
(
depth
>=
0
);
offset
=
fdt_next_node
(
fdt
,
offset
,
&
depth
))
if
((
depth
==
1
)
&&
fdt_nodename_eq_
(
fdt
,
offset
,
name
,
namelen
))
return
offset
;
if
(
depth
<
0
)
return
-
FDT_ERR_NOTFOUND
;
return
offset
;
/* error */
}
int
fdt_subnode_offset
(
const
void
*
fdt
,
int
parentoffset
,
const
char
*
name
)
{
return
fdt_subnode_offset_namelen
(
fdt
,
parentoffset
,
name
,
strlen
(
name
));
}
int
fdt_path_offset_namelen
(
const
void
*
fdt
,
const
char
*
path
,
int
namelen
)
{
const
char
*
end
=
path
+
namelen
;
const
char
*
p
=
path
;
int
offset
=
0
;
FDT_CHECK_HEADER
(
fdt
);
/* see if we have an alias */
if
(
*
path
!=
'/'
)
{
const
char
*
q
=
memchr
(
path
,
'/'
,
end
-
p
);
if
(
!
q
)
q
=
end
;
p
=
fdt_get_alias_namelen
(
fdt
,
p
,
q
-
p
);
if
(
!
p
)
return
-
FDT_ERR_BADPATH
;
offset
=
fdt_path_offset
(
fdt
,
p
);
p
=
q
;
}
while
(
p
<
end
)
{
const
char
*
q
;
while
(
*
p
==
'/'
)
{
p
++
;
if
(
p
==
end
)
return
offset
;
}
q
=
memchr
(
p
,
'/'
,
end
-
p
);
if
(
!
q
)
q
=
end
;
offset
=
fdt_subnode_offset_namelen
(
fdt
,
offset
,
p
,
q
-
p
);
if
(
offset
<
0
)
return
offset
;
p
=
q
;
}
return
offset
;
}
int
fdt_path_offset
(
const
void
*
fdt
,
const
char
*
path
)
{
return
fdt_path_offset_namelen
(
fdt
,
path
,
strlen
(
path
));
}
const
char
*
fdt_get_name
(
const
void
*
fdt
,
int
nodeoffset
,
int
*
len
)
{
const
struct
fdt_node_header
*
nh
=
fdt_offset_ptr_
(
fdt
,
nodeoffset
);
const
char
*
nameptr
;
int
err
;
if
(((
err
=
fdt_check_header
(
fdt
))
!=
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
;
}
nameptr
=
leaf
+
1
;
}
if
(
len
)
*
len
=
strlen
(
nameptr
);
return
nameptr
;
fail:
if
(
len
)
*
len
=
err
;
return
NULL
;
}
int
fdt_first_property_offset
(
const
void
*
fdt
,
int
nodeoffset
)
{
int
offset
;
if
((
offset
=
fdt_check_node_offset_
(
fdt
,
nodeoffset
))
<
0
)
return
offset
;
return
nextprop_
(
fdt
,
offset
);
}
int
fdt_next_property_offset
(
const
void
*
fdt
,
int
offset
)
{
if
((
offset
=
fdt_check_prop_offset_
(
fdt
,
offset
))
<
0
)
return
offset
;
return
nextprop_
(
fdt
,
offset
);
}
static
const
struct
fdt_property
*
fdt_get_property_by_offset_
(
const
void
*
fdt
,
int
offset
,
int
*
lenp
)
{
int
err
;
const
struct
fdt_property
*
prop
;
if
((
err
=
fdt_check_prop_offset_
(
fdt
,
offset
))
<
0
)
{
if
(
lenp
)
*
lenp
=
err
;
return
NULL
;
}
prop
=
fdt_offset_ptr_
(
fdt
,
offset
);
if
(
lenp
)
*
lenp
=
fdt32_to_cpu
(
prop
->
len
);
return
prop
;
}
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
,
const
char
*
name
,
int
namelen
,
int
*
lenp
,
int
*
poffset
)
{
for
(
offset
=
fdt_first_property_offset
(
fdt
,
offset
);
(
offset
>=
0
);
(
offset
=
fdt_next_property_offset
(
fdt
,
offset
)))
{
const
struct
fdt_property
*
prop
;
if
(
!
(
prop
=
fdt_get_property_by_offset_
(
fdt
,
offset
,
lenp
)))
{
offset
=
-
FDT_ERR_INTERNAL
;
break
;
}
if
(
fdt_string_eq_
(
fdt
,
fdt32_to_cpu
(
prop
->
nameoff
),
name
,
namelen
))
{
if
(
poffset
)
*
poffset
=
offset
;
return
prop
;
}
}
if
(
lenp
)
*
lenp
=
offset
;
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
,
int
nodeoffset
,
const
char
*
name
,
int
*
lenp
)
{
return
fdt_get_property_namelen
(
fdt
,
nodeoffset
,
name
,
strlen
(
name
),
lenp
);
}
const
void
*
fdt_getprop_namelen
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
namelen
,
int
*
lenp
)
{
int
poffset
;
const
struct
fdt_property
*
prop
;
prop
=
fdt_get_property_namelen_
(
fdt
,
nodeoffset
,
name
,
namelen
,
lenp
,
&
poffset
);
if
(
!
prop
)
return
NULL
;
/* Handle realignment */
if
(
fdt_version
(
fdt
)
<
0x10
&&
(
poffset
+
sizeof
(
*
prop
))
%
8
&&
fdt32_to_cpu
(
prop
->
len
)
>=
8
)
return
prop
->
data
+
4
;
return
prop
->
data
;
}
const
void
*
fdt_getprop_by_offset
(
const
void
*
fdt
,
int
offset
,
const
char
**
namep
,
int
*
lenp
)
{
const
struct
fdt_property
*
prop
;
prop
=
fdt_get_property_by_offset_
(
fdt
,
offset
,
lenp
);
if
(
!
prop
)
return
NULL
;
if
(
namep
)
*
namep
=
fdt_string
(
fdt
,
fdt32_to_cpu
(
prop
->
nameoff
));
/* Handle realignment */
if
(
fdt_version
(
fdt
)
<
0x10
&&
(
offset
+
sizeof
(
*
prop
))
%
8
&&
fdt32_to_cpu
(
prop
->
len
)
>=
8
)
return
prop
->
data
+
4
;
return
prop
->
data
;
}
const
void
*
fdt_getprop
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
*
lenp
)
{
return
fdt_getprop_namelen
(
fdt
,
nodeoffset
,
name
,
strlen
(
name
),
lenp
);
}
uint32_t
fdt_get_phandle
(
const
void
*
fdt
,
int
nodeoffset
)
{
const
fdt32_t
*
php
;
int
len
;
/* FIXME: This is a bit sub-optimal, since we potentially scan
* over all the properties twice. */
php
=
fdt_getprop
(
fdt
,
nodeoffset
,
"phandle"
,
&
len
);
if
(
!
php
||
(
len
!=
sizeof
(
*
php
)))
{
php
=
fdt_getprop
(
fdt
,
nodeoffset
,
"linux,phandle"
,
&
len
);
if
(
!
php
||
(
len
!=
sizeof
(
*
php
)))
return
0
;
}
return
fdt32_to_cpu
(
*
php
);
}
const
char
*
fdt_get_alias_namelen
(
const
void
*
fdt
,
const
char
*
name
,
int
namelen
)
{
int
aliasoffset
;
aliasoffset
=
fdt_path_offset
(
fdt
,
"/aliases"
);
if
(
aliasoffset
<
0
)
return
NULL
;
return
fdt_getprop_namelen
(
fdt
,
aliasoffset
,
name
,
namelen
,
NULL
);
}
const
char
*
fdt_get_alias
(
const
void
*
fdt
,
const
char
*
name
)
{
return
fdt_get_alias_namelen
(
fdt
,
name
,
strlen
(
name
));
}
int
fdt_get_path
(
const
void
*
fdt
,
int
nodeoffset
,
char
*
buf
,
int
buflen
)
{
int
pdepth
=
0
,
p
=
0
;
int
offset
,
depth
,
namelen
;
const
char
*
name
;
FDT_CHECK_HEADER
(
fdt
);
if
(
buflen
<
2
)
return
-
FDT_ERR_NOSPACE
;
for
(
offset
=
0
,
depth
=
0
;
(
offset
>=
0
)
&&
(
offset
<=
nodeoffset
);
offset
=
fdt_next_node
(
fdt
,
offset
,
&
depth
))
{
while
(
pdepth
>
depth
)
{
do
{
p
--
;
}
while
(
buf
[
p
-
1
]
!=
'/'
);
pdepth
--
;
}
if
(
pdepth
>=
depth
)
{
name
=
fdt_get_name
(
fdt
,
offset
,
&
namelen
);
if
(
!
name
)
return
namelen
;
if
((
p
+
namelen
+
1
)
<=
buflen
)
{
memcpy
(
buf
+
p
,
name
,
namelen
);
p
+=
namelen
;
buf
[
p
++
]
=
'/'
;
pdepth
++
;
}
}
if
(
offset
==
nodeoffset
)
{
if
(
pdepth
<
(
depth
+
1
))
return
-
FDT_ERR_NOSPACE
;
if
(
p
>
1
)
/* special case so that root path is "/", not "" */
p
--
;
buf
[
p
]
=
'\0'
;
return
0
;
}
}
if
((
offset
==
-
FDT_ERR_NOTFOUND
)
||
(
offset
>=
0
))
return
-
FDT_ERR_BADOFFSET
;
else
if
(
offset
==
-
FDT_ERR_BADOFFSET
)
return
-
FDT_ERR_BADSTRUCTURE
;
return
offset
;
/* error from fdt_next_node() */
}
int
fdt_supernode_atdepth_offset
(
const
void
*
fdt
,
int
nodeoffset
,
int
supernodedepth
,
int
*
nodedepth
)
{
int
offset
,
depth
;
int
supernodeoffset
=
-
FDT_ERR_INTERNAL
;
FDT_CHECK_HEADER
(
fdt
);
if
(
supernodedepth
<
0
)
return
-
FDT_ERR_NOTFOUND
;
for
(
offset
=
0
,
depth
=
0
;
(
offset
>=
0
)
&&
(
offset
<=
nodeoffset
);
offset
=
fdt_next_node
(
fdt
,
offset
,
&
depth
))
{
if
(
depth
==
supernodedepth
)
supernodeoffset
=
offset
;
if
(
offset
==
nodeoffset
)
{
if
(
nodedepth
)
*
nodedepth
=
depth
;
if
(
supernodedepth
>
depth
)
return
-
FDT_ERR_NOTFOUND
;
else
return
supernodeoffset
;
}
}
if
((
offset
==
-
FDT_ERR_NOTFOUND
)
||
(
offset
>=
0
))
return
-
FDT_ERR_BADOFFSET
;
else
if
(
offset
==
-
FDT_ERR_BADOFFSET
)
return
-
FDT_ERR_BADSTRUCTURE
;
return
offset
;
/* error from fdt_next_node() */
}
int
fdt_node_depth
(
const
void
*
fdt
,
int
nodeoffset
)
{
int
nodedepth
;
int
err
;
err
=
fdt_supernode_atdepth_offset
(
fdt
,
nodeoffset
,
0
,
&
nodedepth
);
if
(
err
)
return
(
err
<
0
)
?
err
:
-
FDT_ERR_INTERNAL
;
return
nodedepth
;
}
int
fdt_parent_offset
(
const
void
*
fdt
,
int
nodeoffset
)
{
int
nodedepth
=
fdt_node_depth
(
fdt
,
nodeoffset
);
if
(
nodedepth
<
0
)
return
nodedepth
;
return
fdt_supernode_atdepth_offset
(
fdt
,
nodeoffset
,
nodedepth
-
1
,
NULL
);
}
int
fdt_node_offset_by_prop_value
(
const
void
*
fdt
,
int
startoffset
,
const
char
*
propname
,
const
void
*
propval
,
int
proplen
)
{
int
offset
;
const
void
*
val
;
int
len
;
FDT_CHECK_HEADER
(
fdt
);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
* find what we want, we scan over them again making our way
* to the next node. Still it's the easiest to implement
* approach; performance can come later. */
for
(
offset
=
fdt_next_node
(
fdt
,
startoffset
,
NULL
);
offset
>=
0
;
offset
=
fdt_next_node
(
fdt
,
offset
,
NULL
))
{
val
=
fdt_getprop
(
fdt
,
offset
,
propname
,
&
len
);
if
(
val
&&
(
len
==
proplen
)
&&
(
memcmp
(
val
,
propval
,
len
)
==
0
))
return
offset
;
}
return
offset
;
/* error from fdt_next_node() */
}
int
fdt_node_offset_by_phandle
(
const
void
*
fdt
,
uint32_t
phandle
)
{
int
offset
;
if
((
phandle
==
0
)
||
(
phandle
==
-
1
))
return
-
FDT_ERR_BADPHANDLE
;
FDT_CHECK_HEADER
(
fdt
);
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
* fdt_get_phandle(), then if that didn't find what
* we want, we scan over them again making our way to the next
* node. Still it's the easiest to implement approach;
* performance can come later. */
for
(
offset
=
fdt_next_node
(
fdt
,
-
1
,
NULL
);
offset
>=
0
;
offset
=
fdt_next_node
(
fdt
,
offset
,
NULL
))
{
if
(
fdt_get_phandle
(
fdt
,
offset
)
==
phandle
)
return
offset
;
}
return
offset
;
/* error from fdt_next_node() */
}
int
fdt_stringlist_contains
(
const
char
*
strlist
,
int
listlen
,
const
char
*
str
)
{
int
len
=
strlen
(
str
);
const
char
*
p
;
while
(
listlen
>=
len
)
{
if
(
memcmp
(
str
,
strlist
,
len
+
1
)
==
0
)
return
1
;
p
=
memchr
(
strlist
,
'\0'
,
listlen
);
if
(
!
p
)
return
0
;
/* malformed strlist.. */
listlen
-=
(
p
-
strlist
)
+
1
;
strlist
=
p
+
1
;
}
return
0
;
}
int
fdt_stringlist_count
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
property
)
{
const
char
*
list
,
*
end
;
int
length
,
count
=
0
;
list
=
fdt_getprop
(
fdt
,
nodeoffset
,
property
,
&
length
);
if
(
!
list
)
return
length
;
end
=
list
+
length
;
while
(
list
<
end
)
{
length
=
strnlen
(
list
,
end
-
list
)
+
1
;
/* Abort if the last string isn't properly NUL-terminated. */
if
(
list
+
length
>
end
)
return
-
FDT_ERR_BADVALUE
;
list
+=
length
;
count
++
;
}
return
count
;
}
int
fdt_stringlist_search
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
property
,
const
char
*
string
)
{
int
length
,
len
,
idx
=
0
;
const
char
*
list
,
*
end
;
list
=
fdt_getprop
(
fdt
,
nodeoffset
,
property
,
&
length
);
if
(
!
list
)
return
length
;
len
=
strlen
(
string
)
+
1
;
end
=
list
+
length
;
while
(
list
<
end
)
{
length
=
strnlen
(
list
,
end
-
list
)
+
1
;
/* Abort if the last string isn't properly NUL-terminated. */
if
(
list
+
length
>
end
)
return
-
FDT_ERR_BADVALUE
;
if
(
length
==
len
&&
memcmp
(
list
,
string
,
length
)
==
0
)
return
idx
;
list
+=
length
;
idx
++
;
}
return
-
FDT_ERR_NOTFOUND
;
}
const
char
*
fdt_stringlist_get
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
property
,
int
idx
,
int
*
lenp
)
{
const
char
*
list
,
*
end
;
int
length
;
list
=
fdt_getprop
(
fdt
,
nodeoffset
,
property
,
&
length
);
if
(
!
list
)
{
if
(
lenp
)
*
lenp
=
length
;
return
NULL
;
}
end
=
list
+
length
;
while
(
list
<
end
)
{
length
=
strnlen
(
list
,
end
-
list
)
+
1
;
/* Abort if the last string isn't properly NUL-terminated. */
if
(
list
+
length
>
end
)
{
if
(
lenp
)
*
lenp
=
-
FDT_ERR_BADVALUE
;
return
NULL
;
}
if
(
idx
==
0
)
{
if
(
lenp
)
*
lenp
=
length
-
1
;
return
list
;
}
list
+=
length
;
idx
--
;
}
if
(
lenp
)
*
lenp
=
-
FDT_ERR_NOTFOUND
;
return
NULL
;
}
int
fdt_node_check_compatible
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
compatible
)
{
const
void
*
prop
;
int
len
;
prop
=
fdt_getprop
(
fdt
,
nodeoffset
,
"compatible"
,
&
len
);
if
(
!
prop
)
return
len
;
return
!
fdt_stringlist_contains
(
prop
,
len
,
compatible
);
}
int
fdt_node_offset_by_compatible
(
const
void
*
fdt
,
int
startoffset
,
const
char
*
compatible
)
{
int
offset
,
err
;
FDT_CHECK_HEADER
(
fdt
);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
* that didn't find what we want, we scan over them again
* making our way to the next node. Still it's the easiest to
* implement approach; performance can come later. */
for
(
offset
=
fdt_next_node
(
fdt
,
startoffset
,
NULL
);
offset
>=
0
;
offset
=
fdt_next_node
(
fdt
,
offset
,
NULL
))
{
err
=
fdt_node_check_compatible
(
fdt
,
offset
,
compatible
);
if
((
err
<
0
)
&&
(
err
!=
-
FDT_ERR_NOTFOUND
))
return
err
;
else
if
(
err
==
0
)
return
offset
;
}
return
offset
;
/* error from fdt_next_node() */
}
u-boot-tree/scripts/dtc/libfdt/fdt_rw.c
0 → 100644
View file @
7496de94
/*
* 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"
static
int
fdt_blocks_misordered_
(
const
void
*
fdt
,
int
mem_rsv_size
,
int
struct_size
)
{
return
(
fdt_off_mem_rsvmap
(
fdt
)
<
FDT_ALIGN
(
sizeof
(
struct
fdt_header
),
8
))
||
(
fdt_off_dt_struct
(
fdt
)
<
(
fdt_off_mem_rsvmap
(
fdt
)
+
mem_rsv_size
))
||
(
fdt_off_dt_strings
(
fdt
)
<
(
fdt_off_dt_struct
(
fdt
)
+
struct_size
))
||
(
fdt_totalsize
(
fdt
)
<
(
fdt_off_dt_strings
(
fdt
)
+
fdt_size_dt_strings
(
fdt
)));
}
static
int
fdt_rw_check_header_
(
void
*
fdt
)
{
FDT_CHECK_HEADER
(
fdt
);
if
(
fdt_version
(
fdt
)
<
17
)
return
-
FDT_ERR_BADVERSION
;
if
(
fdt_blocks_misordered_
(
fdt
,
sizeof
(
struct
fdt_reserve_entry
),
fdt_size_dt_struct
(
fdt
)))
return
-
FDT_ERR_BADLAYOUT
;
if
(
fdt_version
(
fdt
)
>
17
)
fdt_set_version
(
fdt
,
17
);
return
0
;
}
#define FDT_RW_CHECK_HEADER(fdt) \
{ \
int err_; \
if ((err_ = fdt_rw_check_header_(fdt)) != 0) \
return err_; \
}
static
inline
int
fdt_data_size_
(
void
*
fdt
)
{
return
fdt_off_dt_strings
(
fdt
)
+
fdt_size_dt_strings
(
fdt
);
}
static
int
fdt_splice_
(
void
*
fdt
,
void
*
splicepoint
,
int
oldlen
,
int
newlen
)
{
char
*
p
=
splicepoint
;
char
*
end
=
(
char
*
)
fdt
+
fdt_data_size_
(
fdt
);
if
(((
p
+
oldlen
)
<
p
)
||
((
p
+
oldlen
)
>
end
))
return
-
FDT_ERR_BADOFFSET
;
if
((
p
<
(
char
*
)
fdt
)
||
((
end
-
oldlen
+
newlen
)
<
(
char
*
)
fdt
))
return
-
FDT_ERR_BADOFFSET
;
if
((
end
-
oldlen
+
newlen
)
>
((
char
*
)
fdt
+
fdt_totalsize
(
fdt
)))
return
-
FDT_ERR_NOSPACE
;
memmove
(
p
+
newlen
,
p
+
oldlen
,
end
-
p
-
oldlen
);
return
0
;
}
static
int
fdt_splice_mem_rsv_
(
void
*
fdt
,
struct
fdt_reserve_entry
*
p
,
int
oldn
,
int
newn
)
{
int
delta
=
(
newn
-
oldn
)
*
sizeof
(
*
p
);
int
err
;
err
=
fdt_splice_
(
fdt
,
p
,
oldn
*
sizeof
(
*
p
),
newn
*
sizeof
(
*
p
));
if
(
err
)
return
err
;
fdt_set_off_dt_struct
(
fdt
,
fdt_off_dt_struct
(
fdt
)
+
delta
);
fdt_set_off_dt_strings
(
fdt
,
fdt_off_dt_strings
(
fdt
)
+
delta
);
return
0
;
}
static
int
fdt_splice_struct_
(
void
*
fdt
,
void
*
p
,
int
oldlen
,
int
newlen
)
{
int
delta
=
newlen
-
oldlen
;
int
err
;
if
((
err
=
fdt_splice_
(
fdt
,
p
,
oldlen
,
newlen
)))
return
err
;
fdt_set_size_dt_struct
(
fdt
,
fdt_size_dt_struct
(
fdt
)
+
delta
);
fdt_set_off_dt_strings
(
fdt
,
fdt_off_dt_strings
(
fdt
)
+
delta
);
return
0
;
}
static
int
fdt_splice_string_
(
void
*
fdt
,
int
newlen
)
{
void
*
p
=
(
char
*
)
fdt
+
fdt_off_dt_strings
(
fdt
)
+
fdt_size_dt_strings
(
fdt
);
int
err
;
if
((
err
=
fdt_splice_
(
fdt
,
p
,
0
,
newlen
)))
return
err
;
fdt_set_size_dt_strings
(
fdt
,
fdt_size_dt_strings
(
fdt
)
+
newlen
);
return
0
;
}
static
int
fdt_find_add_string_
(
void
*
fdt
,
const
char
*
s
)
{
char
*
strtab
=
(
char
*
)
fdt
+
fdt_off_dt_strings
(
fdt
);
const
char
*
p
;
char
*
new
;
int
len
=
strlen
(
s
)
+
1
;
int
err
;
p
=
fdt_find_string_
(
strtab
,
fdt_size_dt_strings
(
fdt
),
s
);
if
(
p
)
/* found it */
return
(
p
-
strtab
);
new
=
strtab
+
fdt_size_dt_strings
(
fdt
);
err
=
fdt_splice_string_
(
fdt
,
len
);
if
(
err
)
return
err
;
memcpy
(
new
,
s
,
len
);
return
(
new
-
strtab
);
}
int
fdt_add_mem_rsv
(
void
*
fdt
,
uint64_t
address
,
uint64_t
size
)
{
struct
fdt_reserve_entry
*
re
;
int
err
;
FDT_RW_CHECK_HEADER
(
fdt
);
re
=
fdt_mem_rsv_w_
(
fdt
,
fdt_num_mem_rsv
(
fdt
));
err
=
fdt_splice_mem_rsv_
(
fdt
,
re
,
0
,
1
);
if
(
err
)
return
err
;
re
->
address
=
cpu_to_fdt64
(
address
);
re
->
size
=
cpu_to_fdt64
(
size
);
return
0
;
}
int
fdt_del_mem_rsv
(
void
*
fdt
,
int
n
)
{
struct
fdt_reserve_entry
*
re
=
fdt_mem_rsv_w_
(
fdt
,
n
);
FDT_RW_CHECK_HEADER
(
fdt
);
if
(
n
>=
fdt_num_mem_rsv
(
fdt
))
return
-
FDT_ERR_NOTFOUND
;
return
fdt_splice_mem_rsv_
(
fdt
,
re
,
1
,
0
);
}
static
int
fdt_resize_property_
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
len
,
struct
fdt_property
**
prop
)
{
int
oldlen
;
int
err
;
*
prop
=
fdt_get_property_w
(
fdt
,
nodeoffset
,
name
,
&
oldlen
);
if
(
!*
prop
)
return
oldlen
;
if
((
err
=
fdt_splice_struct_
(
fdt
,
(
*
prop
)
->
data
,
FDT_TAGALIGN
(
oldlen
),
FDT_TAGALIGN
(
len
))))
return
err
;
(
*
prop
)
->
len
=
cpu_to_fdt32
(
len
);
return
0
;
}
static
int
fdt_add_property_
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
len
,
struct
fdt_property
**
prop
)
{
int
proplen
;
int
nextoffset
;
int
namestroff
;
int
err
;
if
((
nextoffset
=
fdt_check_node_offset_
(
fdt
,
nodeoffset
))
<
0
)
return
nextoffset
;
namestroff
=
fdt_find_add_string_
(
fdt
,
name
);
if
(
namestroff
<
0
)
return
namestroff
;
*
prop
=
fdt_offset_ptr_w_
(
fdt
,
nextoffset
);
proplen
=
sizeof
(
**
prop
)
+
FDT_TAGALIGN
(
len
);
err
=
fdt_splice_struct_
(
fdt
,
*
prop
,
0
,
proplen
);
if
(
err
)
return
err
;
(
*
prop
)
->
tag
=
cpu_to_fdt32
(
FDT_PROP
);
(
*
prop
)
->
nameoff
=
cpu_to_fdt32
(
namestroff
);
(
*
prop
)
->
len
=
cpu_to_fdt32
(
len
);
return
0
;
}
int
fdt_set_name
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
)
{
char
*
namep
;
int
oldlen
,
newlen
;
int
err
;
FDT_RW_CHECK_HEADER
(
fdt
);
namep
=
(
char
*
)(
uintptr_t
)
fdt_get_name
(
fdt
,
nodeoffset
,
&
oldlen
);
if
(
!
namep
)
return
oldlen
;
newlen
=
strlen
(
name
);
err
=
fdt_splice_struct_
(
fdt
,
namep
,
FDT_TAGALIGN
(
oldlen
+
1
),
FDT_TAGALIGN
(
newlen
+
1
));
if
(
err
)
return
err
;
memcpy
(
namep
,
name
,
newlen
+
1
);
return
0
;
}
int
fdt_setprop_placeholder
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
len
,
void
**
prop_data
)
{
struct
fdt_property
*
prop
;
int
err
;
FDT_RW_CHECK_HEADER
(
fdt
);
err
=
fdt_resize_property_
(
fdt
,
nodeoffset
,
name
,
len
,
&
prop
);
if
(
err
==
-
FDT_ERR_NOTFOUND
)
err
=
fdt_add_property_
(
fdt
,
nodeoffset
,
name
,
len
,
&
prop
);
if
(
err
)
return
err
;
*
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
;
}
int
fdt_appendprop
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
const
void
*
val
,
int
len
)
{
struct
fdt_property
*
prop
;
int
err
,
oldlen
,
newlen
;
FDT_RW_CHECK_HEADER
(
fdt
);
prop
=
fdt_get_property_w
(
fdt
,
nodeoffset
,
name
,
&
oldlen
);
if
(
prop
)
{
newlen
=
len
+
oldlen
;
err
=
fdt_splice_struct_
(
fdt
,
prop
->
data
,
FDT_TAGALIGN
(
oldlen
),
FDT_TAGALIGN
(
newlen
));
if
(
err
)
return
err
;
prop
->
len
=
cpu_to_fdt32
(
newlen
);
memcpy
(
prop
->
data
+
oldlen
,
val
,
len
);
}
else
{
err
=
fdt_add_property_
(
fdt
,
nodeoffset
,
name
,
len
,
&
prop
);
if
(
err
)
return
err
;
memcpy
(
prop
->
data
,
val
,
len
);
}
return
0
;
}
int
fdt_delprop
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
)
{
struct
fdt_property
*
prop
;
int
len
,
proplen
;
FDT_RW_CHECK_HEADER
(
fdt
);
prop
=
fdt_get_property_w
(
fdt
,
nodeoffset
,
name
,
&
len
);
if
(
!
prop
)
return
len
;
proplen
=
sizeof
(
*
prop
)
+
FDT_TAGALIGN
(
len
);
return
fdt_splice_struct_
(
fdt
,
prop
,
proplen
,
0
);
}
int
fdt_add_subnode_namelen
(
void
*
fdt
,
int
parentoffset
,
const
char
*
name
,
int
namelen
)
{
struct
fdt_node_header
*
nh
;
int
offset
,
nextoffset
;
int
nodelen
;
int
err
;
uint32_t
tag
;
fdt32_t
*
endtag
;
FDT_RW_CHECK_HEADER
(
fdt
);
offset
=
fdt_subnode_offset_namelen
(
fdt
,
parentoffset
,
name
,
namelen
);
if
(
offset
>=
0
)
return
-
FDT_ERR_EXISTS
;
else
if
(
offset
!=
-
FDT_ERR_NOTFOUND
)
return
offset
;
/* Try to place the new node after the parent's properties */
fdt_next_tag
(
fdt
,
parentoffset
,
&
nextoffset
);
/* skip the BEGIN_NODE */
do
{
offset
=
nextoffset
;
tag
=
fdt_next_tag
(
fdt
,
offset
,
&
nextoffset
);
}
while
((
tag
==
FDT_PROP
)
||
(
tag
==
FDT_NOP
));
nh
=
fdt_offset_ptr_w_
(
fdt
,
offset
);
nodelen
=
sizeof
(
*
nh
)
+
FDT_TAGALIGN
(
namelen
+
1
)
+
FDT_TAGSIZE
;
err
=
fdt_splice_struct_
(
fdt
,
nh
,
0
,
nodelen
);
if
(
err
)
return
err
;
nh
->
tag
=
cpu_to_fdt32
(
FDT_BEGIN_NODE
);
memset
(
nh
->
name
,
0
,
FDT_TAGALIGN
(
namelen
+
1
));
memcpy
(
nh
->
name
,
name
,
namelen
);
endtag
=
(
fdt32_t
*
)((
char
*
)
nh
+
nodelen
-
FDT_TAGSIZE
);
*
endtag
=
cpu_to_fdt32
(
FDT_END_NODE
);
return
offset
;
}
int
fdt_add_subnode
(
void
*
fdt
,
int
parentoffset
,
const
char
*
name
)
{
return
fdt_add_subnode_namelen
(
fdt
,
parentoffset
,
name
,
strlen
(
name
));
}
int
fdt_del_node
(
void
*
fdt
,
int
nodeoffset
)
{
int
endoffset
;
FDT_RW_CHECK_HEADER
(
fdt
);
endoffset
=
fdt_node_end_offset_
(
fdt
,
nodeoffset
);
if
(
endoffset
<
0
)
return
endoffset
;
return
fdt_splice_struct_
(
fdt
,
fdt_offset_ptr_w_
(
fdt
,
nodeoffset
),
endoffset
-
nodeoffset
,
0
);
}
static
void
fdt_packblocks_
(
const
char
*
old
,
char
*
new
,
int
mem_rsv_size
,
int
struct_size
)
{
int
mem_rsv_off
,
struct_off
,
strings_off
;
mem_rsv_off
=
FDT_ALIGN
(
sizeof
(
struct
fdt_header
),
8
);
struct_off
=
mem_rsv_off
+
mem_rsv_size
;
strings_off
=
struct_off
+
struct_size
;
memmove
(
new
+
mem_rsv_off
,
old
+
fdt_off_mem_rsvmap
(
old
),
mem_rsv_size
);
fdt_set_off_mem_rsvmap
(
new
,
mem_rsv_off
);
memmove
(
new
+
struct_off
,
old
+
fdt_off_dt_struct
(
old
),
struct_size
);
fdt_set_off_dt_struct
(
new
,
struct_off
);
fdt_set_size_dt_struct
(
new
,
struct_size
);
memmove
(
new
+
strings_off
,
old
+
fdt_off_dt_strings
(
old
),
fdt_size_dt_strings
(
old
));
fdt_set_off_dt_strings
(
new
,
strings_off
);
fdt_set_size_dt_strings
(
new
,
fdt_size_dt_strings
(
old
));
}
int
fdt_open_into
(
const
void
*
fdt
,
void
*
buf
,
int
bufsize
)
{
int
err
;
int
mem_rsv_size
,
struct_size
;
int
newsize
;
const
char
*
fdtstart
=
fdt
;
const
char
*
fdtend
=
fdtstart
+
fdt_totalsize
(
fdt
);
char
*
tmp
;
FDT_CHECK_HEADER
(
fdt
);
mem_rsv_size
=
(
fdt_num_mem_rsv
(
fdt
)
+
1
)
*
sizeof
(
struct
fdt_reserve_entry
);
if
(
fdt_version
(
fdt
)
>=
17
)
{
struct_size
=
fdt_size_dt_struct
(
fdt
);
}
else
{
struct_size
=
0
;
while
(
fdt_next_tag
(
fdt
,
struct_size
,
&
struct_size
)
!=
FDT_END
)
;
if
(
struct_size
<
0
)
return
struct_size
;
}
if
(
!
fdt_blocks_misordered_
(
fdt
,
mem_rsv_size
,
struct_size
))
{
/* no further work necessary */
err
=
fdt_move
(
fdt
,
buf
,
bufsize
);
if
(
err
)
return
err
;
fdt_set_version
(
buf
,
17
);
fdt_set_size_dt_struct
(
buf
,
struct_size
);
fdt_set_totalsize
(
buf
,
bufsize
);
return
0
;
}
/* Need to reorder */
newsize
=
FDT_ALIGN
(
sizeof
(
struct
fdt_header
),
8
)
+
mem_rsv_size
+
struct_size
+
fdt_size_dt_strings
(
fdt
);
if
(
bufsize
<
newsize
)
return
-
FDT_ERR_NOSPACE
;
/* First attempt to build converted tree at beginning of buffer */
tmp
=
buf
;
/* But if that overlaps with the old tree... */
if
(((
tmp
+
newsize
)
>
fdtstart
)
&&
(
tmp
<
fdtend
))
{
/* Try right after the old tree instead */
tmp
=
(
char
*
)(
uintptr_t
)
fdtend
;
if
((
tmp
+
newsize
)
>
((
char
*
)
buf
+
bufsize
))
return
-
FDT_ERR_NOSPACE
;
}
fdt_packblocks_
(
fdt
,
tmp
,
mem_rsv_size
,
struct_size
);
memmove
(
buf
,
tmp
,
newsize
);
fdt_set_magic
(
buf
,
FDT_MAGIC
);
fdt_set_totalsize
(
buf
,
bufsize
);
fdt_set_version
(
buf
,
17
);
fdt_set_last_comp_version
(
buf
,
16
);
fdt_set_boot_cpuid_phys
(
buf
,
fdt_boot_cpuid_phys
(
fdt
));
return
0
;
}
int
fdt_pack
(
void
*
fdt
)
{
int
mem_rsv_size
;
FDT_RW_CHECK_HEADER
(
fdt
);
mem_rsv_size
=
(
fdt_num_mem_rsv
(
fdt
)
+
1
)
*
sizeof
(
struct
fdt_reserve_entry
);
fdt_packblocks_
(
fdt
,
fdt
,
mem_rsv_size
,
fdt_size_dt_struct
(
fdt
));
fdt_set_totalsize
(
fdt
,
fdt_data_size_
(
fdt
));
return
0
;
}
u-boot-tree/scripts/dtc/libfdt/fdt_strerror.c
0 → 100644
View file @
7496de94
/*
* 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"
struct
fdt_errtabent
{
const
char
*
str
;
};
#define FDT_ERRTABENT(val) \
[(val)] = { .str = #val, }
static
struct
fdt_errtabent
fdt_errtable
[]
=
{
FDT_ERRTABENT
(
FDT_ERR_NOTFOUND
),
FDT_ERRTABENT
(
FDT_ERR_EXISTS
),
FDT_ERRTABENT
(
FDT_ERR_NOSPACE
),
FDT_ERRTABENT
(
FDT_ERR_BADOFFSET
),
FDT_ERRTABENT
(
FDT_ERR_BADPATH
),
FDT_ERRTABENT
(
FDT_ERR_BADPHANDLE
),
FDT_ERRTABENT
(
FDT_ERR_BADSTATE
),
FDT_ERRTABENT
(
FDT_ERR_TRUNCATED
),
FDT_ERRTABENT
(
FDT_ERR_BADMAGIC
),
FDT_ERRTABENT
(
FDT_ERR_BADVERSION
),
FDT_ERRTABENT
(
FDT_ERR_BADSTRUCTURE
),
FDT_ERRTABENT
(
FDT_ERR_BADLAYOUT
),
FDT_ERRTABENT
(
FDT_ERR_INTERNAL
),
FDT_ERRTABENT
(
FDT_ERR_BADNCELLS
),
FDT_ERRTABENT
(
FDT_ERR_BADVALUE
),
FDT_ERRTABENT
(
FDT_ERR_BADOVERLAY
),
FDT_ERRTABENT
(
FDT_ERR_NOPHANDLES
),
};
#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
const
char
*
fdt_strerror
(
int
errval
)
{
if
(
errval
>
0
)
return
"<valid offset/length>"
;
else
if
(
errval
==
0
)
return
"<no error>"
;
else
if
(
errval
>
-
FDT_ERRTABSIZE
)
{
const
char
*
s
=
fdt_errtable
[
-
errval
].
str
;
if
(
s
)
return
s
;
}
return
"<unknown error>"
;
}
u-boot-tree/scripts/dtc/libfdt/fdt_sw.c
0 → 100644
View file @
7496de94
/*
* 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"
static
int
fdt_sw_check_header_
(
void
*
fdt
)
{
if
(
fdt_magic
(
fdt
)
!=
FDT_SW_MAGIC
)
return
-
FDT_ERR_BADMAGIC
;
/* FIXME: should check more details about the header state */
return
0
;
}
#define FDT_SW_CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = fdt_sw_check_header_(fdt)) != 0) \
return err; \
}
static
void
*
fdt_grab_space_
(
void
*
fdt
,
size_t
len
)
{
int
offset
=
fdt_size_dt_struct
(
fdt
);
int
spaceleft
;
spaceleft
=
fdt_totalsize
(
fdt
)
-
fdt_off_dt_struct
(
fdt
)
-
fdt_size_dt_strings
(
fdt
);
if
((
offset
+
len
<
offset
)
||
(
offset
+
len
>
spaceleft
))
return
NULL
;
fdt_set_size_dt_struct
(
fdt
,
offset
+
len
);
return
fdt_offset_ptr_w_
(
fdt
,
offset
);
}
int
fdt_create
(
void
*
buf
,
int
bufsize
)
{
void
*
fdt
=
buf
;
if
(
bufsize
<
sizeof
(
struct
fdt_header
))
return
-
FDT_ERR_NOSPACE
;
memset
(
buf
,
0
,
bufsize
);
fdt_set_magic
(
fdt
,
FDT_SW_MAGIC
);
fdt_set_version
(
fdt
,
FDT_LAST_SUPPORTED_VERSION
);
fdt_set_last_comp_version
(
fdt
,
FDT_FIRST_SUPPORTED_VERSION
);
fdt_set_totalsize
(
fdt
,
bufsize
);
fdt_set_off_mem_rsvmap
(
fdt
,
FDT_ALIGN
(
sizeof
(
struct
fdt_header
),
sizeof
(
struct
fdt_reserve_entry
)));
fdt_set_off_dt_struct
(
fdt
,
fdt_off_mem_rsvmap
(
fdt
));
fdt_set_off_dt_strings
(
fdt
,
bufsize
);
return
0
;
}
int
fdt_resize
(
void
*
fdt
,
void
*
buf
,
int
bufsize
)
{
size_t
headsize
,
tailsize
;
char
*
oldtail
,
*
newtail
;
FDT_SW_CHECK_HEADER
(
fdt
);
headsize
=
fdt_off_dt_struct
(
fdt
);
tailsize
=
fdt_size_dt_strings
(
fdt
);
if
((
headsize
+
tailsize
)
>
bufsize
)
return
-
FDT_ERR_NOSPACE
;
oldtail
=
(
char
*
)
fdt
+
fdt_totalsize
(
fdt
)
-
tailsize
;
newtail
=
(
char
*
)
buf
+
bufsize
-
tailsize
;
/* Two cases to avoid clobbering data if the old and new
* buffers partially overlap */
if
(
buf
<=
fdt
)
{
memmove
(
buf
,
fdt
,
headsize
);
memmove
(
newtail
,
oldtail
,
tailsize
);
}
else
{
memmove
(
newtail
,
oldtail
,
tailsize
);
memmove
(
buf
,
fdt
,
headsize
);
}
fdt_set_off_dt_strings
(
buf
,
bufsize
);
fdt_set_totalsize
(
buf
,
bufsize
);
return
0
;
}
int
fdt_add_reservemap_entry
(
void
*
fdt
,
uint64_t
addr
,
uint64_t
size
)
{
struct
fdt_reserve_entry
*
re
;
int
offset
;
FDT_SW_CHECK_HEADER
(
fdt
);
if
(
fdt_size_dt_struct
(
fdt
))
return
-
FDT_ERR_BADSTATE
;
offset
=
fdt_off_dt_struct
(
fdt
);
if
((
offset
+
sizeof
(
*
re
))
>
fdt_totalsize
(
fdt
))
return
-
FDT_ERR_NOSPACE
;
re
=
(
struct
fdt_reserve_entry
*
)((
char
*
)
fdt
+
offset
);
re
->
address
=
cpu_to_fdt64
(
addr
);
re
->
size
=
cpu_to_fdt64
(
size
);
fdt_set_off_dt_struct
(
fdt
,
offset
+
sizeof
(
*
re
));
return
0
;
}
int
fdt_finish_reservemap
(
void
*
fdt
)
{
return
fdt_add_reservemap_entry
(
fdt
,
0
,
0
);
}
int
fdt_begin_node
(
void
*
fdt
,
const
char
*
name
)
{
struct
fdt_node_header
*
nh
;
int
namelen
=
strlen
(
name
)
+
1
;
FDT_SW_CHECK_HEADER
(
fdt
);
nh
=
fdt_grab_space_
(
fdt
,
sizeof
(
*
nh
)
+
FDT_TAGALIGN
(
namelen
));
if
(
!
nh
)
return
-
FDT_ERR_NOSPACE
;
nh
->
tag
=
cpu_to_fdt32
(
FDT_BEGIN_NODE
);
memcpy
(
nh
->
name
,
name
,
namelen
);
return
0
;
}
int
fdt_end_node
(
void
*
fdt
)
{
fdt32_t
*
en
;
FDT_SW_CHECK_HEADER
(
fdt
);
en
=
fdt_grab_space_
(
fdt
,
FDT_TAGSIZE
);
if
(
!
en
)
return
-
FDT_ERR_NOSPACE
;
*
en
=
cpu_to_fdt32
(
FDT_END_NODE
);
return
0
;
}
static
int
fdt_find_add_string_
(
void
*
fdt
,
const
char
*
s
)
{
char
*
strtab
=
(
char
*
)
fdt
+
fdt_totalsize
(
fdt
);
const
char
*
p
;
int
strtabsize
=
fdt_size_dt_strings
(
fdt
);
int
len
=
strlen
(
s
)
+
1
;
int
struct_top
,
offset
;
p
=
fdt_find_string_
(
strtab
-
strtabsize
,
strtabsize
,
s
);
if
(
p
)
return
p
-
strtab
;
/* Add it */
offset
=
-
strtabsize
-
len
;
struct_top
=
fdt_off_dt_struct
(
fdt
)
+
fdt_size_dt_struct
(
fdt
);
if
(
fdt_totalsize
(
fdt
)
+
offset
<
struct_top
)
return
0
;
/* no more room :( */
memcpy
(
strtab
+
offset
,
s
,
len
);
fdt_set_size_dt_strings
(
fdt
,
strtabsize
+
len
);
return
offset
;
}
int
fdt_property_placeholder
(
void
*
fdt
,
const
char
*
name
,
int
len
,
void
**
valp
)
{
struct
fdt_property
*
prop
;
int
nameoff
;
FDT_SW_CHECK_HEADER
(
fdt
);
nameoff
=
fdt_find_add_string_
(
fdt
,
name
);
if
(
nameoff
==
0
)
return
-
FDT_ERR_NOSPACE
;
prop
=
fdt_grab_space_
(
fdt
,
sizeof
(
*
prop
)
+
FDT_TAGALIGN
(
len
));
if
(
!
prop
)
return
-
FDT_ERR_NOSPACE
;
prop
->
tag
=
cpu_to_fdt32
(
FDT_PROP
);
prop
->
nameoff
=
cpu_to_fdt32
(
nameoff
);
prop
->
len
=
cpu_to_fdt32
(
len
);
*
valp
=
prop
->
data
;
return
0
;
}
int
fdt_property
(
void
*
fdt
,
const
char
*
name
,
const
void
*
val
,
int
len
)
{
void
*
ptr
;
int
ret
;
ret
=
fdt_property_placeholder
(
fdt
,
name
,
len
,
&
ptr
);
if
(
ret
)
return
ret
;
memcpy
(
ptr
,
val
,
len
);
return
0
;
}
int
fdt_finish
(
void
*
fdt
)
{
char
*
p
=
(
char
*
)
fdt
;
fdt32_t
*
end
;
int
oldstroffset
,
newstroffset
;
uint32_t
tag
;
int
offset
,
nextoffset
;
FDT_SW_CHECK_HEADER
(
fdt
);
/* Add terminator */
end
=
fdt_grab_space_
(
fdt
,
sizeof
(
*
end
));
if
(
!
end
)
return
-
FDT_ERR_NOSPACE
;
*
end
=
cpu_to_fdt32
(
FDT_END
);
/* Relocate the string table */
oldstroffset
=
fdt_totalsize
(
fdt
)
-
fdt_size_dt_strings
(
fdt
);
newstroffset
=
fdt_off_dt_struct
(
fdt
)
+
fdt_size_dt_struct
(
fdt
);
memmove
(
p
+
newstroffset
,
p
+
oldstroffset
,
fdt_size_dt_strings
(
fdt
));
fdt_set_off_dt_strings
(
fdt
,
newstroffset
);
/* Walk the structure, correcting string offsets */
offset
=
0
;
while
((
tag
=
fdt_next_tag
(
fdt
,
offset
,
&
nextoffset
))
!=
FDT_END
)
{
if
(
tag
==
FDT_PROP
)
{
struct
fdt_property
*
prop
=
fdt_offset_ptr_w_
(
fdt
,
offset
);
int
nameoff
;
nameoff
=
fdt32_to_cpu
(
prop
->
nameoff
);
nameoff
+=
fdt_size_dt_strings
(
fdt
);
prop
->
nameoff
=
cpu_to_fdt32
(
nameoff
);
}
offset
=
nextoffset
;
}
if
(
nextoffset
<
0
)
return
nextoffset
;
/* Finally, adjust the header */
fdt_set_totalsize
(
fdt
,
newstroffset
+
fdt_size_dt_strings
(
fdt
));
fdt_set_magic
(
fdt
,
FDT_MAGIC
);
return
0
;
}
u-boot-tree/scripts/dtc/libfdt/fdt_wip.c
0 → 100644
View file @
7496de94
/*
* 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_setprop_inplace_namelen_partial
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
namelen
,
uint32_t
idx
,
const
void
*
val
,
int
len
)
{
void
*
propval
;
int
proplen
;
propval
=
fdt_getprop_namelen_w
(
fdt
,
nodeoffset
,
name
,
namelen
,
&
proplen
);
if
(
!
propval
)
return
proplen
;
if
(
proplen
<
(
len
+
idx
))
return
-
FDT_ERR_NOSPACE
;
memcpy
((
char
*
)
propval
+
idx
,
val
,
len
);
return
0
;
}
int
fdt_setprop_inplace
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
const
void
*
val
,
int
len
)
{
const
void
*
propval
;
int
proplen
;
propval
=
fdt_getprop
(
fdt
,
nodeoffset
,
name
,
&
proplen
);
if
(
!
propval
)
return
proplen
;
if
(
proplen
!=
len
)
return
-
FDT_ERR_NOSPACE
;
return
fdt_setprop_inplace_namelen_partial
(
fdt
,
nodeoffset
,
name
,
strlen
(
name
),
0
,
val
,
len
);
}
static
void
fdt_nop_region_
(
void
*
start
,
int
len
)
{
fdt32_t
*
p
;
for
(
p
=
start
;
(
char
*
)
p
<
((
char
*
)
start
+
len
);
p
++
)
*
p
=
cpu_to_fdt32
(
FDT_NOP
);
}
int
fdt_nop_property
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
)
{
struct
fdt_property
*
prop
;
int
len
;
prop
=
fdt_get_property_w
(
fdt
,
nodeoffset
,
name
,
&
len
);
if
(
!
prop
)
return
len
;
fdt_nop_region_
(
prop
,
len
+
sizeof
(
*
prop
));
return
0
;
}
int
fdt_node_end_offset_
(
void
*
fdt
,
int
offset
)
{
int
depth
=
0
;
while
((
offset
>=
0
)
&&
(
depth
>=
0
))
offset
=
fdt_next_node
(
fdt
,
offset
,
&
depth
);
return
offset
;
}
int
fdt_nop_node
(
void
*
fdt
,
int
nodeoffset
)
{
int
endoffset
;
endoffset
=
fdt_node_end_offset_
(
fdt
,
nodeoffset
);
if
(
endoffset
<
0
)
return
endoffset
;
fdt_nop_region_
(
fdt_offset_ptr_w
(
fdt
,
nodeoffset
,
0
),
endoffset
-
nodeoffset
);
return
0
;
}
u-boot-tree/scripts/dtc/libfdt/libfdt.h
0 → 100644
View file @
7496de94
#ifndef LIBFDT_H
#define LIBFDT_H
/*
* 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"
#define FDT_FIRST_SUPPORTED_VERSION 0x02
#define FDT_LAST_SUPPORTED_VERSION 0x11
/* Error codes: informative error codes */
#define FDT_ERR_NOTFOUND 1
/* FDT_ERR_NOTFOUND: The requested node or property does not exist */
#define FDT_ERR_EXISTS 2
/* FDT_ERR_EXISTS: Attempted to create a node or property which
* already exists */
#define FDT_ERR_NOSPACE 3
/* FDT_ERR_NOSPACE: Operation needed to expand the device
* tree, but its buffer did not have sufficient space to
* contain the expanded tree. Use fdt_open_into() to move the
* device tree to a buffer with more space. */
/* Error codes: codes for bad parameters */
#define FDT_ERR_BADOFFSET 4
/* FDT_ERR_BADOFFSET: Function was passed a structure block
* offset which is out-of-bounds, or which points to an
* unsuitable part of the structure for the operation. */
#define FDT_ERR_BADPATH 5
/* FDT_ERR_BADPATH: Function was passed a badly formatted path
* (e.g. missing a leading / for a function which requires an
* absolute path) */
#define FDT_ERR_BADPHANDLE 6
/* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle.
* 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
/* FDT_ERR_BADSTATE: Function was passed an incomplete device
* tree created by the sequential-write functions, which is
* not sufficiently complete for the requested operation. */
/* Error codes: codes for bad device tree blobs */
#define FDT_ERR_TRUNCATED 8
/* FDT_ERR_TRUNCATED: Structure block of the given device tree
* ends without an FDT_END tag. */
#define FDT_ERR_BADMAGIC 9
/* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
* device tree at all - it is missing the flattened device
* tree magic number. */
#define FDT_ERR_BADVERSION 10
/* FDT_ERR_BADVERSION: Given device tree has a version which
* can't be handled by the requested operation. For
* read-write functions, this may mean that fdt_open_into() is
* required to convert the tree to the expected version. */
#define FDT_ERR_BADSTRUCTURE 11
/* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
* structure block or other serious error (e.g. misnested
* nodes, or subnodes preceding properties). */
#define FDT_ERR_BADLAYOUT 12
/* FDT_ERR_BADLAYOUT: For read-write functions, the given
* device tree has it's sub-blocks in an order that the
* function can't handle (memory reserve map, then structure,
* then strings). Use fdt_open_into() to reorganize the tree
* into a form suitable for the read-write operations. */
/* "Can't happen" error indicating a bug in libfdt */
#define FDT_ERR_INTERNAL 13
/* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
* Should never be returned, if it is, it indicates a bug in
* libfdt itself. */
/* Errors in device tree content */
#define FDT_ERR_BADNCELLS 14
/* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
* or similar property with a bad format or value */
#define FDT_ERR_BADVALUE 15
/* FDT_ERR_BADVALUE: Device tree has a property with an unexpected
* value. For example: a property expected to contain a string list
* is not NUL-terminated within the length of its value. */
#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) */
/**********************************************************************/
#ifndef SWIG
/* This function is not useful in Python */
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
)
{
return
(
void
*
)(
uintptr_t
)
fdt_offset_ptr
(
fdt
,
offset
,
checklen
);
}
uint32_t
fdt_next_tag
(
const
void
*
fdt
,
int
offset
,
int
*
nextoffset
);
/**********************************************************************/
/* Traversal functions */
/**********************************************************************/
int
fdt_next_node
(
const
void
*
fdt
,
int
offset
,
int
*
depth
);
/**
* fdt_first_subnode() - get offset of first direct subnode
*
* @fdt: FDT blob
* @offset: Offset of node to check
* @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
*/
int
fdt_first_subnode
(
const
void
*
fdt
,
int
offset
);
/**
* fdt_next_subnode() - get offset of next direct subnode
*
* After first calling fdt_first_subnode(), call this function repeatedly to
* get direct subnodes of a parent node.
*
* @fdt: FDT blob
* @offset: Offset of previous subnode
* @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
* subnodes
*/
int
fdt_next_subnode
(
const
void
*
fdt
,
int
offset
);
/**
* fdt_for_each_subnode - iterate over all subnodes of a parent
*
* @node: child node (int, lvalue)
* @fdt: FDT blob (const void *)
* @parent: parent node (int)
*
* This is actually a wrapper around a for loop and would be used like so:
*
* fdt_for_each_subnode(node, fdt, parent) {
* Use node
* ...
* }
*
* if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) {
* Error handling
* }
*
* Note that this is implemented as a macro and @node is used as
* iterator in the loop. The parent variable be constant or even a
* literal.
*
*/
#define fdt_for_each_subnode(node, fdt, parent) \
for (node = fdt_first_subnode(fdt, parent); \
node >= 0; \
node = fdt_next_subnode(fdt, node))
/**********************************************************************/
/* General functions */
/**********************************************************************/
#define fdt_get_header(fdt, field) \
(fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
#define fdt_magic(fdt) (fdt_get_header(fdt, magic))
#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_strings(fdt) (fdt_get_header(fdt, off_dt_strings))
#define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap))
#define fdt_version(fdt) (fdt_get_header(fdt, version))
#define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version))
#define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys))
#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_set_hdr_(name) \
static inline void fdt_set_##name(void *fdt, uint32_t val) \
{ \
struct fdt_header *fdth = (struct fdt_header *)fdt; \
fdth->name = cpu_to_fdt32(val); \
}
fdt_set_hdr_
(
magic
);
fdt_set_hdr_
(
totalsize
);
fdt_set_hdr_
(
off_dt_struct
);
fdt_set_hdr_
(
off_dt_strings
);
fdt_set_hdr_
(
off_mem_rsvmap
);
fdt_set_hdr_
(
version
);
fdt_set_hdr_
(
last_comp_version
);
fdt_set_hdr_
(
boot_cpuid_phys
);
fdt_set_hdr_
(
size_dt_strings
);
fdt_set_hdr_
(
size_dt_struct
);
#undef fdt_set_hdr_
/**
* fdt_check_header - sanity check a device tree or possible device tree
* @fdt: pointer to data which might be a flattened device tree
*
* fdt_check_header() checks that the given buffer contains what
* appears to be a flattened device tree with sane information in its
* header.
*
* returns:
* 0, if the buffer appears to contain a valid device tree
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings, as above
*/
int
fdt_check_header
(
const
void
*
fdt
);
/**
* fdt_move - move a device tree around in memory
* @fdt: pointer to the device tree to move
* @buf: pointer to memory where the device is to be moved
* @bufsize: size of the memory space at buf
*
* fdt_move() relocates, if possible, the device tree blob located at
* fdt to the buffer at buf of size bufsize. The buffer may overlap
* with the existing device tree blob at fdt. Therefore,
* fdt_move(fdt, fdt, fdt_totalsize(fdt))
* should always succeed.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings
*/
int
fdt_move
(
const
void
*
fdt
,
void
*
buf
,
int
bufsize
);
/**********************************************************************/
/* Read-only functions */
/**********************************************************************/
/**
* fdt_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)
*
* fdt_string() retrieves a pointer to a single string from the
* strings block of the device tree blob at fdt.
*
* returns:
* a pointer to the string, on success
* NULL, if stroffset is out of bounds
*/
const
char
*
fdt_string
(
const
void
*
fdt
,
int
stroffset
);
/**
* fdt_get_max_phandle - retrieves the highest phandle in a tree
* @fdt: pointer to the device tree blob
*
* fdt_get_max_phandle retrieves the highest phandle in the given
* device tree. This will ignore badly formatted phandles, or phandles
* with a value of 0 or -1.
*
* returns:
* the highest phandle on success
* 0, if no phandle was found in the device tree
* -1, if an error occurred
*/
uint32_t
fdt_get_max_phandle
(
const
void
*
fdt
);
/**
* fdt_num_mem_rsv - retrieve the number of memory reserve map entries
* @fdt: pointer to the device tree blob
*
* Returns the number of entries in the device tree blob's memory
* reservation map. This does not include the terminating 0,0 entry
* or any other (0,0) entries reserved for expansion.
*
* returns:
* the number of entries
*/
int
fdt_num_mem_rsv
(
const
void
*
fdt
);
/**
* fdt_get_mem_rsv - retrieve one memory reserve map entry
* @fdt: pointer to the device tree blob
* @address, @size: pointers to 64-bit variables
*
* On success, *address and *size will contain the address and size of
* the n-th reserve map entry from the device tree blob, in
* native-endian format.
*
* returns:
* 0, on success
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings
*/
int
fdt_get_mem_rsv
(
const
void
*
fdt
,
int
n
,
uint64_t
*
address
,
uint64_t
*
size
);
/**
* fdt_subnode_offset_namelen - find a subnode based on substring
* @fdt: pointer to the device tree blob
* @parentoffset: structure block offset of a node
* @name: name of the subnode to locate
* @namelen: number of characters of name to consider
*
* Identical to fdt_subnode_offset(), but only examine the first
* namelen characters of name for matching the subnode name. This is
* useful for finding subnodes based on a portion of a larger string,
* such as a full path.
*/
#ifndef SWIG
/* Not available in Python */
int
fdt_subnode_offset_namelen
(
const
void
*
fdt
,
int
parentoffset
,
const
char
*
name
,
int
namelen
);
#endif
/**
* fdt_subnode_offset - find a subnode of a given node
* @fdt: pointer to the device tree blob
* @parentoffset: structure block offset of a node
* @name: name of the subnode to locate
*
* fdt_subnode_offset() finds a subnode of the node at structure block
* offset parentoffset with the given name. name may include a unit
* address, in which case fdt_subnode_offset() will find the subnode
* with that unit address, or the unit address may be omitted, in
* which case fdt_subnode_offset() will find an arbitrary subnode
* whose name excluding unit address matches the given name.
*
* returns:
* structure block offset of the requested subnode (>=0), on success
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings.
*/
int
fdt_subnode_offset
(
const
void
*
fdt
,
int
parentoffset
,
const
char
*
name
);
/**
* fdt_path_offset_namelen - find a tree node by its full path
* @fdt: pointer to the device tree blob
* @path: full path of the node to locate
* @namelen: number of characters of path to consider
*
* Identical to fdt_path_offset(), but only consider the first namelen
* 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
);
#endif
/**
* fdt_path_offset - find a tree node by its full path
* @fdt: pointer to the device tree blob
* @path: full path of the node to locate
*
* fdt_path_offset() finds a node of a given path in the device tree.
* Each path component may omit the unit address portion, but the
* results of this are undefined if any such path component is
* ambiguous (that is if there are multiple nodes at the relevant
* level matching the given component, differentiated only by unit
* address).
*
* returns:
* structure block offset of the node with the requested path (>=0), on
* success
* -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
* -FDT_ERR_NOTFOUND, if the requested node does not exist
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings.
*/
int
fdt_path_offset
(
const
void
*
fdt
,
const
char
*
path
);
/**
* fdt_get_name - retrieve the name of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: structure block offset of the starting node
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* fdt_get_name() retrieves the name (including unit address) of the
* device tree node at structure block offset nodeoffset. If lenp is
* non-NULL, the length of this name is also returned, in the integer
* pointed to by lenp.
*
* returns:
* pointer to the node's name, on success
* If lenp is non-NULL, *lenp contains the length of that name
* (>=0)
* NULL, on error
* if lenp is non-NULL *lenp contains an error code (<0):
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings
*/
const
char
*
fdt_get_name
(
const
void
*
fdt
,
int
nodeoffset
,
int
*
lenp
);
/**
* fdt_first_property_offset - find the offset of a node's first property
* @fdt: pointer to the device tree blob
* @nodeoffset: structure block offset of a node
*
* fdt_first_property_offset() finds the first property of the node at
* the given structure block offset.
*
* returns:
* structure block offset of the property (>=0), on success
* -FDT_ERR_NOTFOUND, if the requested node has no properties
* -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings.
*/
int
fdt_first_property_offset
(
const
void
*
fdt
,
int
nodeoffset
);
/**
* fdt_next_property_offset - step through a node's properties
* @fdt: pointer to the device tree blob
* @offset: structure block offset of a property
*
* fdt_next_property_offset() finds the property immediately after the
* one at the given structure block offset. This will be a property
* of the same node as the given property.
*
* returns:
* structure block offset of the next property (>=0), on success
* -FDT_ERR_NOTFOUND, if the given property is the last in its node
* -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings.
*/
int
fdt_next_property_offset
(
const
void
*
fdt
,
int
offset
);
/**
* fdt_for_each_property_offset - iterate over all properties of a node
*
* @property_offset: property offset (int, lvalue)
* @fdt: FDT blob (const void *)
* @node: node offset (int)
*
* This is actually a wrapper around a for loop and would be used like so:
*
* fdt_for_each_property_offset(property, fdt, node) {
* Use property
* ...
* }
*
* if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) {
* Error handling
* }
*
* Note that this is implemented as a macro and property is used as
* iterator in the loop. The node variable can be constant or even a
* literal.
*/
#define fdt_for_each_property_offset(property, fdt, node) \
for (property = fdt_first_property_offset(fdt, node); \
property >= 0; \
property = fdt_next_property_offset(fdt, property))
/**
* fdt_get_property_by_offset - retrieve the property at a given offset
* @fdt: pointer to the device tree blob
* @offset: offset of the property to retrieve
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* fdt_get_property_by_offset() retrieves a pointer to the
* fdt_property structure within the device tree blob at the given
* offset. If lenp is non-NULL, the length of the property value is
* 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:
* pointer to the structure representing the property
* if lenp is non-NULL, *lenp contains the length of the property
* value (>=0)
* NULL, on error
* if lenp is non-NULL, *lenp contains an error code (<0):
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
const
struct
fdt_property
*
fdt_get_property_by_offset
(
const
void
*
fdt
,
int
offset
,
int
*
lenp
);
/**
* fdt_get_property_namelen - find a property based on substring
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to find
* @name: name of the property to find
* @namelen: number of characters of name to consider
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* Identical to fdt_get_property(), but only examine the first namelen
* 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
,
int
nodeoffset
,
const
char
*
name
,
int
namelen
,
int
*
lenp
);
#endif
/**
* fdt_get_property - find a given property in a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to find
* @name: name of the property to find
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* fdt_get_property() retrieves a pointer to the fdt_property
* structure within the device tree blob corresponding to the property
* named 'name' of the node at offset nodeoffset. If lenp is
* non-NULL, the length of the property value is also returned, in the
* integer pointed to by lenp.
*
* returns:
* pointer to the structure representing the property
* if lenp is non-NULL, *lenp contains the length of the property
* value (>=0)
* NULL, on error
* if lenp is non-NULL, *lenp contains an error code (<0):
* -FDT_ERR_NOTFOUND, node does not have named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
const
struct
fdt_property
*
fdt_get_property
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
*
lenp
);
static
inline
struct
fdt_property
*
fdt_get_property_w
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
*
lenp
)
{
return
(
struct
fdt_property
*
)(
uintptr_t
)
fdt_get_property
(
fdt
,
nodeoffset
,
name
,
lenp
);
}
/**
* fdt_getprop_by_offset - retrieve the value of a property at a given offset
* @fdt: pointer to the device tree blob
* @ffset: offset of the property to read
* @namep: pointer to a string variable (will be overwritten) or NULL
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* fdt_getprop_by_offset() retrieves a pointer to the value of the
* property at structure block offset 'offset' (this will be a pointer
* to within the device blob itself, not a copy of the value). If
* lenp is non-NULL, the length of the property value is also
* returned, in the integer pointed to by lenp. If namep is non-NULL,
* the property's namne will also be returned in the char * pointed to
* by namep (this will be a pointer to within the device tree's string
* block, not a new copy of the name).
*
* returns:
* pointer to the property's value
* if lenp is non-NULL, *lenp contains the length of the property
* value (>=0)
* if namep is non-NULL *namep contiains a pointer to the property
* name.
* NULL, on error
* if lenp is non-NULL, *lenp contains an error code (<0):
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -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
char
**
namep
,
int
*
lenp
);
#endif
/**
* fdt_getprop_namelen - get property value based on substring
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to find
* @name: name of the property to find
* @namelen: number of characters of name to consider
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* Identical to fdt_getprop(), but only examine the first namelen
* 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
char
*
name
,
int
namelen
,
int
*
lenp
);
static
inline
void
*
fdt_getprop_namelen_w
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
namelen
,
int
*
lenp
)
{
return
(
void
*
)(
uintptr_t
)
fdt_getprop_namelen
(
fdt
,
nodeoffset
,
name
,
namelen
,
lenp
);
}
#endif
/**
* fdt_getprop - retrieve the value of a given property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to find
* @name: name of the property to find
* @lenp: pointer to an integer variable (will be overwritten) or NULL
*
* fdt_getprop() retrieves a pointer to the value of the property
* named 'name' of the node at offset nodeoffset (this will be a
* pointer to within the device blob itself, not a copy of the value).
* If lenp is non-NULL, the length of the property value is also
* returned, in the integer pointed to by lenp.
*
* returns:
* pointer to the property's value
* if lenp is non-NULL, *lenp contains the length of the property
* value (>=0)
* NULL, on error
* if lenp is non-NULL, *lenp contains an error code (<0):
* -FDT_ERR_NOTFOUND, node does not have named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE
* tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
const
void
*
fdt_getprop
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
*
lenp
);
static
inline
void
*
fdt_getprop_w
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
*
lenp
)
{
return
(
void
*
)(
uintptr_t
)
fdt_getprop
(
fdt
,
nodeoffset
,
name
,
lenp
);
}
/**
* fdt_get_phandle - retrieve the phandle of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: structure block offset of the node
*
* fdt_get_phandle() retrieves the phandle of the device tree node at
* structure block offset nodeoffset.
*
* returns:
* the phandle of the node at nodeoffset, on success (!= 0, != -1)
* 0, if the node has no phandle, or another error occurs
*/
uint32_t
fdt_get_phandle
(
const
void
*
fdt
,
int
nodeoffset
);
/**
* fdt_get_alias_namelen - get alias based on substring
* @fdt: pointer to the device tree blob
* @name: name of the alias th look up
* @namelen: number of characters of name to consider
*
* Identical to fdt_get_alias(), but only examine the first namelen
* 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
*
name
,
int
namelen
);
#endif
/**
* fdt_get_alias - retrieve the path referenced by a given alias
* @fdt: pointer to the device tree blob
* @name: name of the alias th look up
*
* fdt_get_alias() retrieves the value of a given alias. That is, the
* value of the property named 'name' in the node /aliases.
*
* returns:
* a pointer to the expansion of the alias named 'name', if it exists
* NULL, if the given alias or the /aliases node does not exist
*/
const
char
*
fdt_get_alias
(
const
void
*
fdt
,
const
char
*
name
);
/**
* fdt_get_path - determine the full path of a node
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose path to find
* @buf: character buffer to contain the returned path (will be overwritten)
* @buflen: size of the character buffer at buf
*
* fdt_get_path() computes the full path of the node at offset
* nodeoffset, and records that path in the buffer at buf.
*
* NOTE: This function is expensive, as it must scan the device tree
* structure from the start to nodeoffset.
*
* returns:
* 0, on success
* buf contains the absolute path of the node at
* nodeoffset, as a NUL-terminated string.
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
* characters and will not fit in the given buffer.
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_get_path
(
const
void
*
fdt
,
int
nodeoffset
,
char
*
buf
,
int
buflen
);
/**
* fdt_supernode_atdepth_offset - find a specific ancestor of a node
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose parent to find
* @supernodedepth: depth of the ancestor to find
* @nodedepth: pointer to an integer variable (will be overwritten) or NULL
*
* fdt_supernode_atdepth_offset() finds an ancestor of the given node
* at a specific depth from the root (where the root itself has depth
* 0, its immediate subnodes depth 1 and so forth). So
* fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
* will always return 0, the offset of the root node. If the node at
* nodeoffset has depth D, then:
* fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
* will return nodeoffset itself.
*
* NOTE: This function is expensive, as it must scan the device tree
* structure from the start to nodeoffset.
*
* returns:
* structure block offset of the node at node offset's ancestor
* of depth supernodedepth (>=0), on success
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of
* nodeoffset
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_supernode_atdepth_offset
(
const
void
*
fdt
,
int
nodeoffset
,
int
supernodedepth
,
int
*
nodedepth
);
/**
* fdt_node_depth - find the depth of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose parent to find
*
* fdt_node_depth() finds the depth of a given node. The root node
* has depth 0, its immediate subnodes depth 1 and so forth.
*
* NOTE: This function is expensive, as it must scan the device tree
* structure from the start to nodeoffset.
*
* returns:
* depth of the node at nodeoffset (>=0), on success
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_node_depth
(
const
void
*
fdt
,
int
nodeoffset
);
/**
* fdt_parent_offset - find the parent of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose parent to find
*
* fdt_parent_offset() locates the parent node of a given node (that
* is, it finds the offset of the node which contains the node at
* nodeoffset as a subnode).
*
* NOTE: This function is expensive, as it must scan the device tree
* structure from the start to nodeoffset, *twice*.
*
* returns:
* structure block offset of the parent of the node at nodeoffset
* (>=0), on success
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_parent_offset
(
const
void
*
fdt
,
int
nodeoffset
);
/**
* fdt_node_offset_by_prop_value - find nodes with a given property value
* @fdt: pointer to the device tree blob
* @startoffset: only find nodes after this offset
* @propname: property name to check
* @propval: property value to search for
* @proplen: length of the value in propval
*
* fdt_node_offset_by_prop_value() returns the offset of the first
* node after startoffset, which has a property named propname whose
* value is of length proplen and has value equal to propval; or if
* startoffset is -1, the very first such node in the tree.
*
* To iterate through all nodes matching the criterion, the following
* idiom can be used:
* offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
* propval, proplen);
* while (offset != -FDT_ERR_NOTFOUND) {
* // other code here
* offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
* propval, proplen);
* }
*
* Note the -1 in the first call to the function, if 0 is used here
* instead, the function will never locate the root node, even if it
* matches the criterion.
*
* returns:
* structure block offset of the located node (>= 0, >startoffset),
* on success
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
* tree after startoffset
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_node_offset_by_prop_value
(
const
void
*
fdt
,
int
startoffset
,
const
char
*
propname
,
const
void
*
propval
,
int
proplen
);
/**
* fdt_node_offset_by_phandle - find the node with a given phandle
* @fdt: pointer to the device tree blob
* @phandle: phandle value
*
* fdt_node_offset_by_phandle() returns the offset of the node
* which has the given phandle value. If there is more than one node
* in the tree with the given phandle (an invalid tree), results are
* undefined.
*
* returns:
* structure block offset of the located node (>= 0), on success
* -FDT_ERR_NOTFOUND, no node with that phandle exists
* -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_node_offset_by_phandle
(
const
void
*
fdt
,
uint32_t
phandle
);
/**
* fdt_node_check_compatible: check a node's compatible property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of a tree node
* @compatible: string to match against
*
*
* fdt_node_check_compatible() returns 0 if the given node contains a
* 'compatible' property with the given string as one of its elements,
* it returns non-zero otherwise, or on error.
*
* returns:
* 0, if the node has a 'compatible' property listing the given string
* 1, if the node has a 'compatible' property, but it does not list
* the given string
* -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
* -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_node_check_compatible
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
compatible
);
/**
* fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
* @fdt: pointer to the device tree blob
* @startoffset: only find nodes after this offset
* @compatible: 'compatible' string to match against
*
* fdt_node_offset_by_compatible() returns the offset of the first
* node after startoffset, which has a 'compatible' property which
* lists the given compatible string; or if startoffset is -1, the
* very first such node in the tree.
*
* To iterate through all nodes matching the criterion, the following
* idiom can be used:
* offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
* while (offset != -FDT_ERR_NOTFOUND) {
* // other code here
* offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
* }
*
* Note the -1 in the first call to the function, if 0 is used here
* instead, the function will never locate the root node, even if it
* matches the criterion.
*
* returns:
* structure block offset of the located node (>= 0, >startoffset),
* on success
* -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
* tree after startoffset
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE, standard meanings
*/
int
fdt_node_offset_by_compatible
(
const
void
*
fdt
,
int
startoffset
,
const
char
*
compatible
);
/**
* fdt_stringlist_contains - check a string list property for a string
* @strlist: Property containing a list of strings to check
* @listlen: Length of property
* @str: String to search for
*
* This is a utility function provided for convenience. The list contains
* one or more strings, each terminated by \0, as is found in a device tree
* "compatible" property.
*
* @return: 1 if the string is found in the list, 0 not found, or invalid list
*/
int
fdt_stringlist_contains
(
const
char
*
strlist
,
int
listlen
,
const
char
*
str
);
/**
* fdt_stringlist_count - count the number of strings in a string list
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of a tree node
* @property: name of the property containing the string list
* @return:
* the number of strings in the given property
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
* -FDT_ERR_NOTFOUND if the property does not exist
*/
int
fdt_stringlist_count
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
property
);
/**
* fdt_stringlist_search - find a string in a string list and return its index
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of a tree node
* @property: name of the property containing the string list
* @string: string to look up in the string list
*
* Note that it is possible for this function to succeed on property values
* that are not NUL-terminated. That's because the function will stop after
* finding the first occurrence of @string. This can for example happen with
* small-valued cell properties, such as #address-cells, when searching for
* the empty string.
*
* @return:
* the index of the string in the list of strings
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
* -FDT_ERR_NOTFOUND if the property does not exist or does not contain
* the given string
*/
int
fdt_stringlist_search
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
property
,
const
char
*
string
);
/**
* fdt_stringlist_get() - obtain the string at a given index in a string list
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of a tree node
* @property: name of the property containing the string list
* @index: index of the string to return
* @lenp: return location for the string length or an error code on failure
*
* Note that this will successfully extract strings from properties with
* non-NUL-terminated values. For example on small-valued cell properties
* this function will return the empty string.
*
* If non-NULL, the length of the string (on success) or a negative error-code
* (on failure) will be stored in the integer pointer to by lenp.
*
* @return:
* A pointer to the string at the given index in the string list or NULL on
* failure. On success the length of the string will be stored in the memory
* location pointed to by the lenp parameter, if non-NULL. On failure one of
* the following negative error codes will be returned in the lenp parameter
* (if non-NULL):
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
* -FDT_ERR_NOTFOUND if the property does not exist
*/
const
char
*
fdt_stringlist_get
(
const
void
*
fdt
,
int
nodeoffset
,
const
char
*
property
,
int
index
,
int
*
lenp
);
/**********************************************************************/
/* Read-only functions (addressing related) */
/**********************************************************************/
/**
* FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells
*
* This is the maximum value for #address-cells, #size-cells and
* similar properties that will be processed by libfdt. IEE1275
* requires that OF implementations handle values up to 4.
* Implementations may support larger values, but in practice higher
* values aren't used.
*/
#define FDT_MAX_NCELLS 4
/**
* fdt_address_cells - retrieve address size for a bus represented in the tree
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node to find the address size for
*
* When the node has a valid #address-cells property, returns its value.
*
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
* 2, if the node has no #address-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #address-cells property
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int
fdt_address_cells
(
const
void
*
fdt
,
int
nodeoffset
);
/**
* fdt_size_cells - retrieve address range size for a bus represented in the
* tree
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node to find the address range size for
*
* When the node has a valid #size-cells property, returns its value.
*
* returns:
* 0 <= n < FDT_MAX_NCELLS, on success
* 2, if the node has no #address-cells property
* -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
* #size-cells property
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int
fdt_size_cells
(
const
void
*
fdt
,
int
nodeoffset
);
/**********************************************************************/
/* Write-in-place functions */
/**********************************************************************/
/**
* fdt_setprop_inplace_namelen_partial - change a property's value,
* but not its size
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @namelen: number of characters of name to consider
* @idx: index of the property to change in the array
* @val: pointer to data to replace the property value with
* @len: length of the property value
*
* Identical to fdt_setprop_inplace(), but modifies the given property
* starting from the given index, and using only the first characters
* 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.
*/
#ifndef SWIG
/* Not available in Python */
int
fdt_setprop_inplace_namelen_partial
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
int
namelen
,
uint32_t
idx
,
const
void
*
val
,
int
len
);
#endif
/**
* fdt_setprop_inplace - change a property's value, but not its size
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @val: pointer to data to replace the property value with
* @len: length of the property value
*
* fdt_setprop_inplace() replaces the value of a given property with
* the data in val, of length len. This function cannot change the
* size of a property, and so will only work if len is equal to the
* current length of the property.
*
* This function will alter only the bytes in the blob which contain
* the given property value, and will not alter or move any other part
* of the tree.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, if len is not equal to the property's current length
* -FDT_ERR_NOTFOUND, node does not have the named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
#ifndef SWIG
/* Not available in Python */
int
fdt_setprop_inplace
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
const
void
*
val
,
int
len
);
#endif
/**
* fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @val: 32-bit integer value to replace the property with
*
* fdt_setprop_inplace_u32() replaces the value of a given property
* with the 32-bit integer value in val, converting val to big-endian
* if necessary. This function cannot change the size of a property,
* and so will only work if the property already exists and has length
* 4.
*
* This function will alter only the bytes in the blob which contain
* the given property value, and will not alter or move any other part
* of the tree.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, if the property's length is not equal to 4
* -FDT_ERR_NOTFOUND, node does not have the named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
static
inline
int
fdt_setprop_inplace_u32
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint32_t
val
)
{
fdt32_t
tmp
=
cpu_to_fdt32
(
val
);
return
fdt_setprop_inplace
(
fdt
,
nodeoffset
,
name
,
&
tmp
,
sizeof
(
tmp
));
}
/**
* fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @val: 64-bit integer value to replace the property with
*
* fdt_setprop_inplace_u64() replaces the value of a given property
* with the 64-bit integer value in val, converting val to big-endian
* if necessary. This function cannot change the size of a property,
* and so will only work if the property already exists and has length
* 8.
*
* This function will alter only the bytes in the blob which contain
* the given property value, and will not alter or move any other part
* of the tree.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, if the property's length is not equal to 8
* -FDT_ERR_NOTFOUND, node does not have the named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
static
inline
int
fdt_setprop_inplace_u64
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint64_t
val
)
{
fdt64_t
tmp
=
cpu_to_fdt64
(
val
);
return
fdt_setprop_inplace
(
fdt
,
nodeoffset
,
name
,
&
tmp
,
sizeof
(
tmp
));
}
/**
* fdt_setprop_inplace_cell - change the value of a single-cell property
*
* This is an alternative name for fdt_setprop_inplace_u32()
*/
static
inline
int
fdt_setprop_inplace_cell
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint32_t
val
)
{
return
fdt_setprop_inplace_u32
(
fdt
,
nodeoffset
,
name
,
val
);
}
/**
* fdt_nop_property - replace a property with nop tags
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to nop
* @name: name of the property to nop
*
* fdt_nop_property() will replace a given property's representation
* in the blob with FDT_NOP tags, effectively removing it from the
* tree.
*
* This function will alter only the bytes in the blob which contain
* the property, and will not alter or move any other part of the
* tree.
*
* returns:
* 0, on success
* -FDT_ERR_NOTFOUND, node does not have the named property
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int
fdt_nop_property
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
);
/**
* fdt_nop_node - replace a node (subtree) with nop tags
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node to nop
*
* fdt_nop_node() will replace a given node's representation in the
* blob, including all its subnodes, if any, with FDT_NOP tags,
* effectively removing it from the tree.
*
* This function will alter only the bytes in the blob which contain
* the node and its properties and subnodes, and will not alter or
* move any other part of the tree.
*
* returns:
* 0, on success
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int
fdt_nop_node
(
void
*
fdt
,
int
nodeoffset
);
/**********************************************************************/
/* Sequential write functions */
/**********************************************************************/
int
fdt_create
(
void
*
buf
,
int
bufsize
);
int
fdt_resize
(
void
*
fdt
,
void
*
buf
,
int
bufsize
);
int
fdt_add_reservemap_entry
(
void
*
fdt
,
uint64_t
addr
,
uint64_t
size
);
int
fdt_finish_reservemap
(
void
*
fdt
);
int
fdt_begin_node
(
void
*
fdt
,
const
char
*
name
);
int
fdt_property
(
void
*
fdt
,
const
char
*
name
,
const
void
*
val
,
int
len
);
static
inline
int
fdt_property_u32
(
void
*
fdt
,
const
char
*
name
,
uint32_t
val
)
{
fdt32_t
tmp
=
cpu_to_fdt32
(
val
);
return
fdt_property
(
fdt
,
name
,
&
tmp
,
sizeof
(
tmp
));
}
static
inline
int
fdt_property_u64
(
void
*
fdt
,
const
char
*
name
,
uint64_t
val
)
{
fdt64_t
tmp
=
cpu_to_fdt64
(
val
);
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
)
{
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) \
fdt_property(fdt, name, str, strlen(str)+1)
int
fdt_end_node
(
void
*
fdt
);
int
fdt_finish
(
void
*
fdt
);
/**********************************************************************/
/* Read-write functions */
/**********************************************************************/
int
fdt_create_empty_tree
(
void
*
buf
,
int
bufsize
);
int
fdt_open_into
(
const
void
*
fdt
,
void
*
buf
,
int
bufsize
);
int
fdt_pack
(
void
*
fdt
);
/**
* fdt_add_mem_rsv - add one memory reserve map entry
* @fdt: pointer to the device tree blob
* @address, @size: 64-bit values (native endian)
*
* Adds a reserve map entry to the given blob reserving a region at
* address address of length size.
*
* This function will insert data into the reserve map and will
* therefore change the indexes of some entries in the table.
*
* returns:
* 0, on success
* -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
* contain the new reservation entry
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int
fdt_add_mem_rsv
(
void
*
fdt
,
uint64_t
address
,
uint64_t
size
);
/**
* fdt_del_mem_rsv - remove a memory reserve map entry
* @fdt: pointer to the device tree blob
* @n: entry to remove
*
* fdt_del_mem_rsv() removes the n-th memory reserve map entry from
* the blob.
*
* This function will delete data from the reservation table and will
* therefore change the indexes of some entries in the table.
*
* returns:
* 0, on success
* -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
* are less than n+1 reserve map entries)
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_BADLAYOUT,
* -FDT_ERR_TRUNCATED, standard meanings
*/
int
fdt_del_mem_rsv
(
void
*
fdt
,
int
n
);
/**
* fdt_set_name - change the name of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: structure block offset of a node
* @name: name to give the node
*
* fdt_set_name() replaces the name (including unit address, if any)
* of the given node with the given string. NOTE: this function can't
* efficiently check if the new name is unique amongst the given
* node's siblings; results are undefined if this function is invoked
* with a name equal to one of the given node's siblings.
*
* 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 name
* -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE, standard meanings
*/
int
fdt_set_name
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
);
/**
* fdt_setprop - create or change 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
* @val: pointer to data to set the property value to
* @len: length of the property value
*
* fdt_setprop() sets the value of the named property in the given
* node to the given value and length, creating the 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
*/
int
fdt_setprop
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
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: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @val: 32-bit integer value for the property (native endian)
*
* fdt_setprop_u32() sets the value of the named property in the given
* node to the given 32-bit integer value (converting to big-endian if
* necessary), or creates a new property with that value 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
*/
static
inline
int
fdt_setprop_u32
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint32_t
val
)
{
fdt32_t
tmp
=
cpu_to_fdt32
(
val
);
return
fdt_setprop
(
fdt
,
nodeoffset
,
name
,
&
tmp
,
sizeof
(
tmp
));
}
/**
* fdt_setprop_u64 - set a property to a 64-bit integer
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @val: 64-bit integer value for the property (native endian)
*
* fdt_setprop_u64() sets the value of the named property in the given
* node to the given 64-bit integer value (converting to big-endian if
* necessary), or creates a new property with that value 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
*/
static
inline
int
fdt_setprop_u64
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint64_t
val
)
{
fdt64_t
tmp
=
cpu_to_fdt64
(
val
);
return
fdt_setprop
(
fdt
,
nodeoffset
,
name
,
&
tmp
,
sizeof
(
tmp
));
}
/**
* fdt_setprop_cell - set a property to a single cell value
*
* This is an alternative name for fdt_setprop_u32()
*/
static
inline
int
fdt_setprop_cell
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint32_t
val
)
{
return
fdt_setprop_u32
(
fdt
,
nodeoffset
,
name
,
val
);
}
/**
* fdt_setprop_string - set a property to a string value
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to change
* @str: string value for the property
*
* fdt_setprop_string() sets the value of the named property in the
* given node to the given string value (using the length of the
* string to determine the new length of the property), or creates a
* new property with that value 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_string(fdt, nodeoffset, name, str) \
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: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to change
* @name: name of the property to append to
* @val: pointer to data to append to the property value
* @len: length of the data to append to the property value
*
* fdt_appendprop() appends the value to the named property in the
* given node, creating the property if it does not already exist.
*
* This function may insert data into 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_appendprop
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
const
void
*
val
,
int
len
);
/**
* fdt_appendprop_u32 - append a 32-bit integer value to 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
* @val: 32-bit integer value to append to the property (native endian)
*
* fdt_appendprop_u32() appends the given 32-bit integer value
* (converting to big-endian if necessary) to the value of the named
* property in the given node, or creates a new property with that
* value if it does not already exist.
*
* This function may insert data into 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
*/
static
inline
int
fdt_appendprop_u32
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint32_t
val
)
{
fdt32_t
tmp
=
cpu_to_fdt32
(
val
);
return
fdt_appendprop
(
fdt
,
nodeoffset
,
name
,
&
tmp
,
sizeof
(
tmp
));
}
/**
* fdt_appendprop_u64 - append a 64-bit integer value to 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
* @val: 64-bit integer value to append to the property (native endian)
*
* fdt_appendprop_u64() appends the given 64-bit integer value
* (converting to big-endian if necessary) to the value of the named
* property in the given node, or creates a new property with that
* value if it does not already exist.
*
* This function may insert data into 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
*/
static
inline
int
fdt_appendprop_u64
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint64_t
val
)
{
fdt64_t
tmp
=
cpu_to_fdt64
(
val
);
return
fdt_appendprop
(
fdt
,
nodeoffset
,
name
,
&
tmp
,
sizeof
(
tmp
));
}
/**
* fdt_appendprop_cell - append a single cell value to a property
*
* This is an alternative name for fdt_appendprop_u32()
*/
static
inline
int
fdt_appendprop_cell
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
,
uint32_t
val
)
{
return
fdt_appendprop_u32
(
fdt
,
nodeoffset
,
name
,
val
);
}
/**
* fdt_appendprop_string - append a string to 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
* @str: string value to append to the property
*
* fdt_appendprop_string() appends the given string to the value of
* the named property in the given node, or creates a new property
* with that value if it does not already exist.
*
* This function may insert data into 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_appendprop_string(fdt, nodeoffset, name, str) \
fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
/**
* fdt_delprop - delete a property
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node whose property to nop
* @name: name of the property to nop
*
* fdt_del_property() will delete the given property.
*
* This function will delete data from the blob, and will therefore
* change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -FDT_ERR_NOTFOUND, node does not have the named property
* -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_TRUNCATED, standard meanings
*/
int
fdt_delprop
(
void
*
fdt
,
int
nodeoffset
,
const
char
*
name
);
/**
* fdt_add_subnode_namelen - creates a new node based on substring
* @fdt: pointer to the device tree blob
* @parentoffset: structure block offset of a node
* @name: name of the subnode to locate
* @namelen: number of characters of name to consider
*
* Identical to fdt_add_subnode(), but use only the first namelen
* characters of name as the name of the new node. This is useful for
* creating subnodes based on a portion of a larger string, such as a
* full path.
*/
#ifndef SWIG
/* Not available in Python */
int
fdt_add_subnode_namelen
(
void
*
fdt
,
int
parentoffset
,
const
char
*
name
,
int
namelen
);
#endif
/**
* fdt_add_subnode - creates a new node
* @fdt: pointer to the device tree blob
* @parentoffset: structure block offset of a node
* @name: name of the subnode to locate
*
* fdt_add_subnode() creates a new node as a subnode of the node at
* structure block offset parentoffset, with the given name (which
* should include the unit address, if any).
*
* This function will insert data into the blob, and will therefore
* change the offsets of some existing nodes.
* returns:
* structure block offset of the created nodeequested subnode (>=0), on
* success
* -FDT_ERR_NOTFOUND, if the requested subnode does not exist
* -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE
* tag
* -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
* the given name
* -FDT_ERR_NOSPACE, if there is insufficient free space in the
* blob to contain the new node
* -FDT_ERR_NOSPACE
* -FDT_ERR_BADLAYOUT
* -FDT_ERR_BADMAGIC,
* -FDT_ERR_BADVERSION,
* -FDT_ERR_BADSTATE,
* -FDT_ERR_BADSTRUCTURE,
* -FDT_ERR_TRUNCATED, standard meanings.
*/
int
fdt_add_subnode
(
void
*
fdt
,
int
parentoffset
,
const
char
*
name
);
/**
* fdt_del_node - delete a node (subtree)
* @fdt: pointer to the device tree blob
* @nodeoffset: offset of the node to nop
*
* fdt_del_node() will remove the given node, including all its
* subnodes if any, from the blob.
*
* This function will delete data from the blob, and will therefore
* change the offsets of some existing nodes.
*
* returns:
* 0, on success
* -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_TRUNCATED, standard meanings
*/
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 */
/**********************************************************************/
const
char
*
fdt_strerror
(
int
errval
);
#endif
/* LIBFDT_H */
u-boot-tree/scripts/dtc/libfdt/libfdt_env.h
0 → 100644
View file @
7496de94
#ifndef LIBFDT_ENV_H
#define LIBFDT_ENV_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
* Copyright 2012 Kim Phillips, Freescale Semiconductor.
*
* 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 <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef __CHECKER__
#define FDT_FORCE __attribute__((force))
#define FDT_BITWISE __attribute__((bitwise))
#else
#define FDT_FORCE
#define FDT_BITWISE
#endif
typedef
uint16_t
FDT_BITWISE
fdt16_t
;
typedef
uint32_t
FDT_BITWISE
fdt32_t
;
typedef
uint64_t
FDT_BITWISE
fdt64_t
;
#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_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
(EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
(EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
(EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
(EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
static
inline
uint16_t
fdt16_to_cpu
(
fdt16_t
x
)
{
return
(
FDT_FORCE
uint16_t
)
CPU_TO_FDT16
(
x
);
}
static
inline
fdt16_t
cpu_to_fdt16
(
uint16_t
x
)
{
return
(
FDT_FORCE
fdt16_t
)
CPU_TO_FDT16
(
x
);
}
static
inline
uint32_t
fdt32_to_cpu
(
fdt32_t
x
)
{
return
(
FDT_FORCE
uint32_t
)
CPU_TO_FDT32
(
x
);
}
static
inline
fdt32_t
cpu_to_fdt32
(
uint32_t
x
)
{
return
(
FDT_FORCE
fdt32_t
)
CPU_TO_FDT32
(
x
);
}
static
inline
uint64_t
fdt64_to_cpu
(
fdt64_t
x
)
{
return
(
FDT_FORCE
uint64_t
)
CPU_TO_FDT64
(
x
);
}
static
inline
fdt64_t
cpu_to_fdt64
(
uint64_t
x
)
{
return
(
FDT_FORCE
fdt64_t
)
CPU_TO_FDT64
(
x
);
}
#undef CPU_TO_FDT64
#undef CPU_TO_FDT32
#undef CPU_TO_FDT16
#undef EXTRACT_BYTE
#ifdef __APPLE__
#include <AvailabilityMacros.h>
/* strnlen() is not available on Mac OS < 10.7 */
# if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \
MAC_OS_X_VERSION_10_7)
#define strnlen fdt_strnlen
/*
* fdt_strnlen: returns the length of a string or max_count - which ever is
* smallest.
* Input 1 string: the string whose size is to be determined
* Input 2 max_count: the maximum value returned by this function
* Output: length of the string or max_count (the smallest of the two)
*/
static
inline
size_t
fdt_strnlen
(
const
char
*
string
,
size_t
max_count
)
{
const
char
*
p
=
memchr
(
string
,
0
,
max_count
);
return
p
?
p
-
string
:
max_count
;
}
#endif
/* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED <
MAC_OS_X_VERSION_10_7) */
#endif
/* __APPLE__ */
#endif
/* LIBFDT_ENV_H */
u-boot-tree/scripts/dtc/libfdt/libfdt_internal.h
0 → 100644
View file @
7496de94
#ifndef LIBFDT_INTERNAL_H
#define LIBFDT_INTERNAL_H
/*
* 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 <fdt.h>
#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
#define FDT_CHECK_HEADER(fdt) \
{ \
int err_; \
if ((err_ = fdt_check_header(fdt)) != 0) \
return err_; \
}
int
fdt_check_node_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
);
int
fdt_node_end_offset_
(
void
*
fdt
,
int
nodeoffset
);
static
inline
const
void
*
fdt_offset_ptr_
(
const
void
*
fdt
,
int
offset
)
{
return
(
const
char
*
)
fdt
+
fdt_off_dt_struct
(
fdt
)
+
offset
;
}
static
inline
void
*
fdt_offset_ptr_w_
(
void
*
fdt
,
int
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
)
{
const
struct
fdt_reserve_entry
*
rsv_table
=
(
const
struct
fdt_reserve_entry
*
)
((
const
char
*
)
fdt
+
fdt_off_mem_rsvmap
(
fdt
));
return
rsv_table
+
n
;
}
static
inline
struct
fdt_reserve_entry
*
fdt_mem_rsv_w_
(
void
*
fdt
,
int
n
)
{
return
(
void
*
)(
uintptr_t
)
fdt_mem_rsv_
(
fdt
,
n
);
}
#define FDT_SW_MAGIC (~FDT_MAGIC)
#endif
/* LIBFDT_INTERNAL_H */
u-boot-tree/scripts/dtc/livetree.c
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
/*
* Tree building functions
*/
void
add_label
(
struct
label
**
labels
,
char
*
label
)
{
struct
label
*
new
;
/* Make sure the label isn't already there */
for_each_label_withdel
(
*
labels
,
new
)
if
(
streq
(
new
->
label
,
label
))
{
new
->
deleted
=
0
;
return
;
}
new
=
xmalloc
(
sizeof
(
*
new
));
memset
(
new
,
0
,
sizeof
(
*
new
));
new
->
label
=
label
;
new
->
next
=
*
labels
;
*
labels
=
new
;
}
void
delete_labels
(
struct
label
**
labels
)
{
struct
label
*
label
;
for_each_label
(
*
labels
,
label
)
label
->
deleted
=
1
;
}
struct
property
*
build_property
(
char
*
name
,
struct
data
val
)
{
struct
property
*
new
=
xmalloc
(
sizeof
(
*
new
));
memset
(
new
,
0
,
sizeof
(
*
new
));
new
->
name
=
name
;
new
->
val
=
val
;
return
new
;
}
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
;
}
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
;
}
struct
node
*
build_node
(
struct
property
*
proplist
,
struct
node
*
children
)
{
struct
node
*
new
=
xmalloc
(
sizeof
(
*
new
));
struct
node
*
child
;
memset
(
new
,
0
,
sizeof
(
*
new
));
new
->
proplist
=
reverse_properties
(
proplist
);
new
->
children
=
children
;
for_each_child
(
new
,
child
)
{
child
->
parent
=
new
;
}
return
new
;
}
struct
node
*
build_node_delete
(
void
)
{
struct
node
*
new
=
xmalloc
(
sizeof
(
*
new
));
memset
(
new
,
0
,
sizeof
(
*
new
));
new
->
deleted
=
1
;
return
new
;
}
struct
node
*
name_node
(
struct
node
*
node
,
char
*
name
)
{
assert
(
node
->
name
==
NULL
);
node
->
name
=
name
;
return
node
;
}
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
;
old_node
->
deleted
=
0
;
/* Add new node labels to old node */
for_each_label_withdel
(
new_node
->
labels
,
l
)
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
;
if
(
new_prop
->
deleted
)
{
delete_property_by_name
(
old_node
,
new_prop
->
name
);
free
(
new_prop
);
continue
;
}
/* Look for a collision, set new value if there is */
for_each_property_withdel
(
old_node
,
old_prop
)
{
if
(
streq
(
old_prop
->
name
,
new_prop
->
name
))
{
/* Add new labels to old property */
for_each_label_withdel
(
new_prop
->
labels
,
l
)
add_label
(
&
old_prop
->
labels
,
l
->
label
);
old_prop
->
val
=
new_prop
->
val
;
old_prop
->
deleted
=
0
;
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
;
if
(
new_child
->
deleted
)
{
delete_node_by_name
(
old_node
,
new_child
->
name
);
free
(
new_child
);
continue
;
}
/* Search for a collision. Merge if there is */
for_each_child_withdel
(
old_node
,
old_child
)
{
if
(
streq
(
old_child
->
name
,
new_child
->
name
))
{
merge_nodes
(
old_child
,
new_child
);
new_child
=
NULL
;
break
;
}
}
/* if no collision occurred, add child to the old node. */
if
(
new_child
)
add_child
(
old_node
,
new_child
);
}
/* The new node contents are now merged into the old node. Free
* the new node. */
free
(
new_node
);
return
old_node
;
}
struct
node
*
add_orphan_node
(
struct
node
*
dt
,
struct
node
*
new_node
,
char
*
ref
)
{
static
unsigned
int
next_orphan_fragment
=
0
;
struct
node
*
node
;
struct
property
*
p
;
struct
data
d
=
empty_data
;
char
*
name
;
d
=
data_add_marker
(
d
,
REF_PHANDLE
,
ref
);
d
=
data_append_integer
(
d
,
0xffffffff
,
32
);
p
=
build_property
(
"target"
,
d
);
xasprintf
(
&
name
,
"fragment@%u"
,
next_orphan_fragment
++
);
name_node
(
new_node
,
"__overlay__"
);
node
=
build_node
(
p
,
new_node
);
name_node
(
node
,
name
);
add_child
(
dt
,
node
);
return
dt
;
}
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
;
}
void
delete_property_by_name
(
struct
node
*
node
,
char
*
name
)
{
struct
property
*
prop
=
node
->
proplist
;
while
(
prop
)
{
if
(
streq
(
prop
->
name
,
name
))
{
delete_property
(
prop
);
return
;
}
prop
=
prop
->
next
;
}
}
void
delete_property
(
struct
property
*
prop
)
{
prop
->
deleted
=
1
;
delete_labels
(
&
prop
->
labels
);
}
void
add_child
(
struct
node
*
parent
,
struct
node
*
child
)
{
struct
node
**
p
;
child
->
next_sibling
=
NULL
;
child
->
parent
=
parent
;
p
=
&
parent
->
children
;
while
(
*
p
)
p
=
&
((
*
p
)
->
next_sibling
);
*
p
=
child
;
}
void
delete_node_by_name
(
struct
node
*
parent
,
char
*
name
)
{
struct
node
*
node
=
parent
->
children
;
while
(
node
)
{
if
(
streq
(
node
->
name
,
name
))
{
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
);
}
void
append_to_property
(
struct
node
*
node
,
char
*
name
,
const
void
*
data
,
int
len
)
{
struct
data
d
;
struct
property
*
p
;
p
=
get_property
(
node
,
name
);
if
(
p
)
{
d
=
data_append_data
(
p
->
val
,
data
,
len
);
p
->
val
=
d
;
}
else
{
d
=
data_append_data
(
empty_data
,
data
,
len
);
p
=
build_property
(
name
,
d
);
add_property
(
node
,
p
);
}
}
struct
reserve_info
*
build_reserve_entry
(
uint64_t
address
,
uint64_t
size
)
{
struct
reserve_info
*
new
=
xmalloc
(
sizeof
(
*
new
));
memset
(
new
,
0
,
sizeof
(
*
new
));
new
->
address
=
address
;
new
->
size
=
size
;
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
;
}
struct
dt_info
*
build_dt_info
(
unsigned
int
dtsflags
,
struct
reserve_info
*
reservelist
,
struct
node
*
tree
,
uint32_t
boot_cpuid_phys
)
{
struct
dt_info
*
dti
;
dti
=
xmalloc
(
sizeof
(
*
dti
));
dti
->
dtsflags
=
dtsflags
;
dti
->
reservelist
=
reservelist
;
dti
->
dt
=
tree
;
dti
->
boot_cpuid_phys
=
boot_cpuid_phys
;
return
dti
;
}
/*
* 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
));
return
fdt32_to_cpu
(
*
((
fdt32_t
*
)
prop
->
val
.
val
));
}
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
));
}
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
;
}
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
;
if
(
!
path
||
!
(
*
path
))
{
if
(
tree
->
deleted
)
return
NULL
;
return
tree
;
}
while
(
path
[
0
]
==
'/'
)
path
++
;
p
=
strchr
(
path
,
'/'
);
for_each_child
(
tree
,
child
)
{
if
(
p
&&
(
strlen
(
child
->
name
)
==
p
-
path
)
&&
strprefixeq
(
path
,
p
-
path
,
child
->
name
))
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
;
struct
label
*
l
;
assert
(
label
&&
(
strlen
(
label
)
>
0
));
for_each_label
(
tree
->
labels
,
l
)
if
(
streq
(
l
->
label
,
label
))
return
tree
;
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
;
if
((
phandle
==
0
)
||
(
phandle
==
-
1
))
{
assert
(
generate_fixups
);
return
NULL
;
}
if
(
tree
->
phandle
==
phandle
)
{
if
(
tree
->
deleted
)
return
NULL
;
return
tree
;
}
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
)
{
if
(
streq
(
ref
,
"/"
))
return
tree
;
else
if
(
ref
[
0
]
==
'/'
)
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 */
if
((
node
->
phandle
!=
0
)
&&
(
node
->
phandle
!=
-
1
))
return
node
->
phandle
;
while
(
get_node_by_phandle
(
root
,
phandle
))
phandle
++
;
node
->
phandle
=
phandle
;
if
(
!
get_property
(
node
,
"linux,phandle"
)
&&
(
phandle_format
&
PHANDLE_LEGACY
))
add_property
(
node
,
build_property
(
"linux,phandle"
,
data_append_cell
(
empty_data
,
phandle
)));
if
(
!
get_property
(
node
,
"phandle"
)
&&
(
phandle_format
&
PHANDLE_EPAPR
))
add_property
(
node
,
build_property
(
"phandle"
,
data_append_cell
(
empty_data
,
phandle
)));
/* 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 */
return
node
->
phandle
;
}
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
);
if
(
a
->
address
<
b
->
address
)
return
-
1
;
else
if
(
a
->
address
>
b
->
address
)
return
1
;
else
if
(
a
->
size
<
b
->
size
)
return
-
1
;
else
if
(
a
->
size
>
b
->
size
)
return
1
;
else
return
0
;
}
static
void
sort_reserve_entries
(
struct
dt_info
*
dti
)
{
struct
reserve_info
*
ri
,
**
tbl
;
int
n
=
0
,
i
=
0
;
for
(
ri
=
dti
->
reservelist
;
ri
;
ri
=
ri
->
next
)
n
++
;
if
(
n
==
0
)
return
;
tbl
=
xmalloc
(
n
*
sizeof
(
*
tbl
));
for
(
ri
=
dti
->
reservelist
;
ri
;
ri
=
ri
->
next
)
tbl
[
i
++
]
=
ri
;
qsort
(
tbl
,
n
,
sizeof
(
*
tbl
),
cmp_reserve_info
);
dti
->
reservelist
=
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_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
;
for_each_property_withdel
(
node
,
prop
)
n
++
;
if
(
n
==
0
)
return
;
tbl
=
xmalloc
(
n
*
sizeof
(
*
tbl
));
for_each_property_withdel
(
node
,
prop
)
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
;
for_each_child_withdel
(
node
,
subnode
)
n
++
;
if
(
n
==
0
)
return
;
tbl
=
xmalloc
(
n
*
sizeof
(
*
tbl
));
for_each_child_withdel
(
node
,
subnode
)
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
);
for_each_child_withdel
(
node
,
c
)
sort_node
(
c
);
}
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
;
node
=
build_node
(
NULL
,
NULL
);
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
,
data_copy_mem
(
node
->
fullpath
,
strlen
(
node
->
fullpath
)
+
1
));
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
)
{
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
);
append_to_property
(
fn
,
m
->
ref
,
entry
,
strlen
(
entry
)
+
1
);
free
(
entry
);
}
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 */
fdt32_t
value_32
;
char
**
compp
;
int
i
,
depth
;
/* walk back retreiving depth */
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
);
append_to_property
(
wn
,
prop
->
name
,
&
value_32
,
sizeof
(
value_32
));
}
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
);
}
u-boot-tree/scripts/dtc/pylibfdt/.gitignore
0 → 100644
View file @
7496de94
/_libfdt.so
/libfdt.py
/libfdt.pyc
/libfdt_wrap.c
u-boot-tree/scripts/dtc/pylibfdt/Makefile
0 → 100644
View file @
7496de94
# Unfortunately setup.py below cannot handle srctree being ".." which it often
# is. It fails with an error like:
# Fatal error: can't create build/temp.linux-x86_64-2.7/../lib/libfdt/fdt.o:
# No such file or directory
# To fix this, use an absolute path.
LIBFDT_srcdir
=
$
(
abspath
$(srctree)
/
$(src)
/../libfdt
)
include
$(LIBFDT_srcdir)/Makefile.libfdt
# Unfortunately setup.py (or actually the Python distutil implementation) puts
# files into the same directory as the .i file. We cannot touch the source
# directory, so we "ship" .i file into the objtree.
PYLIBFDT_srcs
=
$
(
addprefix
$(LIBFDT_srcdir)
/,
$(LIBFDT_SRCS)
)
\
$(obj)
/libfdt.i
quiet_cmd_pymod
=
PYMOD
$@
cmd_pymod
=
unset
CROSS_COMPILE
;
unset
CFLAGS
;
\
CC
=
"
$(HOSTCC)
"
LDSHARED
=
"
$(HOSTCC)
-shared "
\
LDFLAGS
=
"
$(HOSTLDFLAGS)
"
\
VERSION
=
"u-boot-
$(UBOOTVERSION)
"
\
CPPFLAGS
=
"
$(HOSTCFLAGS)
-I
$(LIBFDT_srcdir)
"
OBJDIR
=
$(obj)
\
SOURCES
=
"
$(PYLIBFDT_srcs)
"
\
SWIG_OPTS
=
"-I
$(LIBFDT_srcdir)
-I
$(LIBFDT_srcdir)
/.."
\
$(PYTHON)
$<
--quiet
build_ext
--inplace
$(obj)/_libfdt.so
:
$(src)/setup.py $(PYLIBFDT_srcs) FORCE
$
(
call if_changed,pymod
)
always
+=
_libfdt.so
clean-files
+=
libfdt.i _libfdt.so libfdt.py libfdt_wrap.c
u-boot-tree/scripts/dtc/pylibfdt/libfdt.i_shipped
0 → 100644
View file @
7496de94
/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
/*
* pylibfdt - Flat Device Tree manipulation in Python
* Copyright (C) 2017 Google, Inc.
* Written by Simon Glass <sjg@chromium.org>
*/
%module libfdt
%include <stdint.i>
%{
#define SWIG_FILE_WITH_INIT
#include "libfdt.h"
/*
* We rename this function here to avoid problems with swig, since we also have
* a struct called fdt_property. That struct causes swig to create a class in
* libfdt.py called fdt_property(), which confuses things.
*/
static int fdt_property_stub(void *fdt, const char *name, const char *val,
int len)
{
return fdt_property(fdt, name, val, len);
}
%}
%pythoncode %{
import struct
# Error codes, corresponding to FDT_ERR_... in libfdt.h
(NOTFOUND,
EXISTS,
NOSPACE,
BADOFFSET,
BADPATH,
BADPHANDLE,
BADSTATE,
TRUNCATED,
BADMAGIC,
BADVERSION,
BADSTRUCTURE,
BADLAYOUT,
INTERNAL,
BADNCELLS,
BADVALUE,
BADOVERLAY,
NOPHANDLES) = QUIET_ALL = range(1, 18)
# QUIET_ALL can be passed as the 'quiet' parameter to avoid exceptions
# altogether. All # functions passed this value will return an error instead
# of raising an exception.
# Pass this as the 'quiet' parameter to return -ENOTFOUND on NOTFOUND errors,
# instead of raising an exception.
QUIET_NOTFOUND = (NOTFOUND,)
QUIET_NOSPACE = (NOSPACE,)
class FdtException(Exception):
"""An exception caused by an error such as one of the codes above"""
def __init__(self, err):
self.err = err
def __str__(self):
return 'pylibfdt error %d: %s' % (self.err, fdt_strerror(self.err))
def strerror(fdt_err):
"""Get the string for an error number
Args:
fdt_err: Error number (-ve)
Returns:
String containing the associated error
"""
return fdt_strerror(fdt_err)
def check_err(val, quiet=()):
"""Raise an error if the return value is -ve
This is used to check for errors returned by libfdt C functions.
Args:
val: Return value from a libfdt function
quiet: Errors to ignore (empty to raise on all errors)
Returns:
val if val >= 0
Raises
FdtException if val < 0
"""
if val < 0:
if -val not in quiet:
raise FdtException(val)
return val
def check_err_null(val, quiet=()):
"""Raise an error if the return value is NULL
This is used to check for a NULL return value from certain libfdt C
functions
Args:
val: Return value from a libfdt function
quiet: Errors to ignore (empty to raise on all errors)
Returns:
val if val is a list, None if not
Raises
FdtException if val indicates an error was reported and the error
is not in @quiet.
"""
# Normally a list is returned which contains the data and its length.
# If we get just an integer error code, it means the function failed.
if not isinstance(val, list):
if -val not in quiet:
raise FdtException(val)
return val
class FdtRo(object):
"""Class for a read-only device-tree
This is a base class used by FdtRw (read-write access) and FdtSw
(sequential-write access). It implements read-only access to the
device tree.
Here are the three classes and when you should use them:
FdtRo - read-only access to an existing FDT
FdtRw - read-write access to an existing FDT (most common case)
FdtSw - for creating a new FDT, as well as allowing read-only access
"""
def __init__(self, data):
self._fdt = bytearray(data)
check_err(fdt_check_header(self._fdt));
def as_bytearray(self):
"""Get the device tree contents as a bytearray
This can be passed directly to libfdt functions that access a
const void * for the device tree.
Returns:
bytearray containing the device tree
"""
return bytearray(self._fdt)
def next_node(self, nodeoffset, depth, quiet=()):
"""Find the next subnode
Args:
nodeoffset: Node offset of previous node
depth: The depth of the node at nodeoffset. This is used to
calculate the depth of the returned node
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Typle:
Offset of the next node, if any, else a -ve error
Depth of the returned node, if any, else undefined
Raises:
FdtException if no more nodes found or other error occurs
"""
return check_err(fdt_next_node(self._fdt, nodeoffset, depth), quiet)
def first_subnode(self, nodeoffset, quiet=()):
"""Find the first subnode of a parent node
Args:
nodeoffset: Node offset of parent node
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of the first subnode, if any
Raises:
FdtException if no subnodes found or other error occurs
"""
return check_err(fdt_first_subnode(self._fdt, nodeoffset), quiet)
def next_subnode(self, nodeoffset, quiet=()):
"""Find the next subnode
Args:
nodeoffset: Node offset of previous subnode
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of the next subnode, if any
Raises:
FdtException if no more subnodes found or other error occurs
"""
return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet)
def magic(self):
"""Return the magic word from the header
Returns:
Magic word
"""
return fdt_magic(self._fdt)
def totalsize(self):
"""Return the total size of the device tree
Returns:
Total tree size in bytes
"""
return fdt_totalsize(self._fdt)
def off_dt_struct(self):
"""Return the start of the device-tree struct area
Returns:
Start offset of struct area
"""
return fdt_off_dt_struct(self._fdt)
def off_dt_strings(self):
"""Return the start of the device-tree string area
Returns:
Start offset of string area
"""
return fdt_off_dt_strings(self._fdt)
def off_mem_rsvmap(self):
"""Return the start of the memory reserve map
Returns:
Start offset of memory reserve map
"""
return fdt_off_mem_rsvmap(self._fdt)
def version(self):
"""Return the version of the device tree
Returns:
Version number of the device tree
"""
return fdt_version(self._fdt)
def last_comp_version(self):
"""Return the last compatible version of the device tree
Returns:
Last compatible version number of the device tree
"""
return fdt_last_comp_version(self._fdt)
def boot_cpuid_phys(self):
"""Return the physical boot CPU ID
Returns:
Physical boot CPU ID
"""
return fdt_boot_cpuid_phys(self._fdt)
def size_dt_strings(self):
"""Return the start of the device-tree string area
Returns:
Start offset of string area
"""
return fdt_size_dt_strings(self._fdt)
def size_dt_struct(self):
"""Return the start of the device-tree struct area
Returns:
Start offset of struct area
"""
return fdt_size_dt_struct(self._fdt)
def num_mem_rsv(self, quiet=()):
"""Return the number of memory reserve-map records
Returns:
Number of memory reserve-map records
"""
return check_err(fdt_num_mem_rsv(self._fdt), quiet)
def get_mem_rsv(self, index, quiet=()):
"""Return the indexed memory reserve-map record
Args:
index: Record to return (0=first)
Returns:
Number of memory reserve-map records
"""
return check_err(fdt_get_mem_rsv(self._fdt, index), quiet)
def subnode_offset(self, parentoffset, name, quiet=()):
"""Get the offset of a named subnode
Args:
parentoffset: Offset of the parent node to check
name: Name of the required subnode, e.g. 'subnode@1'
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The node offset of the found node, if any
Raises
FdtException if there is no node with that name, or other error
"""
return check_err(fdt_subnode_offset(self._fdt, parentoffset, name),
quiet)
def path_offset(self, path, quiet=()):
"""Get the offset for a given path
Args:
path: Path to the required node, e.g. '/node@3/subnode@1'
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Node offset
Raises
FdtException if the path is not valid or not found
"""
return check_err(fdt_path_offset(self._fdt, path), quiet)
def get_name(self, nodeoffset):
"""Get the name of a node
Args:
nodeoffset: Offset of node to check
Returns:
Node name
Raises:
FdtException on error (e.g. nodeoffset is invalid)
"""
return check_err_null(fdt_get_name(self._fdt, nodeoffset))[0]
def first_property_offset(self, nodeoffset, quiet=()):
"""Get the offset of the first property in a node offset
Args:
nodeoffset: Offset to the node to check
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Offset of the first property
Raises
FdtException if the associated node has no properties, or some
other error occurred
"""
return check_err(fdt_first_property_offset(self._fdt, nodeoffset),
quiet)
def next_property_offset(self, prop_offset, quiet=()):
"""Get the next property in a node
Args:
prop_offset: Offset of the previous property
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Offset of the next property
Raises:
FdtException if the associated node has no more properties, or
some other error occurred
"""
return check_err(fdt_next_property_offset(self._fdt, prop_offset),
quiet)
def get_property_by_offset(self, prop_offset, quiet=()):
"""Obtains a property that can be examined
Args:
prop_offset: Offset of property (e.g. from first_property_offset())
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Property object, or None if not found
Raises:
FdtException on error (e.g. invalid prop_offset or device
tree format)
"""
pdata = check_err_null(
fdt_get_property_by_offset(self._fdt, prop_offset), quiet)
if isinstance(pdata, (int)):
return pdata
return Property(pdata[0], pdata[1])
def getprop(self, nodeoffset, prop_name, quiet=()):
"""Get a property from a node
Args:
nodeoffset: Node offset containing property to get
prop_name: Name of property to get
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Value of property as a Property object (which can be used as a
bytearray/string), or -ve error number. On failure, returns an
integer error
Raises:
FdtError if any error occurs (e.g. the property is not found)
"""
pdata = check_err_null(fdt_getprop(self._fdt, nodeoffset, prop_name),
quiet)
if isinstance(pdata, (int)):
return pdata
return Property(prop_name, bytearray(pdata[0]))
def get_phandle(self, nodeoffset):
"""Get the phandle of a node
Args:
nodeoffset: Node offset to check
Returns:
phandle of node, or 0 if the node has no phandle or another error
occurs
"""
return fdt_get_phandle(self._fdt, nodeoffset)
def parent_offset(self, nodeoffset, quiet=()):
"""Get the offset of a node's parent
Args:
nodeoffset: Node offset to check
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of the parent node, if any
Raises:
FdtException if no parent found or other error occurs
"""
return check_err(fdt_parent_offset(self._fdt, nodeoffset), quiet)
def node_offset_by_phandle(self, phandle, quiet=()):
"""Get the offset of a node with the given phandle
Args:
phandle: Phandle to search for
quiet: Errors to ignore (empty to raise on all errors)
Returns:
The offset of node with that phandle, if any
Raises:
FdtException if no node found or other error occurs
"""
return check_err(fdt_node_offset_by_phandle(self._fdt, phandle), quiet)
class Fdt(FdtRo):
"""Device tree class, supporting all operations
The Fdt object is created is created from a device tree binary file,
e.g. with something like:
fdt = Fdt(open("filename.dtb").read())
Operations can then be performed using the methods in this class. Each
method xxx(args...) corresponds to a libfdt function fdt_xxx(fdt, args...).
All methods raise an FdtException if an error occurs. To avoid this
behaviour a 'quiet' parameter is provided for some functions. This
defaults to empty, but you can pass a list of errors that you expect.
If one of these errors occurs, the function will return an error number
(e.g. -NOTFOUND).
"""
def __init__(self, data):
FdtRo.__init__(self, data)
@staticmethod
def create_empty_tree(size, quiet=()):
"""Create an empty device tree ready for use
Args:
size: Size of device tree in bytes
Returns:
Fdt object containing the device tree
"""
data = bytearray(size)
err = check_err(fdt_create_empty_tree(data, size), quiet)
if err:
return err
return Fdt(data)
def resize(self, size, quiet=()):
"""Move the device tree into a larger or smaller space
This creates a new device tree of size @size and moves the existing
device tree contents over to that. It can be used to create more space
in a device tree. Note that the Fdt object remains the same, but it
now has a new bytearray holding the contents.
Args:
size: Required new size of device tree in bytes
"""
fdt = bytearray(size)
err = check_err(fdt_open_into(self._fdt, fdt, size), quiet)
if err:
return err
self._fdt = fdt
def pack(self, quiet=()):
"""Pack the device tree to remove unused space
This adjusts the tree in place.
Args:
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Error code, or 0 if OK
Raises:
FdtException if any error occurs
"""
err = check_err(fdt_pack(self._fdt), quiet)
if err:
return err
del self._fdt[self.totalsize():]
return err
def set_name(self, nodeoffset, name, quiet=()):
"""Set the name of a node
Args:
nodeoffset: Node offset of node to update
name: New node name (string without \0)
Returns:
Error code, or 0 if OK
Raises:
FdtException if no parent found or other error occurs
"""
if chr(0) in name:
raise ValueError('Property contains embedded nul characters')
return check_err(fdt_set_name(self._fdt, nodeoffset, name), quiet)
def setprop(self, nodeoffset, prop_name, val, quiet=()):
"""Set the value of a property
Args:
nodeoffset: Node offset containing the property to create/update
prop_name: Name of property
val: Value to write (string or bytearray)
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Error code, or 0 if OK
Raises:
FdtException if no parent found or other error occurs
"""
return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name, val,
len(val)), quiet)
def setprop_u32(self, nodeoffset, prop_name, val, quiet=()):
"""Set the value of a property
Args:
nodeoffset: Node offset containing the property to create/update
prop_name: Name of property
val: Value to write (integer)
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Error code, or 0 if OK
Raises:
FdtException if no parent found or other error occurs
"""
return check_err(fdt_setprop_u32(self._fdt, nodeoffset, prop_name, val),
quiet)
def setprop_u64(self, nodeoffset, prop_name, val, quiet=()):
"""Set the value of a property
Args:
nodeoffset: Node offset containing the property to create/update
prop_name: Name of property
val: Value to write (integer)
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Error code, or 0 if OK
Raises:
FdtException if no parent found or other error occurs
"""
return check_err(fdt_setprop_u64(self._fdt, nodeoffset, prop_name, val),
quiet)
def setprop_str(self, nodeoffset, prop_name, val, quiet=()):
"""Set the string value of a property
The property is set to the string, with a nul terminator added
Args:
nodeoffset: Node offset containing the property to create/update
prop_name: Name of property
val: Value to write (string without nul terminator). Unicode is
supposed by encoding to UTF-8
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Error code, or 0 if OK
Raises:
FdtException if no parent found or other error occurs
"""
val = val.encode('utf-8') + '\0'
return check_err(fdt_setprop(self._fdt, nodeoffset, prop_name,
val, len(val)), quiet)
def delprop(self, nodeoffset, prop_name, quiet=()):
"""Delete a property from a node
Args:
nodeoffset: Node offset containing property to delete
prop_name: Name of property to delete
quiet: Errors to ignore (empty to raise on all errors)
Returns:
Error code, or 0 if OK
Raises:
FdtError if the property does not exist, or another error occurs
"""
return check_err(fdt_delprop(self._fdt, nodeoffset, prop_name), quiet)
def add_subnode(self, parentoffset, name, quiet=()):
"""Add a new subnode to a node
Args:
parentoffset: Parent offset to add the subnode to
name: Name of node to add
Returns:
offset of the node created, or negative error code on failure
Raises:
FdtError if there is not enough space, or another error occurs
"""
return check_err(fdt_add_subnode(self._fdt, parentoffset, name), quiet)
def del_node(self, nodeoffset, quiet=()):
"""Delete a node
Args:
nodeoffset: Offset of node to delete
Returns:
Error code, or 0 if OK
Raises:
FdtError if an error occurs
"""
return check_err(fdt_del_node(self._fdt, nodeoffset), quiet)
class Property(bytearray):
"""Holds a device tree property name and value.
This holds a copy of a property taken from the device tree. It does not
reference the device tree, so if anything changes in the device tree,
a Property object will remain valid.
Properties:
name: Property name
value: Property value as a bytearray
"""
def __init__(self, name, value):
bytearray.__init__(self, value)
self.name = name
def as_cell(self, fmt):
return struct.unpack('>' + fmt, self)[0]
def as_uint32(self):
return self.as_cell('L')
def as_int32(self):
return self.as_cell('l')
def as_uint64(self):
return self.as_cell('Q')
def as_int64(self):
return self.as_cell('q')
def as_str(self):
"""Unicode is supported by decoding from UTF-8"""
if self[-1] != 0:
raise ValueError('Property lacks nul termination')
if 0 in self[:-1]:
raise ValueError('Property contains embedded nul characters')
return self[:-1].decode('utf-8')
class FdtSw(FdtRo):
"""Software interface to create a device tree from scratch
The methods in this class work by adding to an existing 'partial' device
tree buffer of a fixed size created by instantiating this class. When the
tree is complete, call as_fdt() to obtain a device tree ready to be used.
Similarly with nodes, a new node is started with begin_node() and finished
with end_node().
The context manager functions can be used to make this a bit easier:
# First create the device tree with a node and property:
sw = FdtSw()
with sw.add_node('node'):
sw.property_u32('reg', 2)
fdt = sw.as_fdt()
# Now we can use it as a real device tree
fdt.setprop_u32(0, 'reg', 3)
The size hint provides a starting size for the space to be used by the
device tree. This will be increased automatically as needed as new items
are added to the tree.
"""
INC_SIZE = 1024 # Expand size by this much when out of space
def __init__(self, size_hint=None):
"""Create a new FdtSw object
Args:
size_hint: A hint as to the initial size to use
Raises:
ValueError if size_hint is negative
Returns:
FdtSw object on success, else integer error code (if not raising)
"""
if not size_hint:
size_hint = self.INC_SIZE
fdtsw = bytearray(size_hint)
err = check_err(fdt_create(fdtsw, size_hint))
if err:
return err
self._fdt = fdtsw
def as_fdt(self):
"""Convert a FdtSw into an Fdt so it can be accessed as normal
Creates a new Fdt object from the work-in-progress device tree. This
does not call fdt_finish() on the current object, so it is possible to
add more nodes/properties and call as_fdt() again to get an updated
tree.
Returns:
Fdt object allowing access to the newly created device tree
"""
fdtsw = bytearray(self._fdt)
check_err(fdt_finish(fdtsw))
return Fdt(fdtsw)
def check_space(self, val):
"""Check if we need to add more space to the FDT
This should be called with the error code from an operation. If this is
-NOSPACE then the FDT will be expanded to have more space, and True will
be returned, indicating that the operation needs to be tried again.
Args:
val: Return value from the operation that was attempted
Returns:
True if the operation must be retried, else False
"""
if check_err(val, QUIET_NOSPACE) < 0:
self.resize(len(self._fdt) + self.INC_SIZE)
return True
return False
def resize(self, size):
"""Resize the buffer to accommodate a larger tree
Args:
size: New size of tree
Raises:
FdtException on any error
"""
fdt = bytearray(size)
err = check_err(fdt_resize(self._fdt, fdt, size))
self._fdt = fdt
def add_reservemap_entry(self, addr, size):
"""Add a new memory reserve map entry
Once finished adding, you must call finish_reservemap().
Args:
addr: 64-bit start address
size: 64-bit size
Raises:
FdtException on any error
"""
while self.check_space(fdt_add_reservemap_entry(self._fdt, addr,
size)):
pass
def finish_reservemap(self):
"""Indicate that there are no more reserve map entries to add
Raises:
FdtException on any error
"""
while self.check_space(fdt_finish_reservemap(self._fdt)):
pass
def begin_node(self, name):
"""Begin a new node
Use this before adding properties to the node. Then call end_node() to
finish it. You can also use the context manager as shown in the FdtSw
class comment.
Args:
name: Name of node to begin
Raises:
FdtException on any error
"""
while self.check_space(fdt_begin_node(self._fdt, name)):
pass
def property_string(self, name, string):
"""Add a property with a string value
The string will be nul-terminated when written to the device tree
Args:
name: Name of property to add
string: String value of property
Raises:
FdtException on any error
"""
while self.check_space(fdt_property_string(self._fdt, name, string)):
pass
def property_u32(self, name, val):
"""Add a property with a 32-bit value
Write a single-cell value to the device tree
Args:
name: Name of property to add
val: Value of property
Raises:
FdtException on any error
"""
while self.check_space(fdt_property_u32(self._fdt, name, val)):
pass
def property_u64(self, name, val):
"""Add a property with a 64-bit value
Write a double-cell value to the device tree in big-endian format
Args:
name: Name of property to add
val: Value of property
Raises:
FdtException on any error
"""
while self.check_space(fdt_property_u64(self._fdt, name, val)):
pass
def property_cell(self, name, val):
"""Add a property with a single-cell value
Write a single-cell value to the device tree
Args:
name: Name of property to add
val: Value of property
quiet: Errors to ignore (empty to raise on all errors)
Raises:
FdtException on any error
"""
while self.check_space(fdt_property_cell(self._fdt, name, val)):
pass
def property(self, name, val):
"""Add a property
Write a new property with the given value to the device tree. The value
is taken as is and is not nul-terminated
Args:
name: Name of property to add
val: Value of property
quiet: Errors to ignore (empty to raise on all errors)
Raises:
FdtException on any error
"""
while self.check_space(fdt_property_stub(self._fdt, name, val,
len(val))):
pass
def end_node(self):
"""End a node
Use this after adding properties to a node to close it off. You can also
use the context manager as shown in the FdtSw class comment.
Args:
quiet: Errors to ignore (empty to raise on all errors)
Raises:
FdtException on any error
"""
while self.check_space(fdt_end_node(self._fdt)):
pass
def add_node(self, name):
"""Create a new context for adding a node
When used in a 'with' clause this starts a new node and finishes it
afterward.
Args:
name: Name of node to add
"""
return NodeAdder(self, name)
class NodeAdder():
"""Class to provide a node context
This allows you to add nodes in a more natural way:
with fdtsw.add_node('name'):
fdtsw.property_string('test', 'value')
The node is automatically completed with a call to end_node() when the
context exits.
"""
def __init__(self, fdtsw, name):
self._fdt = fdtsw
self._name = name
def __enter__(self):
self._fdt.begin_node(self._name)
def __exit__(self, type, value, traceback):
self._fdt.end_node()
%}
%rename(fdt_property) fdt_property_func;
/*
* fdt32_t is a big-endian 32-bit value defined to uint32_t in libfdt_env.h
* so use the same type here.
*/
typedef uint32_t fdt32_t;
%include "libfdt/fdt.h"
%include "typemaps.i"
/* Most functions don't change the device tree, so use a const void * */
%typemap(in) (const void *)(const void *fdt) {
if (!PyByteArray_Check($input)) {
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
"', argument " "$argnum"" of type '" "$type""'");
}
$1 = (void *)PyByteArray_AsString($input);
fdt = $1;
fdt = fdt; /* avoid unused variable warning */
}
/* Some functions do change the device tree, so use void * */
%typemap(in) (void *)(const void *fdt) {
if (!PyByteArray_Check($input)) {
SWIG_exception_fail(SWIG_TypeError, "in method '" "$symname"
"', argument " "$argnum"" of type '" "$type""'");
}
$1 = PyByteArray_AsString($input);
fdt = $1;
fdt = fdt; /* avoid unused variable warning */
}
/* typemap used for fdt_get_property_by_offset() */
%typemap(out) (struct fdt_property *) {
PyObject *buff;
if ($1) {
resultobj = PyString_FromString(
fdt_string(fdt1, fdt32_to_cpu($1->nameoff)));
buff = PyByteArray_FromStringAndSize(
(const char *)($1 + 1), fdt32_to_cpu($1->len));
resultobj = SWIG_Python_AppendOutput(resultobj, buff);
}
}
%apply int *OUTPUT { int *lenp };
/* typemap used for fdt_getprop() */
%typemap(out) (const void *) {
if (!$1)
$result = Py_None;
else
$result = Py_BuildValue("s#", $1, *arg4);
}
/* typemap used for fdt_setprop() */
%typemap(in) (const void *val) {
$1 = PyString_AsString($input); /* char *str */
}
/* typemap used for fdt_add_reservemap_entry() */
%typemap(in) uint64_t {
$1 = PyLong_AsUnsignedLong($input);
}
/* typemaps used for fdt_next_node() */
%typemap(in, numinputs=1) int *depth (int depth) {
depth = (int) PyInt_AsLong($input);
$1 = &depth;
}
%typemap(argout) int *depth {
PyObject *val = Py_BuildValue("i", *arg$argnum);
resultobj = SWIG_Python_AppendOutput(resultobj, val);
}
%apply int *depth { int *depth };
/* typemaps for fdt_get_mem_rsv */
%typemap(in, numinputs=0) uint64_t * (uint64_t temp) {
$1 = &temp;
}
%typemap(argout) uint64_t * {
PyObject *val = PyLong_FromUnsignedLong(*arg$argnum);
if (!result) {
if (PyTuple_GET_SIZE(resultobj) == 0)
resultobj = val;
else
resultobj = SWIG_Python_AppendOutput(resultobj, val);
}
}
/* We have both struct fdt_property and a function fdt_property() */
%warnfilter(302) fdt_property;
/* These are macros in the header so have to be redefined here */
uint32_t fdt_magic(const void *fdt);
uint32_t fdt_totalsize(const void *fdt);
uint32_t fdt_off_dt_struct(const void *fdt);
uint32_t fdt_off_dt_strings(const void *fdt);
uint32_t fdt_off_mem_rsvmap(const void *fdt);
uint32_t fdt_version(const void *fdt);
uint32_t fdt_last_comp_version(const void *fdt);
uint32_t fdt_boot_cpuid_phys(const void *fdt);
uint32_t fdt_size_dt_strings(const void *fdt);
uint32_t fdt_size_dt_struct(const void *fdt);
int fdt_property_string(void *fdt, const char *name, const char *val);
int fdt_property_cell(void *fdt, const char *name, uint32_t val);
/*
* This function has a stub since the name fdt_property is used for both a
* function and a struct, which confuses SWIG.
*/
int fdt_property_stub(void *fdt, const char *name, const char *val, int len);
%include <../libfdt/libfdt.h>
u-boot-tree/scripts/dtc/pylibfdt/setup.py
0 → 100755
View file @
7496de94
#!/usr/bin/env python2
"""
setup.py file for SWIG libfdt
Copyright (C) 2017 Google, Inc.
Written by Simon Glass <sjg@chromium.org>
SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
Files to be built into the extension are provided in SOURCES
C flags to use are provided in CPPFLAGS
Object file directory is provided in OBJDIR
Version is provided in VERSION
If these variables are not given they are parsed from the Makefiles. This
allows this script to be run stand-alone, e.g.:
./pylibfdt/setup.py install [--prefix=...]
"""
from
distutils.core
import
setup
,
Extension
import
os
import
re
import
sys
# Decodes a Makefile assignment line into key and value (and plus for +=)
RE_KEY_VALUE
=
re
.
compile
(
'(?P<key>
\
w+) *(?P<plus>[+])?= *(?P<value>.*)$'
)
def
ParseMakefile
(
fname
):
"""Parse a Makefile to obtain its variables.
This collects variable assigments of the form:
VAR = value
VAR += more
It does not pick out := assignments, as these are not needed here. It does
handle line continuation.
Returns a dict:
key: Variable name (e.g. 'VAR')
value: Variable value (e.g. 'value more')
"""
makevars
=
{}
with
open
(
fname
)
as
fd
:
prev_text
=
''
# Continuation text from previous line(s)
for
line
in
fd
.
read
()
.
splitlines
():
if
line
and
line
[
-
1
]
==
'
\\
'
:
# Deal with line continuation
prev_text
+=
line
[:
-
1
]
continue
elif
prev_text
:
line
=
prev_text
+
line
prev_text
=
''
# Continuation is now used up
m
=
RE_KEY_VALUE
.
match
(
line
)
if
m
:
value
=
m
.
group
(
'value'
)
or
''
key
=
m
.
group
(
'key'
)
# Appending to a variable inserts a space beforehand
if
'plus'
in
m
.
groupdict
()
and
key
in
makevars
:
makevars
[
key
]
+=
' '
+
value
else
:
makevars
[
key
]
=
value
return
makevars
def
GetEnvFromMakefiles
():
"""Scan the Makefiles to obtain the settings we need.
This assumes that this script is being run from the top-level directory,
not the pylibfdt directory.
Returns:
Tuple with:
List of swig options
Version string
List of files to build
List of extra C preprocessor flags needed
Object directory to use (always '')
"""
basedir
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
abspath
(
sys
.
argv
[
0
])))
swig_opts
=
[
'-I
%
s'
%
basedir
]
makevars
=
ParseMakefile
(
os
.
path
.
join
(
basedir
,
'Makefile'
))
version
=
'
%
s.
%
s.
%
s'
%
(
makevars
[
'VERSION'
],
makevars
[
'PATCHLEVEL'
],
makevars
[
'SUBLEVEL'
])
makevars
=
ParseMakefile
(
os
.
path
.
join
(
basedir
,
'libfdt'
,
'Makefile.libfdt'
))
files
=
makevars
[
'LIBFDT_SRCS'
]
.
split
()
files
=
[
os
.
path
.
join
(
basedir
,
'libfdt'
,
fname
)
for
fname
in
files
]
files
.
append
(
'pylibfdt/libfdt.i'
)
cflags
=
[
'-I
%
s'
%
basedir
,
'-I
%
s/libfdt'
%
basedir
]
objdir
=
''
return
swig_opts
,
version
,
files
,
cflags
,
objdir
progname
=
sys
.
argv
[
0
]
files
=
os
.
environ
.
get
(
'SOURCES'
,
''
)
.
split
()
cflags
=
os
.
environ
.
get
(
'CPPFLAGS'
,
''
)
.
split
()
objdir
=
os
.
environ
.
get
(
'OBJDIR'
)
version
=
os
.
environ
.
get
(
'VERSION'
)
swig_opts
=
os
.
environ
.
get
(
'SWIG_OPTS'
,
''
)
.
split
()
# If we were called directly rather than through our Makefile (which is often
# the case with Python module installation), read the settings from the
# Makefile.
if
not
all
((
swig_opts
,
version
,
files
,
cflags
,
objdir
)):
swig_opts
,
version
,
files
,
cflags
,
objdir
=
GetEnvFromMakefiles
()
libfdt_module
=
Extension
(
'_libfdt'
,
sources
=
files
,
extra_compile_args
=
cflags
,
swig_opts
=
swig_opts
,
)
setup
(
name
=
'libfdt'
,
version
=
version
,
author
=
'Simon Glass <sjg@chromium.org>'
,
description
=
'Python binding for libfdt'
,
ext_modules
=
[
libfdt_module
],
package_dir
=
{
''
:
objdir
},
py_modules
=
[
'pylibfdt/libfdt'
],
)
u-boot-tree/scripts/dtc/srcpos.c
0 → 100644
View file @
7496de94
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#define _GNU_SOURCE
#include <stdio.h>
#include "dtc.h"
#include "srcpos.h"
/* A node in our list of directories to search for source/include files */
struct
search_path
{
struct
search_path
*
next
;
/* next node in list, NULL for end */
const
char
*
dirname
;
/* name of directory to search */
};
/* This is the list of directories that we search for source files */
static
struct
search_path
*
search_path_head
,
**
search_path_tail
;
static
char
*
get_dirname
(
const
char
*
path
)
{
const
char
*
slash
=
strrchr
(
path
,
'/'
);
if
(
slash
)
{
int
len
=
slash
-
path
;
char
*
dir
=
xmalloc
(
len
+
1
);
memcpy
(
dir
,
path
,
len
);
dir
[
len
]
=
'\0'
;
return
dir
;
}
return
NULL
;
}
FILE
*
depfile
;
/* = NULL */
struct
srcfile_state
*
current_srcfile
;
/* = NULL */
/* Detect infinite include recursion. */
#define MAX_SRCFILE_DEPTH (100)
static
int
srcfile_depth
;
/* = 0 */
/**
* Try to open a file in a given directory.
*
* If the filename is an absolute path, then dirname is ignored. If it is a
* relative path, then we look in that directory for the file.
*
* @param dirname Directory to look in, or NULL for none
* @param fname Filename to look for
* @param fp Set to NULL if file did not open
* @return allocated filename on success (caller must free), NULL on failure
*/
static
char
*
try_open
(
const
char
*
dirname
,
const
char
*
fname
,
FILE
**
fp
)
{
char
*
fullname
;
if
(
!
dirname
||
fname
[
0
]
==
'/'
)
fullname
=
xstrdup
(
fname
);
else
fullname
=
join_path
(
dirname
,
fname
);
*
fp
=
fopen
(
fullname
,
"rb"
);
if
(
!*
fp
)
{
free
(
fullname
);
fullname
=
NULL
;
}
return
fullname
;
}
/**
* Open a file for read access
*
* If it is a relative filename, we search the full search path for it.
*
* @param fname Filename to open
* @param fp Returns pointer to opened FILE, or NULL on failure
* @return pointer to allocated filename, which caller must free
*/
static
char
*
fopen_any_on_path
(
const
char
*
fname
,
FILE
**
fp
)
{
const
char
*
cur_dir
=
NULL
;
struct
search_path
*
node
;
char
*
fullname
;
/* Try current directory first */
assert
(
fp
);
if
(
current_srcfile
)
cur_dir
=
current_srcfile
->
dir
;
fullname
=
try_open
(
cur_dir
,
fname
,
fp
);
/* Failing that, try each search path in turn */
for
(
node
=
search_path_head
;
!*
fp
&&
node
;
node
=
node
->
next
)
fullname
=
try_open
(
node
->
dirname
,
fname
,
fp
);
return
fullname
;
}
FILE
*
srcfile_relative_open
(
const
char
*
fname
,
char
**
fullnamep
)
{
FILE
*
f
;
char
*
fullname
;
if
(
streq
(
fname
,
"-"
))
{
f
=
stdin
;
fullname
=
xstrdup
(
"<stdin>"
);
}
else
{
fullname
=
fopen_any_on_path
(
fname
,
&
f
);
if
(
!
f
)
die
(
"Couldn't open
\"
%s
\"
: %s
\n
"
,
fname
,
strerror
(
errno
));
}
if
(
depfile
)
fprintf
(
depfile
,
" %s"
,
fullname
);
if
(
fullnamep
)
*
fullnamep
=
fullname
;
else
free
(
fullname
);
return
f
;
}
void
srcfile_push
(
const
char
*
fname
)
{
struct
srcfile_state
*
srcfile
;
if
(
srcfile_depth
++
>=
MAX_SRCFILE_DEPTH
)
die
(
"Includes nested too deeply"
);
srcfile
=
xmalloc
(
sizeof
(
*
srcfile
));
srcfile
->
f
=
srcfile_relative_open
(
fname
,
&
srcfile
->
name
);
srcfile
->
dir
=
get_dirname
(
srcfile
->
name
);
srcfile
->
prev
=
current_srcfile
;
srcfile
->
lineno
=
1
;
srcfile
->
colno
=
1
;
current_srcfile
=
srcfile
;
}
bool
srcfile_pop
(
void
)
{
struct
srcfile_state
*
srcfile
=
current_srcfile
;
assert
(
srcfile
);
current_srcfile
=
srcfile
->
prev
;
if
(
fclose
(
srcfile
->
f
))
die
(
"Error closing
\"
%s
\"
: %s
\n
"
,
srcfile
->
name
,
strerror
(
errno
));
/* FIXME: We allow the srcfile_state structure to leak,
* because it could still be referenced from a location
* variable being carried through the parser somewhere. To
* fix this we could either allocate all the files from a
* table, or use a pool allocator. */
return
current_srcfile
?
true
:
false
;
}
void
srcfile_add_search_path
(
const
char
*
dirname
)
{
struct
search_path
*
node
;
/* Create the node */
node
=
xmalloc
(
sizeof
(
*
node
));
node
->
next
=
NULL
;
node
->
dirname
=
xstrdup
(
dirname
);
/* Add to the end of our list */
if
(
search_path_tail
)
*
search_path_tail
=
node
;
else
search_path_head
=
node
;
search_path_tail
=
&
node
->
next
;
}
/*
* The empty source position.
*/
struct
srcpos
srcpos_empty
=
{
.
first_line
=
0
,
.
first_column
=
0
,
.
last_line
=
0
,
.
last_column
=
0
,
.
file
=
NULL
,
};
void
srcpos_update
(
struct
srcpos
*
pos
,
const
char
*
text
,
int
len
)
{
int
i
;
pos
->
file
=
current_srcfile
;
pos
->
first_line
=
current_srcfile
->
lineno
;
pos
->
first_column
=
current_srcfile
->
colno
;
for
(
i
=
0
;
i
<
len
;
i
++
)
if
(
text
[
i
]
==
'\n'
)
{
current_srcfile
->
lineno
++
;
current_srcfile
->
colno
=
1
;
}
else
{
current_srcfile
->
colno
++
;
}
pos
->
last_line
=
current_srcfile
->
lineno
;
pos
->
last_column
=
current_srcfile
->
colno
;
}
struct
srcpos
*
srcpos_copy
(
struct
srcpos
*
pos
)
{
struct
srcpos
*
pos_new
;
pos_new
=
xmalloc
(
sizeof
(
struct
srcpos
));
memcpy
(
pos_new
,
pos
,
sizeof
(
struct
srcpos
));
return
pos_new
;
}
char
*
srcpos_string
(
struct
srcpos
*
pos
)
{
const
char
*
fname
=
"<no-file>"
;
char
*
pos_str
;
if
(
pos
->
file
&&
pos
->
file
->
name
)
fname
=
pos
->
file
->
name
;
if
(
pos
->
first_line
!=
pos
->
last_line
)
xasprintf
(
&
pos_str
,
"%s:%d.%d-%d.%d"
,
fname
,
pos
->
first_line
,
pos
->
first_column
,
pos
->
last_line
,
pos
->
last_column
);
else
if
(
pos
->
first_column
!=
pos
->
last_column
)
xasprintf
(
&
pos_str
,
"%s:%d.%d-%d"
,
fname
,
pos
->
first_line
,
pos
->
first_column
,
pos
->
last_column
);
else
xasprintf
(
&
pos_str
,
"%s:%d.%d"
,
fname
,
pos
->
first_line
,
pos
->
first_column
);
return
pos_str
;
}
void
srcpos_verror
(
struct
srcpos
*
pos
,
const
char
*
prefix
,
const
char
*
fmt
,
va_list
va
)
{
char
*
srcstr
;
srcstr
=
srcpos_string
(
pos
);
fprintf
(
stderr
,
"%s: %s "
,
prefix
,
srcstr
);
vfprintf
(
stderr
,
fmt
,
va
);
fprintf
(
stderr
,
"
\n
"
);
free
(
srcstr
);
}
void
srcpos_error
(
struct
srcpos
*
pos
,
const
char
*
prefix
,
const
char
*
fmt
,
...)
{
va_list
va
;
va_start
(
va
,
fmt
);
srcpos_verror
(
pos
,
prefix
,
fmt
,
va
);
va_end
(
va
);
}
void
srcpos_set_line
(
char
*
f
,
int
l
)
{
current_srcfile
->
name
=
f
;
current_srcfile
->
lineno
=
l
;
}
u-boot-tree/scripts/dtc/srcpos.h
0 → 100644
View file @
7496de94
/*
* Copyright 2007 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#ifndef SRCPOS_H
#define SRCPOS_H
#include <stdio.h>
#include <stdbool.h>
#include "util.h"
struct
srcfile_state
{
FILE
*
f
;
char
*
name
;
char
*
dir
;
int
lineno
,
colno
;
struct
srcfile_state
*
prev
;
};
extern
FILE
*
depfile
;
/* = NULL */
extern
struct
srcfile_state
*
current_srcfile
;
/* = NULL */
/**
* Open a source file.
*
* If the source file is a relative pathname, then it is searched for in the
* current directory (the directory of the last source file read) and after
* that in the search path.
*
* We work through the search path in order from the first path specified to
* the last.
*
* If the file is not found, then this function does not return, but calls
* die().
*
* @param fname Filename to search
* @param fullnamep If non-NULL, it is set to the allocated filename of the
* file that was opened. The caller is then responsible
* for freeing the pointer.
* @return pointer to opened FILE
*/
FILE
*
srcfile_relative_open
(
const
char
*
fname
,
char
**
fullnamep
);
void
srcfile_push
(
const
char
*
fname
);
bool
srcfile_pop
(
void
);
/**
* Add a new directory to the search path for input files
*
* The new path is added at the end of the list.
*
* @param dirname Directory to add
*/
void
srcfile_add_search_path
(
const
char
*
dirname
);
struct
srcpos
{
int
first_line
;
int
first_column
;
int
last_line
;
int
last_column
;
struct
srcfile_state
*
file
;
};
#define YYLTYPE struct srcpos
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
if (N) { \
(Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC(Rhs, N).last_line; \
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
(Current).file = YYRHSLOC(Rhs, N).file; \
} else { \
(Current).first_line = (Current).last_line = \
YYRHSLOC(Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
YYRHSLOC(Rhs, 0).last_column; \
(Current).file = YYRHSLOC (Rhs, 0).file; \
} \
} while (0)
/*
* Fictional source position used for IR nodes that are
* created without otherwise knowing a true source position.
* For example,constant definitions from the command line.
*/
extern
struct
srcpos
srcpos_empty
;
extern
void
srcpos_update
(
struct
srcpos
*
pos
,
const
char
*
text
,
int
len
);
extern
struct
srcpos
*
srcpos_copy
(
struct
srcpos
*
pos
);
extern
char
*
srcpos_string
(
struct
srcpos
*
pos
);
extern
void
PRINTF
(
3
,
0
)
srcpos_verror
(
struct
srcpos
*
pos
,
const
char
*
prefix
,
const
char
*
fmt
,
va_list
va
);
extern
void
PRINTF
(
3
,
4
)
srcpos_error
(
struct
srcpos
*
pos
,
const
char
*
prefix
,
const
char
*
fmt
,
...);
extern
void
srcpos_set_line
(
char
*
f
,
int
l
);
#endif
/* SRCPOS_H */
u-boot-tree/scripts/dtc/treesource.c
0 → 100644
View file @
7496de94
/*
* (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
*
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "dtc.h"
#include "srcpos.h"
extern
FILE
*
yyin
;
extern
int
yyparse
(
void
);
extern
YYLTYPE
yylloc
;
struct
dt_info
*
parser_output
;
bool
treesource_error
;
struct
dt_info
*
dt_from_source
(
const
char
*
fname
)
{
parser_output
=
NULL
;
treesource_error
=
false
;
srcfile_push
(
fname
);
yyin
=
current_srcfile
->
f
;
yylloc
.
file
=
current_srcfile
;
if
(
yyparse
()
!=
0
)
die
(
"Unable to parse input tree
\n
"
);
if
(
treesource_error
)
die
(
"Syntax error parsing input tree
\n
"
);
return
parser_output
;
}
static
void
write_prefix
(
FILE
*
f
,
int
level
)
{
int
i
;
for
(
i
=
0
;
i
<
level
;
i
++
)
fputc
(
'\t'
,
f
);
}
static
bool
isstring
(
char
c
)
{
return
(
isprint
((
unsigned
char
)
c
)
||
(
c
==
'\0'
)
||
strchr
(
"
\a\b\t\n\v\f\r
"
,
c
));
}
static
void
write_propval_string
(
FILE
*
f
,
struct
data
val
)
{
const
char
*
str
=
val
.
val
;
int
i
;
struct
marker
*
m
=
val
.
markers
;
assert
(
str
[
val
.
len
-
1
]
==
'\0'
);
while
(
m
&&
(
m
->
offset
==
0
))
{
if
(
m
->
type
==
LABEL
)
fprintf
(
f
,
"%s: "
,
m
->
ref
);
m
=
m
->
next
;
}
fprintf
(
f
,
"
\"
"
);
for
(
i
=
0
;
i
<
(
val
.
len
-
1
);
i
++
)
{
char
c
=
str
[
i
];
switch
(
c
)
{
case
'\a'
:
fprintf
(
f
,
"
\\
a"
);
break
;
case
'\b'
:
fprintf
(
f
,
"
\\
b"
);
break
;
case
'\t'
:
fprintf
(
f
,
"
\\
t"
);
break
;
case
'\n'
:
fprintf
(
f
,
"
\\
n"
);
break
;
case
'\v'
:
fprintf
(
f
,
"
\\
v"
);
break
;
case
'\f'
:
fprintf
(
f
,
"
\\
f"
);
break
;
case
'\r'
:
fprintf
(
f
,
"
\\
r"
);
break
;
case
'\\'
:
fprintf
(
f
,
"
\\\\
"
);
break
;
case
'\"'
:
fprintf
(
f
,
"
\\\"
"
);
break
;
case
'\0'
:
fprintf
(
f
,
"
\"
, "
);
while
(
m
&&
(
m
->
offset
<=
(
i
+
1
)))
{
if
(
m
->
type
==
LABEL
)
{
assert
(
m
->
offset
==
(
i
+
1
));
fprintf
(
f
,
"%s: "
,
m
->
ref
);
}
m
=
m
->
next
;
}
fprintf
(
f
,
"
\"
"
);
break
;
default:
if
(
isprint
((
unsigned
char
)
c
))
fprintf
(
f
,
"%c"
,
c
);
else
fprintf
(
f
,
"
\\
x%02hhx"
,
c
);
}
}
fprintf
(
f
,
"
\"
"
);
/* Wrap up any labels at the end of the value */
for_each_marker_of_type
(
m
,
LABEL
)
{
assert
(
m
->
offset
==
val
.
len
);
fprintf
(
f
,
" %s:"
,
m
->
ref
);
}
}
static
void
write_propval_cells
(
FILE
*
f
,
struct
data
val
)
{
void
*
propend
=
val
.
val
+
val
.
len
;
fdt32_t
*
cp
=
(
fdt32_t
*
)
val
.
val
;
struct
marker
*
m
=
val
.
markers
;
fprintf
(
f
,
"<"
);
for
(;;)
{
while
(
m
&&
(
m
->
offset
<=
((
char
*
)
cp
-
val
.
val
)))
{
if
(
m
->
type
==
LABEL
)
{
assert
(
m
->
offset
==
((
char
*
)
cp
-
val
.
val
));
fprintf
(
f
,
"%s: "
,
m
->
ref
);
}
m
=
m
->
next
;
}
fprintf
(
f
,
"0x%x"
,
fdt32_to_cpu
(
*
cp
++
));
if
((
void
*
)
cp
>=
propend
)
break
;
fprintf
(
f
,
" "
);
}
/* Wrap up any labels at the end of the value */
for_each_marker_of_type
(
m
,
LABEL
)
{
assert
(
m
->
offset
==
val
.
len
);
fprintf
(
f
,
" %s:"
,
m
->
ref
);
}
fprintf
(
f
,
">"
);
}
static
void
write_propval_bytes
(
FILE
*
f
,
struct
data
val
)
{
void
*
propend
=
val
.
val
+
val
.
len
;
const
char
*
bp
=
val
.
val
;
struct
marker
*
m
=
val
.
markers
;
fprintf
(
f
,
"["
);
for
(;;)
{
while
(
m
&&
(
m
->
offset
==
(
bp
-
val
.
val
)))
{
if
(
m
->
type
==
LABEL
)
fprintf
(
f
,
"%s: "
,
m
->
ref
);
m
=
m
->
next
;
}
fprintf
(
f
,
"%02hhx"
,
(
unsigned
char
)(
*
bp
++
));
if
((
const
void
*
)
bp
>=
propend
)
break
;
fprintf
(
f
,
" "
);
}
/* Wrap up any labels at the end of the value */
for_each_marker_of_type
(
m
,
LABEL
)
{
assert
(
m
->
offset
==
val
.
len
);
fprintf
(
f
,
" %s:"
,
m
->
ref
);
}
fprintf
(
f
,
"]"
);
}
static
void
write_propval
(
FILE
*
f
,
struct
property
*
prop
)
{
int
len
=
prop
->
val
.
len
;
const
char
*
p
=
prop
->
val
.
val
;
struct
marker
*
m
=
prop
->
val
.
markers
;
int
nnotstring
=
0
,
nnul
=
0
;
int
nnotstringlbl
=
0
,
nnotcelllbl
=
0
;
int
i
;
if
(
len
==
0
)
{
fprintf
(
f
,
";
\n
"
);
return
;
}
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
!
isstring
(
p
[
i
]))
nnotstring
++
;
if
(
p
[
i
]
==
'\0'
)
nnul
++
;
}
for_each_marker_of_type
(
m
,
LABEL
)
{
if
((
m
->
offset
>
0
)
&&
(
prop
->
val
.
val
[
m
->
offset
-
1
]
!=
'\0'
))
nnotstringlbl
++
;
if
((
m
->
offset
%
sizeof
(
cell_t
))
!=
0
)
nnotcelllbl
++
;
}
fprintf
(
f
,
" = "
);
if
((
p
[
len
-
1
]
==
'\0'
)
&&
(
nnotstring
==
0
)
&&
(
nnul
<
(
len
-
nnul
))
&&
(
nnotstringlbl
==
0
))
{
write_propval_string
(
f
,
prop
->
val
);
}
else
if
(((
len
%
sizeof
(
cell_t
))
==
0
)
&&
(
nnotcelllbl
==
0
))
{
write_propval_cells
(
f
,
prop
->
val
);
}
else
{
write_propval_bytes
(
f
,
prop
->
val
);
}
fprintf
(
f
,
";
\n
"
);
}
static
void
write_tree_source_node
(
FILE
*
f
,
struct
node
*
tree
,
int
level
)
{
struct
property
*
prop
;
struct
node
*
child
;
struct
label
*
l
;
write_prefix
(
f
,
level
);
for_each_label
(
tree
->
labels
,
l
)
fprintf
(
f
,
"%s: "
,
l
->
label
);
if
(
tree
->
name
&&
(
*
tree
->
name
))
fprintf
(
f
,
"%s {
\n
"
,
tree
->
name
);
else
fprintf
(
f
,
"/ {
\n
"
);
for_each_property
(
tree
,
prop
)
{
write_prefix
(
f
,
level
+
1
);
for_each_label
(
prop
->
labels
,
l
)
fprintf
(
f
,
"%s: "
,
l
->
label
);
fprintf
(
f
,
"%s"
,
prop
->
name
);
write_propval
(
f
,
prop
);
}
for_each_child
(
tree
,
child
)
{
fprintf
(
f
,
"
\n
"
);
write_tree_source_node
(
f
,
child
,
level
+
1
);
}
write_prefix
(
f
,
level
);
fprintf
(
f
,
"};
\n
"
);
}
void
dt_to_source
(
FILE
*
f
,
struct
dt_info
*
dti
)
{
struct
reserve_info
*
re
;
fprintf
(
f
,
"/dts-v1/;
\n\n
"
);
for
(
re
=
dti
->
reservelist
;
re
;
re
=
re
->
next
)
{
struct
label
*
l
;
for_each_label
(
re
->
labels
,
l
)
fprintf
(
f
,
"%s: "
,
l
->
label
);
fprintf
(
f
,
"/memreserve/
\t
0x%016llx 0x%016llx;
\n
"
,
(
unsigned
long
long
)
re
->
address
,
(
unsigned
long
long
)
re
->
size
);
}
write_tree_source_node
(
f
,
dti
->
dt
,
0
);
}
u-boot-tree/scripts/dtc/update-dtc-source.sh
0 → 100755
View file @
7496de94
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Simple script to update the version of DTC carried by the Linux kernel
#
# This script assumes that the dtc and the linux git trees are in the
# same directory. After building dtc in the dtc directory, it copies the
# source files and generated source file(s) into the scripts/dtc directory
# in the kernel and creates a git commit updating them to the new
# version.
#
# Usage: from the top level Linux source tree, run:
# $ ./scripts/dtc/update-dtc-source.sh
#
# The script will change into the dtc tree, build and test dtc, copy the
# relevant files into the kernel tree and create a git commit. The commit
# message will need to be modified to reflect the version of DTC being
# imported
#
# TODO:
# This script is pretty basic, but it is seldom used so a few manual tasks
# aren't a big deal. If anyone is interested in making it more robust, the
# the following would be nice:
# * Actually fail to complete if any testcase fails.
# - The dtc "make check" target needs to return a failure
# * Extract the version number from the dtc repo for the commit message
# * Build dtc in the kernel tree
# * run 'make check" on dtc built from the kernel tree
set
-ev
DTC_UPSTREAM_PATH
=
`
pwd
`
/../dtc
DTC_LINUX_PATH
=
`
pwd
`
/scripts/dtc
DTC_SOURCE
=
"checks.c data.c dtc.c dtc.h flattree.c fstree.c livetree.c srcpos.c
\
srcpos.h treesource.c util.c util.h version_gen.h Makefile.dtc
\
dtc-lexer.l dtc-parser.y"
LIBFDT_SOURCE
=
"Makefile.libfdt fdt.c fdt.h fdt_addresses.c fdt_empty_tree.c
\
fdt_overlay.c fdt_ro.c fdt_rw.c fdt_strerror.c fdt_sw.c
\
fdt_wip.c libfdt.h libfdt_env.h libfdt_internal.h"
get_last_dtc_version
()
{
git log
--oneline
scripts/dtc/ |
grep
'upstream'
|
head
-1
|
sed
-e
's/^.* \(.*\)/\1/'
}
last_dtc_ver
=
$(
get_last_dtc_version
)
# Build DTC
cd
$DTC_UPSTREAM_PATH
make clean
make check
dtc_version
=
$(
git describe HEAD
)
dtc_log
=
$(
git log
--oneline
${
last_dtc_ver
}
..
)
# Copy the files into the Linux tree
cd
$DTC_LINUX_PATH
for
f
in
$DTC_SOURCE
;
do
cp
${
DTC_UPSTREAM_PATH
}
/
${
f
}
${
f
}
git add
${
f
}
done
for
f
in
$LIBFDT_SOURCE
;
do
cp
${
DTC_UPSTREAM_PATH
}
/libfdt/
${
f
}
libfdt/
${
f
}
git add libfdt/
${
f
}
done
sed
-i
--
's/#include <libfdt_env.h>/#include "libfdt_env.h"/g'
./libfdt/libfdt.h
sed
-i
--
's/#include <fdt.h>/#include "fdt.h"/g'
./libfdt/libfdt.h
git add ./libfdt/libfdt.h
commit_msg
=
$(
cat
<<
EOF
scripts/dtc: Update to upstream version
${
dtc_version
}
This adds the following commits from upstream:
${
dtc_log
}
EOF
)
git commit
-e
-v
-s
-m
"
${
commit_msg
}
"
u-boot-tree/scripts/dtc/util.c
0 → 100644
View file @
7496de94
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* util_is_printable_string contributed by
* Pantelis Antoniou <pantelis.antoniou AT gmail.com>
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "libfdt.h"
#include "util.h"
#include "version_gen.h"
char
*
xstrdup
(
const
char
*
s
)
{
int
len
=
strlen
(
s
)
+
1
;
char
*
d
=
xmalloc
(
len
);
memcpy
(
d
,
s
,
len
);
return
d
;
}
/* based in part from (3) vsnprintf */
int
xasprintf
(
char
**
strp
,
const
char
*
fmt
,
...)
{
int
n
,
size
=
128
;
/* start with 128 bytes */
char
*
p
;
va_list
ap
;
/* initial pointer is NULL making the fist realloc to be malloc */
p
=
NULL
;
while
(
1
)
{
p
=
xrealloc
(
p
,
size
);
/* Try to print in the allocated space. */
va_start
(
ap
,
fmt
);
n
=
vsnprintf
(
p
,
size
,
fmt
,
ap
);
va_end
(
ap
);
/* If that worked, return the string. */
if
(
n
>
-
1
&&
n
<
size
)
break
;
/* Else try again with more space. */
if
(
n
>
-
1
)
/* glibc 2.1 */
size
=
n
+
1
;
/* precisely what is needed */
else
/* glibc 2.0 */
size
*=
2
;
/* twice the old size */
}
*
strp
=
p
;
return
strlen
(
p
);
}
char
*
join_path
(
const
char
*
path
,
const
char
*
name
)
{
int
lenp
=
strlen
(
path
);
int
lenn
=
strlen
(
name
);
int
len
;
int
needslash
=
1
;
char
*
str
;
len
=
lenp
+
lenn
+
2
;
if
((
lenp
>
0
)
&&
(
path
[
lenp
-
1
]
==
'/'
))
{
needslash
=
0
;
len
--
;
}
str
=
xmalloc
(
len
);
memcpy
(
str
,
path
,
lenp
);
if
(
needslash
)
{
str
[
lenp
]
=
'/'
;
lenp
++
;
}
memcpy
(
str
+
lenp
,
name
,
lenn
+
1
);
return
str
;
}
bool
util_is_printable_string
(
const
void
*
data
,
int
len
)
{
const
char
*
s
=
data
;
const
char
*
ss
,
*
se
;
/* zero length is not */
if
(
len
==
0
)
return
0
;
/* must terminate with zero */
if
(
s
[
len
-
1
]
!=
'\0'
)
return
0
;
se
=
s
+
len
;
while
(
s
<
se
)
{
ss
=
s
;
while
(
s
<
se
&&
*
s
&&
isprint
((
unsigned
char
)
*
s
))
s
++
;
/* not zero, or not done yet */
if
(
*
s
!=
'\0'
||
s
==
ss
)
return
0
;
s
++
;
}
return
1
;
}
/*
* Parse a octal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static
char
get_oct_char
(
const
char
*
s
,
int
*
i
)
{
char
x
[
4
];
char
*
endx
;
long
val
;
x
[
3
]
=
'\0'
;
strncpy
(
x
,
s
+
*
i
,
3
);
val
=
strtol
(
x
,
&
endx
,
8
);
assert
(
endx
>
x
);
(
*
i
)
+=
endx
-
x
;
return
val
;
}
/*
* Parse a hexadecimal encoded character starting at index i in string s. The
* resulting character will be returned and the index i will be updated to
* point at the character directly after the end of the encoding, this may be
* the '\0' terminator of the string.
*/
static
char
get_hex_char
(
const
char
*
s
,
int
*
i
)
{
char
x
[
3
];
char
*
endx
;
long
val
;
x
[
2
]
=
'\0'
;
strncpy
(
x
,
s
+
*
i
,
2
);
val
=
strtol
(
x
,
&
endx
,
16
);
if
(
!
(
endx
>
x
))
die
(
"
\\
x used with no following hex digits
\n
"
);
(
*
i
)
+=
endx
-
x
;
return
val
;
}
char
get_escape_char
(
const
char
*
s
,
int
*
i
)
{
char
c
=
s
[
*
i
];
int
j
=
*
i
+
1
;
char
val
;
switch
(
c
)
{
case
'a'
:
val
=
'\a'
;
break
;
case
'b'
:
val
=
'\b'
;
break
;
case
't'
:
val
=
'\t'
;
break
;
case
'n'
:
val
=
'\n'
;
break
;
case
'v'
:
val
=
'\v'
;
break
;
case
'f'
:
val
=
'\f'
;
break
;
case
'r'
:
val
=
'\r'
;
break
;
case
'0'
:
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
j
--
;
/* need to re-read the first digit as
* part of the octal value */
val
=
get_oct_char
(
s
,
&
j
);
break
;
case
'x'
:
val
=
get_hex_char
(
s
,
&
j
);
break
;
default:
val
=
c
;
}
(
*
i
)
=
j
;
return
val
;
}
int
utilfdt_read_err_len
(
const
char
*
filename
,
char
**
buffp
,
off_t
*
len
)
{
int
fd
=
0
;
/* assume stdin */
char
*
buf
=
NULL
;
off_t
bufsize
=
1024
,
offset
=
0
;
int
ret
=
0
;
*
buffp
=
NULL
;
if
(
strcmp
(
filename
,
"-"
)
!=
0
)
{
fd
=
open
(
filename
,
O_RDONLY
);
if
(
fd
<
0
)
return
errno
;
}
/* Loop until we have read everything */
buf
=
xmalloc
(
bufsize
);
do
{
/* Expand the buffer to hold the next chunk */
if
(
offset
==
bufsize
)
{
bufsize
*=
2
;
buf
=
xrealloc
(
buf
,
bufsize
);
}
ret
=
read
(
fd
,
&
buf
[
offset
],
bufsize
-
offset
);
if
(
ret
<
0
)
{
ret
=
errno
;
break
;
}
offset
+=
ret
;
}
while
(
ret
!=
0
);
/* Clean up, including closing stdin; return errno on error */
close
(
fd
);
if
(
ret
)
free
(
buf
);
else
*
buffp
=
buf
;
*
len
=
bufsize
;
return
ret
;
}
int
utilfdt_read_err
(
const
char
*
filename
,
char
**
buffp
)
{
off_t
len
;
return
utilfdt_read_err_len
(
filename
,
buffp
,
&
len
);
}
char
*
utilfdt_read_len
(
const
char
*
filename
,
off_t
*
len
)
{
char
*
buff
;
int
ret
=
utilfdt_read_err_len
(
filename
,
&
buff
,
len
);
if
(
ret
)
{
fprintf
(
stderr
,
"Couldn't open blob from '%s': %s
\n
"
,
filename
,
strerror
(
ret
));
return
NULL
;
}
/* Successful read */
return
buff
;
}
char
*
utilfdt_read
(
const
char
*
filename
)
{
off_t
len
;
return
utilfdt_read_len
(
filename
,
&
len
);
}
int
utilfdt_write_err
(
const
char
*
filename
,
const
void
*
blob
)
{
int
fd
=
1
;
/* assume stdout */
int
totalsize
;
int
offset
;
int
ret
=
0
;
const
char
*
ptr
=
blob
;
if
(
strcmp
(
filename
,
"-"
)
!=
0
)
{
fd
=
open
(
filename
,
O_WRONLY
|
O_CREAT
|
O_TRUNC
,
0666
);
if
(
fd
<
0
)
return
errno
;
}
totalsize
=
fdt_totalsize
(
blob
);
offset
=
0
;
while
(
offset
<
totalsize
)
{
ret
=
write
(
fd
,
ptr
+
offset
,
totalsize
-
offset
);
if
(
ret
<
0
)
{
ret
=
-
errno
;
break
;
}
offset
+=
ret
;
}
/* Close the file/stdin; return errno on error */
if
(
fd
!=
1
)
close
(
fd
);
return
ret
<
0
?
-
ret
:
0
;
}
int
utilfdt_write
(
const
char
*
filename
,
const
void
*
blob
)
{
int
ret
=
utilfdt_write_err
(
filename
,
blob
);
if
(
ret
)
{
fprintf
(
stderr
,
"Couldn't write blob to '%s': %s
\n
"
,
filename
,
strerror
(
ret
));
}
return
ret
?
-
1
:
0
;
}
int
utilfdt_decode_type
(
const
char
*
fmt
,
int
*
type
,
int
*
size
)
{
int
qualifier
=
0
;
if
(
!*
fmt
)
return
-
1
;
/* get the conversion qualifier */
*
size
=
-
1
;
if
(
strchr
(
"hlLb"
,
*
fmt
))
{
qualifier
=
*
fmt
++
;
if
(
qualifier
==
*
fmt
)
{
switch
(
*
fmt
++
)
{
/* TODO: case 'l': qualifier = 'L'; break;*/
case
'h'
:
qualifier
=
'b'
;
break
;
}
}
}
/* we should now have a type */
if
((
*
fmt
==
'\0'
)
||
!
strchr
(
"iuxs"
,
*
fmt
))
return
-
1
;
/* convert qualifier (bhL) to byte size */
if
(
*
fmt
!=
's'
)
*
size
=
qualifier
==
'b'
?
1
:
qualifier
==
'h'
?
2
:
qualifier
==
'l'
?
4
:
-
1
;
*
type
=
*
fmt
++
;
/* that should be it! */
if
(
*
fmt
)
return
-
1
;
return
0
;
}
void
utilfdt_print_data
(
const
char
*
data
,
int
len
)
{
int
i
;
const
char
*
s
;
/* no data, don't print */
if
(
len
==
0
)
return
;
if
(
util_is_printable_string
(
data
,
len
))
{
printf
(
" = "
);
s
=
data
;
do
{
printf
(
"
\"
%s
\"
"
,
s
);
s
+=
strlen
(
s
)
+
1
;
if
(
s
<
data
+
len
)
printf
(
", "
);
}
while
(
s
<
data
+
len
);
}
else
if
((
len
%
4
)
==
0
)
{
const
fdt32_t
*
cell
=
(
const
fdt32_t
*
)
data
;
printf
(
" = <"
);
for
(
i
=
0
,
len
/=
4
;
i
<
len
;
i
++
)
printf
(
"0x%08x%s"
,
fdt32_to_cpu
(
cell
[
i
]),
i
<
(
len
-
1
)
?
" "
:
""
);
printf
(
">"
);
}
else
{
const
unsigned
char
*
p
=
(
const
unsigned
char
*
)
data
;
printf
(
" = ["
);
for
(
i
=
0
;
i
<
len
;
i
++
)
printf
(
"%02x%s"
,
*
p
++
,
i
<
len
-
1
?
" "
:
""
);
printf
(
"]"
);
}
}
void
NORETURN
util_version
(
void
)
{
printf
(
"Version: %s
\n
"
,
DTC_VERSION
);
exit
(
0
);
}
void
NORETURN
util_usage
(
const
char
*
errmsg
,
const
char
*
synopsis
,
const
char
*
short_opts
,
struct
option
const
long_opts
[],
const
char
*
const
opts_help
[])
{
FILE
*
fp
=
errmsg
?
stderr
:
stdout
;
const
char
a_arg
[]
=
"<arg>"
;
size_t
a_arg_len
=
strlen
(
a_arg
)
+
1
;
size_t
i
;
int
optlen
;
fprintf
(
fp
,
"Usage: %s
\n
"
"
\n
"
"Options: -[%s]
\n
"
,
synopsis
,
short_opts
);
/* prescan the --long opt length to auto-align */
optlen
=
0
;
for
(
i
=
0
;
long_opts
[
i
].
name
;
++
i
)
{
/* +1 is for space between --opt and help text */
int
l
=
strlen
(
long_opts
[
i
].
name
)
+
1
;
if
(
long_opts
[
i
].
has_arg
==
a_argument
)
l
+=
a_arg_len
;
if
(
optlen
<
l
)
optlen
=
l
;
}
for
(
i
=
0
;
long_opts
[
i
].
name
;
++
i
)
{
/* helps when adding new applets or options */
assert
(
opts_help
[
i
]
!=
NULL
);
/* first output the short flag if it has one */
if
(
long_opts
[
i
].
val
>
'~'
)
fprintf
(
fp
,
" "
);
else
fprintf
(
fp
,
" -%c, "
,
long_opts
[
i
].
val
);
/* then the long flag */
if
(
long_opts
[
i
].
has_arg
==
no_argument
)
fprintf
(
fp
,
"--%-*s"
,
optlen
,
long_opts
[
i
].
name
);
else
fprintf
(
fp
,
"--%s %s%*s"
,
long_opts
[
i
].
name
,
a_arg
,
(
int
)(
optlen
-
strlen
(
long_opts
[
i
].
name
)
-
a_arg_len
),
""
);
/* finally the help text */
fprintf
(
fp
,
"%s
\n
"
,
opts_help
[
i
]);
}
if
(
errmsg
)
{
fprintf
(
fp
,
"
\n
Error: %s
\n
"
,
errmsg
);
exit
(
EXIT_FAILURE
);
}
else
exit
(
EXIT_SUCCESS
);
}
u-boot-tree/scripts/dtc/util.h
0 → 100644
View file @
7496de94
#ifndef UTIL_H
#define UTIL_H
#include <stdarg.h>
#include <stdbool.h>
#include <getopt.h>
/*
* Copyright 2011 The Chromium Authors, All Rights Reserved.
* Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
*
* This program 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 program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#ifdef __GNUC__
#define PRINTF(i, j) __attribute__((format (printf, i, j)))
#define NORETURN __attribute__((noreturn))
#else
#define PRINTF(i, j)
#define NORETURN
#endif
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define stringify(s) stringify_(s)
#define stringify_(s) #s
static
inline
void
NORETURN
PRINTF
(
1
,
2
)
die
(
const
char
*
str
,
...)
{
va_list
ap
;
va_start
(
ap
,
str
);
fprintf
(
stderr
,
"FATAL ERROR: "
);
vfprintf
(
stderr
,
str
,
ap
);
va_end
(
ap
);
exit
(
1
);
}
static
inline
void
*
xmalloc
(
size_t
len
)
{
void
*
new
=
malloc
(
len
);
if
(
!
new
)
die
(
"malloc() failed
\n
"
);
return
new
;
}
static
inline
void
*
xrealloc
(
void
*
p
,
size_t
len
)
{
void
*
new
=
realloc
(
p
,
len
);
if
(
!
new
)
die
(
"realloc() failed (len=%zd)
\n
"
,
len
);
return
new
;
}
extern
char
*
xstrdup
(
const
char
*
s
);
extern
int
PRINTF
(
2
,
3
)
xasprintf
(
char
**
strp
,
const
char
*
fmt
,
...);
extern
char
*
join_path
(
const
char
*
path
,
const
char
*
name
);
/**
* Check a property of a given length to see if it is all printable and
* has a valid terminator. The property can contain either a single string,
* or multiple strings each of non-zero length.
*
* @param data The string to check
* @param len The string length including terminator
* @return 1 if a valid printable string, 0 if not
*/
bool
util_is_printable_string
(
const
void
*
data
,
int
len
);
/*
* Parse an escaped character starting at index i in string s. The resulting
* character will be returned and the index i will be updated to point at the
* character directly after the end of the encoding, this may be the '\0'
* terminator of the string.
*/
char
get_escape_char
(
const
char
*
s
,
int
*
i
);
/**
* Read a device tree file into a buffer. This will report any errors on
* stderr.
*
* @param filename The filename to read, or - for stdin
* @return Pointer to allocated buffer containing fdt, or NULL on error
*/
char
*
utilfdt_read
(
const
char
*
filename
);
/**
* Like utilfdt_read(), but also passes back the size of the file read.
*
* @param len If non-NULL, the amount of data we managed to read
*/
char
*
utilfdt_read_len
(
const
char
*
filename
,
off_t
*
len
);
/**
* Read a device tree file into a buffer. Does not report errors, but only
* returns them. The value returned can be passed to strerror() to obtain
* an error message for the user.
*
* @param filename The filename to read, or - for stdin
* @param buffp Returns pointer to buffer containing fdt
* @return 0 if ok, else an errno value representing the error
*/
int
utilfdt_read_err
(
const
char
*
filename
,
char
**
buffp
);
/**
* Like utilfdt_read_err(), but also passes back the size of the file read.
*
* @param len If non-NULL, the amount of data we managed to read
*/
int
utilfdt_read_err_len
(
const
char
*
filename
,
char
**
buffp
,
off_t
*
len
);
/**
* Write a device tree buffer to a file. This will report any errors on
* stderr.
*
* @param filename The filename to write, or - for stdout
* @param blob Poiner to buffer containing fdt
* @return 0 if ok, -1 on error
*/
int
utilfdt_write
(
const
char
*
filename
,
const
void
*
blob
);
/**
* Write a device tree buffer to a file. Does not report errors, but only
* returns them. The value returned can be passed to strerror() to obtain
* an error message for the user.
*
* @param filename The filename to write, or - for stdout
* @param blob Poiner to buffer containing fdt
* @return 0 if ok, else an errno value representing the error
*/
int
utilfdt_write_err
(
const
char
*
filename
,
const
void
*
blob
);
/**
* Decode a data type string. The purpose of this string
*
* The string consists of an optional character followed by the type:
* Modifier characters:
* hh or b 1 byte
* h 2 byte
* l 4 byte, default
*
* Type character:
* s string
* i signed integer
* u unsigned integer
* x hex
*
* TODO: Implement ll modifier (8 bytes)
* TODO: Implement o type (octal)
*
* @param fmt Format string to process
* @param type Returns type found(s/d/u/x), or 0 if none
* @param size Returns size found(1,2,4,8) or 4 if none
* @return 0 if ok, -1 on error (no type given, or other invalid format)
*/
int
utilfdt_decode_type
(
const
char
*
fmt
,
int
*
type
,
int
*
size
);
/*
* This is a usage message fragment for the -t option. It is the format
* supported by utilfdt_decode_type.
*/
#define USAGE_TYPE_MSG \
"<type>\ts=string, i=int, u=unsigned, x=hex\n" \
"\tOptional modifier prefix:\n" \
"\t\thh or b=byte, h=2 byte, l=4 byte (default)";
/**
* Print property data in a readable format to stdout
*
* Properties that look like strings will be printed as strings. Otherwise
* the data will be displayed either as cells (if len is a multiple of 4
* bytes) or bytes.
*
* If len is 0 then this function does nothing.
*
* @param data Pointers to property data
* @param len Length of property data
*/
void
utilfdt_print_data
(
const
char
*
data
,
int
len
);
/**
* Show source version and exit
*/
void
NORETURN
util_version
(
void
);
/**
* Show usage and exit
*
* This helps standardize the output of various utils. You most likely want
* to use the usage() helper below rather than call this.
*
* @param errmsg If non-NULL, an error message to display
* @param synopsis The initial example usage text (and possible examples)
* @param short_opts The string of short options
* @param long_opts The structure of long options
* @param opts_help An array of help strings (should align with long_opts)
*/
void
NORETURN
util_usage
(
const
char
*
errmsg
,
const
char
*
synopsis
,
const
char
*
short_opts
,
struct
option
const
long_opts
[],
const
char
*
const
opts_help
[]);
/**
* Show usage and exit
*
* If you name all your usage variables with usage_xxx, then you can call this
* help macro rather than expanding all arguments yourself.
*
* @param errmsg If non-NULL, an error message to display
*/
#define usage(errmsg) \
util_usage(errmsg, usage_synopsis, usage_short_opts, \
usage_long_opts, usage_opts_help)
/**
* Call getopt_long() with standard options
*
* Since all util code runs getopt in the same way, provide a helper.
*/
#define util_getopt_long() getopt_long(argc, argv, usage_short_opts, \
usage_long_opts, NULL)
/* Helper for aligning long_opts array */
#define a_argument required_argument
/* Helper for usage_short_opts string constant */
#define USAGE_COMMON_SHORT_OPTS "hV"
/* Helper for usage_long_opts option array */
#define USAGE_COMMON_LONG_OPTS \
{"help", no_argument, NULL, 'h'}, \
{"version", no_argument, NULL, 'V'}, \
{NULL, no_argument, NULL, 0x0}
/* Helper for usage_opts_help array */
#define USAGE_COMMON_OPTS_HELP \
"Print this help and exit", \
"Print version and exit", \
NULL
/* Helper for getopt case statements */
#define case_USAGE_COMMON_FLAGS \
case 'h': usage(NULL); \
case 'V': util_version(); \
case '?': usage("unknown option");
#endif
/* UTIL_H */
u-boot-tree/scripts/dtc/version_gen.h
0 → 100644
View file @
7496de94
#define DTC_VERSION "DTC 1.4.6-gaadd0b65"
u-boot-tree/tools/Makefile
View file @
7496de94
...
@@ -222,9 +222,8 @@ LICENSE-$(CONFIG_CMD_LICENSE) += $(LICENSE_H)
...
@@ -222,9 +222,8 @@ LICENSE-$(CONFIG_CMD_LICENSE) += $(LICENSE_H)
#
#
HOST_EXTRACFLAGS
+=
-include
$(srctree)
/include/compiler.h
\
HOST_EXTRACFLAGS
+=
-include
$(srctree)
/include/compiler.h
\
$
(
patsubst
-I
%,-idirafter%,
$
(
filter
-I
%,
$(UBOOTINCLUDE)
))
\
$
(
patsubst
-I
%,-idirafter%,
$
(
filter
-I
%,
$(UBOOTINCLUDE)
))
\
-I
$(srctree)
/
lib
/libfdt
\
-I
$(srctree)
/
scripts/dtc
/libfdt
\
-I
$(srctree)
/tools
\
-I
$(srctree)
/tools
\
-DCONFIG_SYS_TEXT_BASE
=
$(CONFIG_SYS_TEXT_BASE)
\
-DUSE_HOSTCC
\
-DUSE_HOSTCC
\
-D__KERNEL_STRICT_NAMES
\
-D__KERNEL_STRICT_NAMES
\
-D_GNU_SOURCE
-D_GNU_SOURCE
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment