filling in

git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@2 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
Ronald G. Minnich 2006-10-06 19:19:14 +00:00
commit a28296a6d2
28 changed files with 8336 additions and 0 deletions

339
COPYING Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

1354
Makefile Normal file

File diff suppressed because it is too large Load diff

6
util/dtc/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
*.o
*.d
*.tab.[ch]
lex.yy.c
dtc
ftdump

340
util/dtc/COPYING Normal file
View file

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,43 @@
@STRING{pub-IEEE = "IEEE Computer Society"}
@STRING{pub-IEEE:adr = "345 E. 47th St, New York, NY 10017, USA"}
@BOOK{IEEE1275,
key = "IEEE1275",
title = "{IEEE} {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware: {C}ore {R}equirements and {P}ractices",
publisher = pub-IEEE,
address = pub-IEEE:adr,
series = "IEEE Std 1275-1994",
year = 1994,
}
@BOOK{IEEE1275-pci,
key = "IEEE1275-pci",
title = "{PCI} {B}us {B}inding to: {IEEE} {S}td 1275-1994 {S}tandard for {B}oot ({I}nitialization {C}onfiguration) {F}irmware",
publisher = pub-IEEE,
address = pub-IEEE:adr,
note = "Revision 2.1",
year = 1998,
}
@MISC{noof1,
author = "Benjamin Herrenschmidt",
title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
month = may,
year = 2005,
note = "v0.1, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-May/004073.html}",
}
@MISC{noof5,
author = "Benjamin Herrenschmidt",
title = "Booting the {L}inux/ppc kernel without {O}pen {F}irmware",
month = nov,
year = 2005,
note = "v0.5, \url{http://ozlabs.org/pipermail/linuxppc64-dev/2005-December/006994.html}",
}
@MISC{dtcgit,
author = "David Gibson et al.",
title = "\dtc{}",
howpublished = "git tree",
note = "\url{http://ozlabs.org/~dgibson/dtc/dtc.git}",
}

View file

@ -0,0 +1,597 @@
\documentclass[a4paper,twocolumn]{article}
\usepackage{abstract}
\usepackage{xspace}
\usepackage{amssymb}
\usepackage{latexsym}
\usepackage{tabularx}
\usepackage[T1]{fontenc}
\usepackage{calc}
\usepackage{listings}
\usepackage{color}
\usepackage{url}
\title{Device trees everywhere}
\author{David Gibson \texttt{<{dwg}{@}{au1.ibm.com}>}\\
Benjamin Herrenschmidt \texttt{<{benh}{@}{kernel.crashing.org}>}\\
\emph{OzLabs, IBM Linux Technology Center}}
\newcommand{\R}{\textsuperscript{\textregistered}\xspace}
\newcommand{\tm}{\textsuperscript{\texttrademark}\xspace}
\newcommand{\tge}{$\geqslant$}
%\newcommand{\ditto}{\textquotedbl\xspace}
\newcommand{\fixme}[1]{$\bigstar$\emph{\textbf{\large #1}}$\bigstar$\xspace}
\newcommand{\ppc}{\mbox{PowerPC}\xspace}
\newcommand{\of}{Open Firmware\xspace}
\newcommand{\benh}{Ben Herrenschmidt\xspace}
\newcommand{\kexec}{\texttt{kexec()}\xspace}
\newcommand{\dtbeginnode}{\texttt{OF\_DT\_BEGIN\_NODE\xspace}}
\newcommand{\dtendnode}{\texttt{OF\_DT\_END\_NODE\xspace}}
\newcommand{\dtprop}{\texttt{OF\_DT\_PROP\xspace}}
\newcommand{\dtend}{\texttt{OF\_DT\_END\xspace}}
\newcommand{\dtc}{\texttt{dtc}\xspace}
\newcommand{\phandle}{\texttt{linux,phandle}\xspace}
\begin{document}
\maketitle
\begin{abstract}
We present a method for booting a \ppc{}\R Linux\R kernel on an
embedded machine. To do this, we supply the kernel with a compact
flattened-tree representation of the system's hardware based on the
device tree supplied by Open Firmware on IBM\R servers and Apple\R
Power Macintosh\R machines.
The ``blob'' representing the device tree can be created using \dtc
--- the Device Tree Compiler --- that turns a simple text
representation of the tree into the compact representation used by
the kernel. The compiler can produce either a binary ``blob'' or an
assembler file ready to be built into a firmware or bootwrapper
image.
This flattened-tree approach is now the only supported method of
booting a \texttt{ppc64} kernel without Open Firmware, and we plan
to make it the only supported method for all \texttt{powerpc}
kernels in the future.
\end{abstract}
\section{Introduction}
\subsection{OF and the device tree}
Historically, ``everyday'' \ppc machines have booted with the help of
\of (OF), a firmware environment defined by IEEE1275 \cite{IEEE1275}.
Among other boot-time services, OF maintains a device tree that
describes all of the system's hardware devices and how they're
connected. During boot, before taking control of memory management,
the Linux kernel uses OF calls to scan the device tree and transfer it
to an internal representation that is used at run time to look up
various device information.
The device tree consists of nodes representing devices or
buses\footnote{Well, mostly. There are a few special exceptions.}.
Each node contains \emph{properties}, name--value pairs that give
information about the device. The values are arbitrary byte strings,
and for some properties, they contain tables or other structured
information.
\subsection{The bad old days}
Embedded systems, by contrast, usually have a minimal firmware that
might supply a few vital system parameters (size of RAM and the like),
but nothing as detailed or complete as the OF device tree. This has
meant that the various 32-bit \ppc embedded ports have required a
variety of hacks spread across the kernel to deal with the lack of
device tree. These vary from specialised boot wrappers to parse
parameters (which are at least reasonably localised) to
CONFIG-dependent hacks in drivers to override normal probe logic with
hardcoded addresses for a particular board. As well as being ugly of
itself, such CONFIG-dependent hacks make it hard to build a single
kernel image that supports multiple embedded machines.
Until relatively recently, the only 64-bit \ppc machines without OF
were legacy (pre-POWER5\R) iSeries\R machines. iSeries machines often
only have virtual IO devices, which makes it quite simple to work
around the lack of a device tree. Even so, the lack means the iSeries
boot sequence must be quite different from the pSeries or Macintosh,
which is not ideal.
The device tree also presents a problem for implementing \kexec. When
the kernel boots, it takes over full control of the system from OF,
even re-using OF's memory. So, when \kexec comes to boot another
kernel, OF is no longer around for the second kernel to query.
\section{The Flattened Tree}
In May 2005 \benh implemented a new approach to handling the device
tree that addresses all these problems. When booting on OF systems,
the first thing the kernel runs is a small piece of code in
\texttt{prom\_init.c}, which executes in the context of OF. This code
walks the device tree using OF calls, and transcribes it into a
compact, flattened format. The resulting device tree ``blob'' is then
passed to the kernel proper, which eventually unflattens the tree into
its runtime form. This blob is the only data communicated between the
\texttt{prom\_init.c} bootstrap and the rest of the kernel.
When OF isn't available, either because the machine doesn't have it at
all or because \kexec has been used, the kernel instead starts
directly from the entry point taking a flattened device tree. The
device tree blob must be passed in from outside, rather than generated
by part of the kernel from OF. For \kexec, the userland
\texttt{kexec} tools build the blob from the runtime device tree
before invoking the new kernel. For embedded systems the blob can
come either from the embedded bootloader, or from a specialised
version of the \texttt{zImage} wrapper for the system in question.
\subsection{Properties of the flattened tree}
The flattened tree format should be easy to handle, both for the
kernel that parses it and the bootloader that generates it. In
particular, the following properties are desirable:
\begin{itemize}
\item \emph{relocatable}: the bootloader or kernel should be able to
move the blob around as a whole, without needing to parse or adjust
its internals. In practice that means we must not use pointers
within the blob.
\item \emph{insert and delete}: sometimes the bootloader might want to
make tweaks to the flattened tree, such as deleting or inserting a
node (or whole subtree). It should be possible to do this without
having to effectively regenerate the whole flattened tree. In
practice this means limiting the use of internal offsets in the blob
that need recalculation if a section is inserted or removed with
\texttt{memmove()}.
\item \emph{compact}: embedded systems are frequently short of
resources, particularly RAM and flash memory space. Thus, the tree
representation should be kept as small as conveniently possible.
\end{itemize}
\subsection{Format of the device tree blob}
\label{sec:format}
\begin{figure}[htb!]
\centering
\footnotesize
\begin{tabular}{r|c|l}
\multicolumn{1}{r}{\textbf{Offset}}& \multicolumn{1}{c}{\textbf{Contents}} \\\cline{2-2}
\texttt{0x00} & \texttt{0xd00dfeed} & magic number \\\cline{2-2}
\texttt{0x04} & \emph{totalsize} \\\cline{2-2}
\texttt{0x08} & \emph{off\_struct} & \\\cline{2-2}
\texttt{0x0C} & \emph{off\_strs} & \\\cline{2-2}
\texttt{0x10} & \emph{off\_rsvmap} & \\\cline{2-2}
\texttt{0x14} & \emph{version} \\\cline{2-2}
\texttt{0x18} & \emph{last\_comp\_ver} & \\\cline{2-2}
\texttt{0x1C} & \emph{boot\_cpu\_id} & \tge v2 only\\\cline{2-2}
\texttt{0x20} & \emph{size\_strs} & \tge v3 only\\\cline{2-2}
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
\emph{off\_rsvmap} & \emph{address0} & memory reserve \\
+ \texttt{0x04} & ...& table \\\cline{2-2}
+ \texttt{0x08} & \emph{len0} & \\
+ \texttt{0x0C} & ...& \\\cline{2-2}
\vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
& \texttt{0x00000000}- & end marker\\
& \texttt{00000000} & \\\cline{2-2}
& \texttt{0x00000000}- & \\
& \texttt{00000000} & \\\cline{2-2}
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
\emph{off\_strs} & \texttt{'n' 'a' 'm' 'e'} & strings block \\
+ \texttt{0x04} & \texttt{~0~ 'm' 'o' 'd'} & \\
+ \texttt{0x08} & \texttt{'e' 'l' ~0~ \makebox[\widthof{~~~}]{\textrm{...}}} & \\
\vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
\multicolumn{1}{r}{+ \emph{size\_strs}} \\
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
\emph{off\_struct} & \dtbeginnode & structure block \\\cline{2-2}
+ \texttt{0x04} & \texttt{'/' ~0~ ~0~ ~0~} & root node\\\cline{2-2}
+ \texttt{0x08} & \dtprop & \\\cline{2-2}
+ \texttt{0x0C} & \texttt{0x00000005} & ``\texttt{model}''\\\cline{2-2}
+ \texttt{0x10} & \texttt{0x00000008} & \\\cline{2-2}
+ \texttt{0x14} & \texttt{'M' 'y' 'B' 'o'} & \\
+ \texttt{0x18} & \texttt{'a' 'r' 'd' ~0~} & \\\cline{2-2}
\vdots & \multicolumn{1}{c|}{\vdots} & \\\cline{2-2}
& \texttt{\dtendnode} \\\cline{2-2}
& \texttt{\dtend} \\\cline{2-2}
\multicolumn{1}{r}{\vdots} & \multicolumn{1}{c}{\vdots} & \\\cline{2-2}
\multicolumn{1}{r}{\emph{totalsize}} \\
\end{tabular}
\caption{Device tree blob layout}
\label{fig:blob-layout}
\end{figure}
The format for the blob we devised, was first described on the
\texttt{linuxppc64-dev} mailing list in \cite{noof1}. The format has
since evolved through various revisions, and the current version is
included as part of the \dtc (see \S\ref{sec:dtc}) git tree,
\cite{dtcgit}.
Figure \ref{fig:blob-layout} shows the layout of the blob of data
containing the device tree. It has three sections of variable size:
the \emph{memory reserve table}, the \emph{structure block} and the
\emph{strings block}. A small header gives the blob's size and
version and the locations of the three sections, plus a handful of
vital parameters used during early boot.
The memory reserve map section gives a list of regions of memory that
the kernel must not use\footnote{Usually such ranges contain some data
structure initialised by the firmware that must be preserved by the
kernel.}. The list is represented as a simple array of (address,
size) pairs of 64 bit values, terminated by a zero size entry. The
strings block is similarly simple, consisting of a number of
null-terminated strings appended together, which are referenced from
the structure block as described below.
The structure block contains the device tree proper. Each node is
introduced with a 32-bit \dtbeginnode tag, followed by the node's name
as a null-terminated string, padded to a 32-bit boundary. Then
follows all of the properties of the node, each introduced with a
\dtprop tag, then all of the node's subnodes, each introduced with
their own \dtbeginnode tag. The node ends with an \dtendnode tag, and
after the \dtendnode for the root node is an \dtend tag, indicating
the end of the whole tree\footnote{This is redundant, but included for
ease of parsing.}. The structure block starts with the \dtbeginnode
introducing the description of the root node (named \texttt{/}).
Each property, after the \dtprop, has a 32-bit value giving an offset
from the beginning of the strings block at which the property name is
stored. Because it's common for many nodes to have properties with
the same name, this approach can substantially reduce the total size
of the blob. The name offset is followed by the length of the
property value (as a 32-bit value) and then the data itself padded to
a 32-bit boundary.
\subsection{Contents of the tree}
\label{sec:treecontents}
Having seen how to represent the device tree structure as a flattened
blob, what actually goes into the tree? The short answer is ``the
same as an OF tree''. On OF systems, the flattened tree is
transcribed directly from the OF device tree, so for simplicity we
also use OF conventions for the tree on other systems.
In many cases a flat tree can be simpler than a typical OF provided
device tree. The flattened tree need only provide those nodes and
properties that the kernel actually requires; the flattened tree
generally need not include devices that the kernel can probe itself.
For example, an OF device tree would normally include nodes for each
PCI device on the system. A flattened tree need only include nodes
for the PCI host bridges; the kernel will scan the buses thus
described to find the subsidiary devices. The device tree can include
nodes for devices where the kernel needs extra information, though:
for example, for ISA devices on a subsidiary PCI/ISA bridge, or for
devices with unusual interrupt routing.
Where they exist, we follow the IEEE1275 bindings that specify how to
describe various buses in the device tree (for example,
\cite{IEEE1275-pci} describe how to represent PCI devices). The
standard has not been updated for a long time, however, and lacks
bindings for many modern buses and devices. In particular, embedded
specific devices such as the various System-on-Chip buses are not
covered. We intend to create new bindings for such buses, in keeping
with the general conventions of IEEE1275 (a simple such binding for a
System-on-Chip bus was included in \cite{noof5} a revision of
\cite{noof1}).
One complication arises for representing ``phandles'' in the flattened
tree. In OF, each node in the tree has an associated phandle, a
32-bit integer that uniquely identifies the node\footnote{In practice
usually implemented as a pointer or offset within OF memory.}. This
handle is used by the various OF calls to query and traverse the tree.
Sometimes phandles are also used within the tree to refer to other
nodes in the tree. For example, devices that produce interrupts
generally have an \texttt{interrupt-parent} property giving the
phandle of the interrupt controller that handles interrupts from this
device. Parsing these and other interrupt related properties allows
the kernel to build a complete representation of the system's
interrupt tree, which can be quite different from the tree of bus
connections.
In the flattened tree, a node's phandle is represented by a special
\phandle property. When the kernel generates a flattened tree from
OF, it adds a \phandle property to each node, containing the phandle
retrieved from OF. When the tree is generated without OF, however,
only nodes that are actually referred to by phandle need to have this
property.
Another complication arises because nodes in an OF tree have two
names. First they have the ``unit name'', which is how the node is
referred to in an OF path. The unit name generally consists of a
device type followed by an \texttt{@} followed by a \emph{unit
address}. For example \texttt{/memory@0} is the full path of a memory
node at address 0, \texttt{/ht@0,f2000000/pci@1} is the path of a PCI
bus node, which is under a HyperTransport\tm bus node. The form of
the unit address is bus dependent, but is generally derived from the
node's \texttt{reg} property. In addition, nodes have a property,
\texttt{name}, whose value is usually equal to the first path of the
unit name. For example, the nodes in the previous example would have
\texttt{name} properties equal to \texttt{memory} and \texttt{pci},
respectively. To save space in the blob, the current version of the
flattened tree format only requires the unit names to be present.
When the kernel unflattens the tree, it automatically generates a
\texttt{name} property from the node's path name.
\section{The Device Tree Compiler}
\label{sec:dtc}
\begin{figure}[htb!]
\centering
\begin{lstlisting}[frame=single,basicstyle=\footnotesize\ttfamily,
tabsize=3,numbers=left,xleftmargin=2em]
/memreserve/ 0x20000000-0x21FFFFFF;
/ {
model = "MyBoard";
compatible = "MyBoardFamily";
#address-cells = <2>;
#size-cells = <2>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
PowerPC,970@0 {
device_type = "cpu";
reg = <0>;
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
linux,boot-cpu;
i-cache-size = <10000>;
d-cache-size = <8000>;
};
};
memory@0 {
device_type = "memory";
memreg: reg = <00000000 00000000
00000000 20000000>;
};
mpic@0x3fffdd08400 {
/* Interrupt controller */
/* ... */
};
pci@40000000000000 {
/* PCI host bridge */
/* ... */
};
chosen {
bootargs = "root=/dev/sda2";
linux,platform = <00000600>;
interrupt-controller =
< &/mpic@0x3fffdd08400 >;
};
};
\end{lstlisting}
\caption{Example \dtc source}
\label{fig:dts}
\end{figure}
As we've seen, the flattened device tree format provides a convenient
way of communicating device tree information to the kernel. It's
simple for the kernel to parse, and simple for bootloaders to
manipulate. On OF systems, it's easy to generate the flattened tree
by walking the OF maintained tree. However, for embedded systems, the
flattened tree must be generated from scratch.
Embedded bootloaders are generally built for a particular board. So,
it's usually possible to build the device tree blob at compile time
and include it in the bootloader image. For minor revisions of the
board, the bootloader can contain code to make the necessary tweaks to
the tree before passing it to the booted kernel.
The device trees for embedded boards are usually quite simple, and
it's possible to hand construct the necessary blob by hand, but doing
so is tedious. The ``device tree compiler'', \dtc{}\footnote{\dtc can
be obtained from \cite{dtcgit}.}, is designed to make creating device
tree blobs easier by converting a text representation of the tree
into the necessary blob.
\subsection{Input and output formats}
As well as the normal mode of compiling a device tree blob from text
source, \dtc can convert a device tree between a number of
representations. It can take its input in one of three different
formats:
\begin{itemize}
\item source, the normal case. The device tree is described in a text
form, described in \S\ref{sec:dts}.
\item blob (\texttt{dtb}), the flattened tree format described in
\S\ref{sec:format}. This mode is useful for checking a pre-existing
device tree blob.
\item filesystem (\texttt{fs}), input is a directory tree in the
layout of \texttt{/proc/device-tree} (roughly, a directory for each
node in the device tree, a file for each property). This is useful
for building a blob for the device tree in use by the currently
running kernel.
\end{itemize}
In addition, \dtc can output the tree in one of three different
formats:
\begin{itemize}
\item blob (\texttt{dtb}), as in \S\ref{sec:format}. The most
straightforward use of \dtc is to compile from ``source'' to
``blob'' format.
\item source (\texttt{dts}), as in \S\ref{sec:dts}. If used with blob
input, this allows \dtc to act as a ``decompiler''.
\item assembler source (\texttt{asm}). \dtc can produce an assembler
file, which will assemble into a \texttt{.o} file containing the
device tree blob, with symbols giving the beginning of the blob and
its various subsections. This can then be linked directly into a
bootloader or firmware image.
\end{itemize}
For maximum applicability, \dtc can both read and write any of the
existing revisions of the blob format. When reading, \dtc takes the
version from the blob header, and when writing it takes a command line
option specifying the desired version. It automatically makes any
necessary adjustments to the tree that are necessary for the specified
version. For example, formats before 0x10 require each node to have
an explicit \texttt{name} property. When \dtc creates such a blob, it
will automatically generate \texttt{name} properties from the unit
names.
\subsection{Source format}
\label{sec:dts}
The ``source'' format for \dtc is a text description of the device
tree in a vaguely C-like form. Figure \ref{fig:dts} shows an
example. The file starts with \texttt{/memreserve/} directives, which
gives address ranges to add to the output blob's memory reserve table,
then the device tree proper is described.
Nodes of the tree are introduced with the node name, followed by a
\texttt{\{} ... \texttt{\};} block containing the node's properties
and subnodes. Properties are given as just {\emph{name} \texttt{=}
\emph{value}\texttt{;}}. The property values can be given in any
of three forms:
\begin{itemize}
\item \emph{string} (for example, \texttt{"MyBoard"}). The property
value is the given string, including terminating NULL. C-style
escapes (\verb+\t+, \verb+\n+, \verb+\0+ and so forth) are allowed.
\item \emph{cells} (for example, \texttt{<0 8000 f0000000>}). The
property value is made up of a list of 32-bit ``cells'', each given
as a hex value.
\item \emph{bytestring} (for example, \texttt{[1234abcdef]}). The
property value is given as a hex bytestring.
\end{itemize}
Cell properties can also contain \emph{references}. Instead of a hex
number, the source can give an ampersand (\texttt{\&}) followed by the
full path to some node in the tree. For example, in Figure
\ref{fig:dts}, the \texttt{/chosen} node has an
\texttt{interrupt-controller} property referring to the interrupt
controller described by the node \texttt{/mpic@0x3fffdd08400}. In the
output tree, the value of the referenced node's phandle is included in
the property. If that node doesn't have an explicit phandle property,
\dtc will automatically create a unique phandle for it. This approach
makes it easy to create interrupt trees without having to explicitly
assign and remember phandles for the various interrupt controller
nodes.
The \dtc source can also include ``labels'', which are placed on a
particular node or property. For example, Figure \ref{fig:dts} has a
label ``\texttt{memreg}'' on the \texttt{reg} property of the node
\texttt{/memory@0}. When using assembler output, corresponding labels
in the output are generated, which will assemble into symbols
addressing the part of the blob with the node or property in question.
This is useful for the common case where an embedded board has an
essentially fixed device tree with a few variable properties, such as
the size of memory. The bootloader for such a board can have a device
tree linked in, including a symbol referring to the right place in the
blob to update the parameter with the correct value determined at
runtime.
\subsection{Tree checking}
Between reading in the device tree and writing it out in the new
format, \dtc performs a number of checks on the tree:
\begin{itemize}
\item \emph{syntactic structure}: \dtc checks that node and property
names contain only allowed characters and meet length restrictions.
It checks that a node does not have multiple properties or subnodes
with the same name.
\item \emph{semantic structure}: In some cases, \dtc checks that
properties whose contents are defined by convention have appropriate
values. For example, it checks that \texttt{reg} properties have a
length that makes sense given the address forms specified by the
\texttt{\#address-cells} and \texttt{\#size-cells} properties. It
checks that properties such as \texttt{interrupt-parent} contain a
valid phandle.
\item \emph{Linux requirements}: \dtc checks that the device tree
contains those nodes and properties that are required by the Linux
kernel to boot correctly.
\end{itemize}
These checks are useful to catch simple problems with the device tree,
rather than having to debug the results on an embedded kernel. With
the blob input mode, it can also be used for diagnosing problems with
an existing blob.
\section{Future Work}
\subsection{Board ports}
The flattened device tree has always been the only supported way to
boot a \texttt{ppc64} kernel on an embedded system. With the merge of
\texttt{ppc32} and \texttt{ppc64} code it has also become the only
supported way to boot any merged \texttt{powerpc} kernel, 32-bit or
64-bit. In fact, the old \texttt{ppc} architecture exists mainly just
to support the old ppc32 embedded ports that have not been migrated
to the flattened device tree approach. We plan to remove the
\texttt{ppc} architecture eventually, which will mean porting all the
various embedded boards to use the flattened device tree.
\subsection{\dtc features}
While it is already quite usable, there are a number of extra features
that \dtc could include to make creating device trees more convenient:
\begin{itemize}
\item \emph{better tree checking}: Although \dtc already performs a
number of checks on the device tree, they are rather haphazard. In
many cases \dtc will give up after detecting a minor error early and
won't pick up more interesting errors later on. There is a
\texttt{-f} parameter that forces \dtc to generate an output tree
even if there are errors. At present, this needs to be used more
often than one might hope, because \dtc is bad at deciding which
errors should really be fatal, and which rate mere warnings.
\item \emph{binary include}: Occasionally, it is useful for the device
tree to incorporate as a property a block of binary data for some
board-specific purpose. For example, many of Apple's device trees
incorporate bytecode drivers for certain platform devices. \dtc's
source format ought to allow this by letting a property's value be
read directly from a binary file.
\item \emph{macros}: it might be useful for \dtc to implement some
sort of macros so that a tree containing a number of similar devices
(for example, multiple identical ethernet controllers or PCI buses)
can be written more quickly. At present, this can be accomplished
in part by running the source file through CPP before compiling with
\dtc. It's not clear whether ``native'' support for macros would be
more useful.
\end{itemize}
\bibliographystyle{amsplain}
\bibliography{dtc-paper}
\section*{About the authors}
David Gibson has been a member of the IBM Linux Technology Center,
working from Canberra, Australia, since 2001. Recently he has worked
on Linux hugepage support and performance counter support for ppc64,
as well as the device tree compiler. In the past, he has worked on
bringup for various ppc and ppc64 embedded systems, the orinoco
wireless driver, ramfs, and a userspace checkpointing system
(\texttt{esky}).
Benjamin Herrenschmidt was a MacOS developer for about 10 years, but
ultimately saw the light and installed Linux on his Apple PowerPC
machine. After writing a bootloader, BootX, for it in 1998, he
started contributing to the PowerPC Linux port in various areas,
mostly around the support for Apple machines. He became official
PowerMac maintainer in 2001. In 2003, he joined the IBM Linux
Technology Center in Canberra, Australia, where he ported the 64 bit
PowerPC kernel to Apple G5 machines and the Maple embedded board,
among others things. He's a member of the ppc64 development ``team''
and one of his current goals is to make the integration of embedded
platforms smoother and more maintainable than in the 32-bit PowerPC
kernel.
\section*{Legal Statement}
This work represents the view of the author and does not necessarily
represent the view of IBM.
IBM, \ppc, \ppc Architecture, POWER5, pSeries and iSeries are
trademarks or registered trademarks of International Business Machines
Corporation in the United States and/or other countries.
Apple and Power Macintosh are a registered trademarks of Apple
Computer Inc. in the United States, other countries, or both.
Linux is a registered trademark of Linus Torvalds.
Other company, product, and service names may be trademarks or service
marks of others.
\end{document}

42
util/dtc/Makefile Normal file
View file

@ -0,0 +1,42 @@
TARGETS = dtc ftdump
CFLAGS = -Wall -g
BISON = bison
DTC_OBJS = dtc.o livetree.o flattree.o data.o treesource.o fstree.o \
dtc-parser.tab.o lex.yy.o
OBJS = $(DTC_OBJS) libdt.o ftdump.o
DEPFILES = $(DTC_OBJS:.o=.d)
all: $(TARGETS)
dtc: $(DTC_OBJS)
$(LINK.c) -o $@ $^
ftdump: ftdump.o
$(LINK.c) -o $@ $^
dtc-parser.tab.c dtc-parser.tab.h dtc-parser.output: dtc-parser.y
$(BISON) -d $<
lex.yy.c: dtc-lexer.l
$(LEX) $<
lex.yy.o: lex.yy.c dtc-parser.tab.h
check: all
cd tests && $(MAKE) check
clean:
rm -f *~ *.o a.out core $(TARGETS)
rm -f *.tab.[ch] lex.yy.c
rm -f *.i *.output vgcore.*
rm -f *.d
cd tests && $(MAKE) clean
%.d: %.c
$(CC) -MM -MG -MT "$*.o $@" $< > $@
-include $(DEPFILES)

14
util/dtc/TODO Normal file
View file

@ -0,0 +1,14 @@
- Bugfixes:
* Proper handling of boot cpu information
- Error handling / reporting
* Better categorization of errors into severity levels
* Don't stop checking for later errors because of earlier ones
whenever possible
- Generate mem reserve map
* linux,reserve-map property
* generating reserve entry for device tree itself
* generating reserve entries from tce, rtas etc. properties
- Testsuite
- Actually number releases, all that kind of jazz

38
util/dtc/comment-test.dts Normal file
View file

@ -0,0 +1,38 @@
/* regexps for lexing comments are.. tricky. Check if we've actually
* got it right */
/ {
// line comment
prop1;
/* comment */
prop2;
/* multiline
notaprop1;
comment */
prop3;
/**/
prop4;
/***/
prop5;
/****/
prop6;
/* another
* multiline
* comment */
prop7;
/* yet
* another
* multline
* comment
*/
prop8;
/** try this */
prop9;
/* and this **/
prop10;
child /* finally */ {
};
};
/* final comment */

276
util/dtc/data.c Normal file
View file

@ -0,0 +1,276 @@
/*
* (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 fixup_free(struct fixup *f)
{
free(f->ref);
free(f);
}
void data_free(struct data d)
{
struct fixup *f;
f = d.refs;
while (f) {
struct fixup *nf;
nf = f->next;
fixup_free(f);
f = nf;
}
assert(!d.val || d.asize);
if (d.val)
free(d.val);
}
struct data data_grow_for(struct data d, int xlen)
{
struct data nd;
int newsize;
/* we must start with an allocated datum */
assert(!d.val || d.asize);
if (xlen == 0)
return d;
newsize = xlen;
while ((d.len + xlen) > newsize)
newsize *= 2;
nd.asize = newsize;
nd.val = xrealloc(d.val, newsize);
nd.len = d.len;
nd.refs = d.refs;
assert(nd.asize >= (d.len + xlen));
return nd;
}
struct data data_copy_mem(char *mem, int len)
{
struct data d;
d = data_grow_for(empty_data, len);
d.len = len;
memcpy(d.val, mem, len);
return d;
}
static char get_oct_char(char *s, int *i)
{
char x[4];
char *endx;
long val;
x[3] = '\0';
x[0] = s[(*i)];
if (x[0]) {
x[1] = s[(*i)+1];
if (x[1])
x[2] = s[(*i)+2];
}
val = strtol(x, &endx, 8);
if ((endx - x) == 0)
fprintf(stderr, "Empty \\nnn escape\n");
(*i) += endx - x;
return val;
}
static char get_hex_char(char *s, int *i)
{
char x[3];
char *endx;
long val;
x[2] = '\0';
x[0] = s[(*i)];
if (x[0])
x[1] = s[(*i)+1];
val = strtol(x, &endx, 16);
if ((endx - x) == 0)
fprintf(stderr, "Empty \\x escape\n");
(*i) += endx - x;
return val;
}
struct data data_copy_escape_string(char *s, int len)
{
int i = 0;
struct data d;
char *q;
d = data_grow_for(empty_data, strlen(s)+1);
q = d.val;
while (i < len) {
char c = s[i++];
if (c != '\\') {
q[d.len++] = c;
continue;
}
c = s[i++];
assert(c);
switch (c) {
case 't':
q[d.len++] = '\t';
break;
case 'n':
q[d.len++] = '\n';
break;
case 'r':
q[d.len++] = '\r';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
i--; /* need to re-read the first digit as
* part of the octal value */
q[d.len++] = get_oct_char(s, &i);
break;
case 'x':
q[d.len++] = get_hex_char(s, &i);
break;
default:
q[d.len++] = c;
}
}
q[d.len++] = '\0';
return d;
}
struct data data_copy_file(FILE *f, size_t len)
{
struct data d;
d = data_grow_for(empty_data, len);
d.len = len;
fread(d.val, len, 1, f);
return d;
}
struct data data_append_data(struct data d, 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_append_cell(struct data d, cell_t word)
{
cell_t beword = cpu_to_be32(word);
return data_append_data(d, &beword, sizeof(beword));
}
struct data data_append_re(struct data d, struct reserve_entry *re)
{
struct reserve_entry bere;
bere.address = cpu_to_be64(re->address);
bere.size = cpu_to_be64(re->size);
return data_append_data(d, &bere, sizeof(bere));
}
struct data data_append_addr(struct data d, u64 addr)
{
u64 beaddr = cpu_to_be64(addr);
return data_append_data(d, &beaddr, sizeof(beaddr));
}
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_fixup(struct data d, char *ref)
{
struct fixup *f;
struct data nd;
f = xmalloc(sizeof(*f));
f->offset = d.len;
f->ref = ref;
f->next = d.refs;
nd = d;
nd.refs = f;
return nd;
}
int data_is_one_string(struct data d)
{
int i;
int len = d.len;
if (len == 0)
return 0;
for (i = 0; i < len-1; i++)
if (d.val[i] == '\0')
return 0;
if (d.val[len-1] != '\0')
return 0;
return 1;
}

180
util/dtc/dtc-lexer.l Normal file
View file

@ -0,0 +1,180 @@
/*
* (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 yylineno
%x CELLDATA
%x BYTESTRING
%x MEMRESERVE
PROPCHAR [a-zA-Z0-9,._+*#?-]
UNITCHAR [0-9a-f,]
WS [ \t\n]
REFCHAR ({PROPCHAR}|{UNITCHAR}|[/@])
%{
#include "dtc.h"
#include "dtc-parser.tab.h"
/*#define LEXDEBUG 1*/
#ifdef LEXDEBUG
#define DPRINT(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
#else
#define DPRINT(fmt, ...) do { } while (0)
#endif
%}
%%
\"[^"]*\" {
yylloc.first_line = yylineno;
DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1,
yyleng-2);
yylloc.first_line = yylineno;
return DT_STRING;
}
"/memreserve/" {
yylloc.first_line = yylineno;
DPRINT("Keyword: /memreserve/\n");
BEGIN(MEMRESERVE);
return DT_MEMRESERVE;
}
<MEMRESERVE>[0-9a-fA-F]+ {
yylloc.first_line = yylineno;
if (yyleng > 2*sizeof(yylval.addr)) {
fprintf(stderr, "Address value %s too large\n",
yytext);
}
yylval.addr = (u64) strtoull(yytext, NULL, 16);
DPRINT("Addr: %llx\n",
(unsigned long long)yylval.addr);
return DT_ADDR;
}
<MEMRESERVE>";" {
yylloc.first_line = yylineno;
DPRINT("/MEMRESERVE\n");
BEGIN(INITIAL);
return ';';
}
<CELLDATA>[0-9a-fA-F]+ {
yylloc.first_line = yylineno;
if (yyleng > 2*sizeof(yylval.cval)) {
fprintf(stderr,
"Cell value %s too long\n", yytext);
}
yylval.cval = strtoul(yytext, NULL, 16);
DPRINT("Cell: %x\n", yylval.cval);
return DT_CELL;
}
<CELLDATA>">" {
yylloc.first_line = yylineno;
DPRINT("/CELLDATA\n");
BEGIN(INITIAL);
return '>';
}
<CELLDATA>\&{REFCHAR}* {
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.str = strdup(yytext+1);
return DT_REF;
}
<BYTESTRING>[0-9a-fA-F]{2} {
yylloc.first_line = yylineno;
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE;
}
<BYTESTRING>"]" {
yylloc.first_line = yylineno;
DPRINT("/BYTESTRING\n");
BEGIN(INITIAL);
return ']';
}
{PROPCHAR}+ {
yylloc.first_line = yylineno;
DPRINT("PropName: %s\n", yytext);
yylval.str = strdup(yytext);
return DT_PROPNAME;
}
{PROPCHAR}+(@{UNITCHAR}+)? {
yylloc.first_line = yylineno;
DPRINT("NodeName: %s\n", yytext);
yylval.str = strdup(yytext);
return DT_NODENAME;
}
[a-zA-Z_][a-zA-Z0-9_]*: {
yylloc.first_line = yylineno;
DPRINT("Label: %s\n", yytext);
yylval.str = strdup(yytext);
yylval.str[yyleng-1] = '\0';
return DT_LABEL;
}
<*>{WS}+ /* eat whitespace */
<*>"/*"([^*]|\*+[^*/])*\*+"/" {
yylloc.first_line = yylineno;
DPRINT("Comment: %s\n", yytext);
/* eat comments */
}
<*>"//".*\n /* eat line comments */
<*>. {
yylloc.first_line = yylineno;
switch (yytext[0]) {
case '<':
DPRINT("CELLDATA\n");
BEGIN(CELLDATA);
break;
case '[':
DPRINT("BYTESTRING\n");
BEGIN(BYTESTRING);
break;
default:
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
break;
}
return yytext[0];
}
%%

162
util/dtc/dtc-parser.y Normal file
View file

@ -0,0 +1,162 @@
/*
* (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
*/
%glr-parser
%locations
%{
#include "dtc.h"
int yylex (void);
void yyerror (char const *);
extern struct boot_info *the_boot_info;
%}
%union {
cell_t cval;
u8 byte;
char *str;
struct data data;
struct property *prop;
struct property *proplist;
struct node *node;
struct node *nodelist;
int datalen;
int hexlen;
u64 addr;
struct reserve_info *re;
}
%token DT_MEMRESERVE
%token <addr> DT_ADDR
%token <str> DT_PROPNAME
%token <str> DT_NODENAME
%token <cval> DT_CELL
%token <byte> DT_BYTE
%token <data> DT_STRING
%token <str> DT_UNIT
%token <str> DT_LABEL
%token <str> DT_REF
%type <data> propdata
%type <re> memreserve
%type <re> memreserves
%type <data> celllist
%type <data> bytestring
%type <prop> propdef
%type <proplist> proplist
%type <node> devicetree
%type <node> nodedef
%type <node> subnode
%type <nodelist> subnodes
%type <str> label
%type <str> nodename
%%
sourcefile: memreserves devicetree {
the_boot_info = build_boot_info($1, $2);
}
;
memreserves: memreserve memreserves {
$$ = chain_reserve_entry($1, $2);
}
| /* empty */ {
$$ = NULL;
}
;
memreserve: DT_MEMRESERVE DT_ADDR DT_ADDR ';' {
$$ = build_reserve_entry($2, $3, NULL);
}
| DT_MEMRESERVE DT_ADDR '-' DT_ADDR ';' {
$$ = build_reserve_entry($2, $4 - $2 + 1, NULL);
}
;
devicetree: '/' nodedef {
$$ = name_node($2, "", NULL);
}
;
nodedef: '{' proplist subnodes '}' ';' {
$$ = build_node($2, $3);
}
;
proplist: propdef proplist {
$$ = chain_property($1, $2);
}
| /* empty */ {
$$ = NULL;
}
;
propdef: label DT_PROPNAME '=' propdata ';' {
$$ = build_property($2, $4, $1);
}
| label DT_PROPNAME ';' {
$$ = build_property($2, empty_data, $1);
}
;
propdata: DT_STRING { $$ = $1; }
| '<' celllist '>' { $$ = $2; }
| '[' bytestring ']' { $$ = $2; }
;
celllist: celllist DT_CELL { $$ = data_append_cell($1, $2); }
| celllist DT_REF {
$$ = data_append_cell(data_add_fixup($1, $2), -1);
}
| /* empty */ { $$ = empty_data; }
;
bytestring: bytestring DT_BYTE { $$ = data_append_byte($1, $2); }
| /* empty */ { $$ = empty_data; }
;
subnodes: subnode subnodes {
$$ = chain_node($1, $2);
}
| /* empty */ { $$ = NULL; }
;
subnode: label nodename nodedef { $$ = name_node($3, $2, $1); }
;
nodename: DT_NODENAME { $$ = $1; }
| DT_PROPNAME { $$ = $1; }
;
label: DT_LABEL { $$ = $1; }
| /* empty */ { $$ = NULL; }
;
%%
void yyerror (char const *s)
{
fprintf (stderr, "%s at line %d\n", s, yylloc.first_line);
}

209
util/dtc/dtc.c Normal file
View file

@ -0,0 +1,209 @@
/*
* (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"
char *join_path(char *path, 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;
}
void fill_fullpaths(struct node *tree, char *prefix)
{
struct node *child;
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);
}
static FILE *dtc_open_file(char *fname)
{
FILE *f;
if (streq(fname, "-"))
f = stdin;
else
f = fopen(fname, "r");
if (! f)
die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
return f;
}
static void usage(void)
{
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\tdtc [options] <input file>\n");
fprintf(stderr, "\nOptions:\n");
fprintf(stderr, "\t-I <input format>\n");
fprintf(stderr, "\t\tInput formats are:\n");
fprintf(stderr, "\t\t\tdts - device tree source text\n");
fprintf(stderr, "\t\t\tdtb - device tree blob\n");
fprintf(stderr, "\t\t\tfs - /proc/device-tree style directory\n");
fprintf(stderr, "\t-O <output format>\n");
fprintf(stderr, "\t\tOutput formats are:\n");
fprintf(stderr, "\t\t\tdts - device tree source text\n");
fprintf(stderr, "\t\t\tdtb - device tree blob\n");
fprintf(stderr, "\t\t\tasm - assembler source\n");
fprintf(stderr, "\t\t\tlinuxbios (or just lb) - linuxbios source\n");
fprintf(stderr, "\t-V <output version>\n");
fprintf(stderr, "\t\tBlob version to produce, defaults to 3 (relevant for dtb\n\t\tand asm output only)\n");
fprintf(stderr, "\t-R <number>\n");
fprintf(stderr, "\t\tMake space for <number> reserve map entries (relevant for \n\t\tdtb and asm output only)\n");
fprintf(stderr, "\t-b <number>\n");
fprintf(stderr, "\t\tSet the physical boot cpu\n");
fprintf(stderr, "\t-f\n");
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
exit(2);
}
int main(int argc, char *argv[])
{
struct boot_info *bi;
char *inform = "dts";
char *outform = "dts";
char *outname = "-";
int force = 0;
char *arg;
int opt;
FILE *inf = NULL;
FILE *outf = NULL;
int outversion = 3;
int reservenum = 1;
int boot_cpuid_phys = 0xfeedbeef;
while ((opt = getopt(argc, argv, "I:O:o:V:R:fb:")) != 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 'R':
reservenum = strtol(optarg, NULL, 0);
break;
case 'f':
force = 1;
break;
case 'b':
boot_cpuid_phys = strtol(optarg, NULL, 0);
break;
default:
usage();
}
}
if (argc > (optind+1))
usage();
else if (argc < (optind+1))
arg = "-";
else
arg = argv[optind];
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);
if (streq(inform, "dts")) {
inf = dtc_open_file(arg);
bi = dt_from_source(inf);
} else if (streq(inform, "fs")) {
bi = dt_from_fs(arg);
} else if(streq(inform, "dtb")) {
inf = dtc_open_file(arg);
bi = dt_from_blob(inf);
} else {
die("Unknown input format \"%s\"\n", inform);
}
if (inf && (inf != stdin))
fclose(inf);
if (! bi || ! bi->dt)
die("Couldn't read input tree\n");
if (! check_device_tree(bi->dt, outversion, boot_cpuid_phys)) {
fprintf(stderr, "Input tree has errors\n");
if (! force)
exit(1);
}
if (streq(outname, "-")) {
outf = stdout;
} else {
outf = fopen(outname, "w");
if (! outf)
die("Couldn't open output file %s: %s\n",
outname, strerror(errno));
}
if (streq(outform, "dts")) {
dt_to_source(outf, bi);
} else if (streq(outform, "dtb")) {
dt_to_blob(outf, bi, outversion, boot_cpuid_phys);
} else if (streq(outform, "asm")) {
dt_to_asm(outf, bi, outversion, boot_cpuid_phys);
} else if (streq(outform, "C")) {
dt_to_C(outf, bi, outversion, boot_cpuid_phys);
} else if (streq(outform, "linuxbios") || streq(outform, "lb")) {
dt_to_linuxbios(outf, bi, outversion, boot_cpuid_phys);
} else if (streq(outform, "null")) {
/* do nothing */
} else {
die("Unknown output format \"%s\"\n", outform);
}
exit(0);
}

233
util/dtc/dtc.h Normal file
View file

@ -0,0 +1,233 @@
#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 <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#include <netinet/in.h>
#include <endian.h>
#include <byteswap.h>
#include "flat_dt.h"
static inline void die(char * str, ...)
{
va_list ap;
va_start(ap, str);
fprintf(stderr, "FATAL ERROR: ");
vfprintf(stderr, str, 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=%d)\n", len);
return new;
}
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef u32 cell_t;
#define cpu_to_be16(x) htons(x)
#define be16_to_cpu(x) ntohs(x)
#define cpu_to_be32(x) htonl(x)
#define be32_to_cpu(x) ntohl(x)
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be64(x) (x)
#define be64_to_cpu(x) (x)
#else
#define cpu_to_be64(x) bswap_64(x)
#define be64_to_cpu(x) bswap_64(x)
#endif
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* Data blobs */
struct fixup {
int offset;
char *ref;
struct fixup *next;
};
struct data {
int len;
char *val;
int asize;
struct fixup *refs;
};
#define empty_data \
((struct data){.len = 0, .val = NULL, .asize = 0, .refs = NULL})
void fixup_free(struct fixup *f);
void data_free(struct data d);
struct data data_grow_for(struct data d, int xlen);
struct data data_copy_mem(char *mem, int len);
struct data data_copy_escape_string(char *s, int len);
struct data data_copy_file(FILE *f, size_t len);
struct data data_append_data(struct data d, void *p, int len);
struct data data_append_cell(struct data d, cell_t word);
struct data data_append_re(struct data d, struct reserve_entry *re);
struct data data_append_addr(struct data d, u64 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_fixup(struct data d, char *ref);
int data_is_one_string(struct data d);
/* DT constraints */
#define MAX_PROPNAME_LEN 31
#define MAX_NODENAME_LEN 31
/* Live trees */
struct property {
char *name;
struct data val;
struct property *next;
char *label;
};
struct node {
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;
char *label;
};
#define for_each_property(n, p) \
for ((p) = (n)->proplist; (p); (p) = (p)->next)
#define for_each_child(n, c) \
for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
struct property *build_property(char *name, struct data val, char *label);
struct property *chain_property(struct property *first, struct property *list);
struct node *build_node(struct property *proplist, struct node *children);
struct node *name_node(struct node *node, char *name, char *label);
struct node *chain_node(struct node *first, struct node *list);
void add_property(struct node *node, struct property *prop);
void add_child(struct node *parent, struct node *child);
int check_device_tree(struct node *dt, int outversion, int boot_cpuid_phys);
/* Boot info (tree plus memreserve information */
struct reserve_info {
struct reserve_entry re;
struct reserve_info *next;
char *label;
};
struct reserve_info *build_reserve_entry(u64 start, u64 len, char *label);
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 boot_info {
struct reserve_info *reservelist;
struct node *dt; /* the device tree */
};
struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree);
/* Flattened trees */
void dt_to_blob(FILE *f, struct boot_info *bi, int version,
int boot_cpuid_phys);
void dt_to_asm(FILE *f, struct boot_info *bi, int version,
int boot_cpuid_phys);
void dt_to_C(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys);
void dt_to_linuxbios(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys);
struct boot_info *dt_from_blob(FILE *f);
/* Tree source */
void dt_to_source(FILE *f, struct boot_info *bi);
struct boot_info *dt_from_source(FILE *f);
/* FS trees */
struct boot_info *dt_from_fs(char *dirname);
/* misc */
char *join_path(char *path, char *name);
void fill_fullpaths(struct node *tree, char *prefix);
#endif /* _DTC_H */

50
util/dtc/dtsqemu Normal file
View file

@ -0,0 +1,50 @@
/{
model = "qemu";
#address-cells = <1>;
#size-cells = <1>;
compatible = "emulation-i386,qemu";
cpus {
#address-cells = <1>;
#size-cells = <0>;
emulation,qemu-i386@0{
name = "emulation,qemu-i386";
device_type = "cpu";
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
linux,boot-cpu;
reg = <0>;
i-cache-size = <2000>;
d-cache-size = <2000>;
};
};
memory@0 {
device_type = "memory";
reg = <00000000 20000000>;
};
/* the I/O stuff */
northbridge,intel,440bx{
associated-cpu = <&/cpus/emulation,qemu-i386@0>;
southbridge,intel,piix4{
superio,nsc,sucks{
uart@0{
enabled=<1>;
};
};
};
};
chosen {
bootargs = "root=/dev/sda2";
linux,platform = <00000600>;
linux,stdout-path="/dev/ttyS0";
};
options {
normal="normal";
fallback="fallback";
};
};

45
util/dtc/flat_dt.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef _FLAT_DT_H_
#define _FLAT_DT_H_
#define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */
#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */
#define OF_DT_END_NODE 0x2 /* End node */
#define OF_DT_PROP 0x3 /* Property: name off,
size, content */
#define OF_DT_NOP 0x4 /* nop */
#define OF_DT_END 0x9
struct boot_param_header {
uint32_t magic; /* magic word OF_DT_HEADER */
uint32_t totalsize; /* total size of DT block */
uint32_t off_dt_struct; /* offset to structure */
uint32_t off_dt_strings; /* offset to strings */
uint32_t off_mem_rsvmap; /* offset to memory reserve map */
uint32_t version; /* format version */
uint32_t last_comp_version; /* last compatible version */
/* version 2 fields below */
uint32_t boot_cpuid_phys; /* Which physical CPU id we're
booting on */
/* version 3 fields below */
uint32_t size_dt_strings; /* size of the strings block */
};
#define BPH_V1_SIZE (7*sizeof(uint32_t))
#define BPH_V2_SIZE (BPH_V1_SIZE + sizeof(uint32_t))
#define BPH_V3_SIZE (BPH_V2_SIZE + sizeof(uint32_t))
struct reserve_entry {
uint64_t address;
uint64_t size;
};
struct flat_dt_property {
uint32_t nameoff;
uint32_t len;
char data[0];
};
#endif /* _FLAT_DT_H_ */

1389
util/dtc/flattree.c Normal file

File diff suppressed because it is too large Load diff

94
util/dtc/fstree.c Normal file
View file

@ -0,0 +1,94 @@
/*
* (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(char *dirname)
{
DIR *d;
struct dirent *de;
struct stat st;
struct node *tree;
d = opendir(dirname);
if (! d)
die("opendir(): %s\n", strerror(errno));
tree = build_node(NULL, NULL);
while ((de = readdir(d)) != NULL) {
char *tmpnam;
if (streq(de->d_name, ".")
|| streq(de->d_name, ".."))
continue;
tmpnam = join_path(dirname, de->d_name);
if (lstat(tmpnam, &st) < 0)
die("stat(%s): %s\n", tmpnam, strerror(errno));
if (S_ISREG(st.st_mode)) {
struct property *prop;
FILE *pfile;
pfile = fopen(tmpnam, "r");
if (! pfile) {
fprintf(stderr,
"WARNING: Cannot open %s: %s\n",
tmpnam, strerror(errno));
} else {
prop = build_property(strdup(de->d_name),
data_copy_file(pfile,
st.st_size),
NULL);
add_property(tree, prop);
fclose(pfile);
}
} else if (S_ISDIR(st.st_mode)) {
struct node *newchild;
newchild = read_fstree(tmpnam);
newchild = name_node(newchild, strdup(de->d_name),
NULL);
add_child(tree, newchild);
}
free(tmpnam);
}
return tree;
}
struct boot_info *dt_from_fs(char *dirname)
{
struct node *tree;
tree = read_fstree(dirname);
tree = name_node(tree, "", NULL);
fill_fullpaths(tree, "");
return build_boot_info(NULL, tree);
}

188
util/dtc/ftdump.c Normal file
View file

@ -0,0 +1,188 @@
/*
* ftdump.c - Contributed by Pantelis Antoniou <pantelis.antoniou AT gmail.com>
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <netinet/in.h>
#include <byteswap.h>
#include "flat_dt.h"
#define cpu_to_be16(x) htons(x)
#define be16_to_cpu(x) ntohs(x)
#define cpu_to_be32(x) htonl(x)
#define be32_to_cpu(x) ntohl(x)
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_be64(x) (x)
#define be64_to_cpu(x) (x)
#else
#define cpu_to_be64(x) bswap_64(x)
#define be64_to_cpu(x) bswap_64(x)
#endif
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
#define GET_CELL(p) (p += 4, *((uint32_t *)(p-4)))
static int is_printable_string(const void *data, int len)
{
const char *s = data;
const char *ss;
/* zero length is not */
if (len == 0)
return 0;
/* must terminate with zero */
if (s[len - 1] != '\0')
return 0;
ss = s;
while (*s && isprint(*s))
s++;
/* not zero, or not done yet */
if (*s != '\0' || (s + 1 - ss) < len)
return 0;
return 1;
}
static void print_data(const void *data, int len)
{
int i;
const uint8_t *s;
/* no data, don't print */
if (len == 0)
return;
if (is_printable_string(data, len)) {
printf(" = \"%s\"", (char *)data);
} else if ((len % 4) == 0) {
printf(" = <");
for (i = 0; i < len; i += 4)
printf("%08x%s", *((uint32_t *)data + i),
i < (len - 4) ? " " : "");
printf(">");
} else {
printf(" = [");
for (i = 0, s = data; i < len; i++)
printf("%02x%s", s[i], i < len - 1 ? " " : "");
printf("]");
}
}
static void dump_blob(void *blob)
{
struct boot_param_header *bph = blob;
struct reserve_entry *p_rsvmap =
(struct reserve_entry *)(blob
+ be32_to_cpu(bph->off_mem_rsvmap));
char *p_struct = blob + be32_to_cpu(bph->off_dt_struct);
char *p_strings = blob + be32_to_cpu(bph->off_dt_strings);
uint32_t version = be32_to_cpu(bph->version);
uint32_t tag;
char *p;
char *s, *t;
int depth, sz, shift;
int i;
uint64_t addr, size;
depth = 0;
shift = 4;
printf("// Version 0x%x tree\n", version);
for (i = 0; ; i++) {
addr = be64_to_cpu(p_rsvmap[i].address);
size = be64_to_cpu(p_rsvmap[i].size);
if (addr == 0 && size == 0)
break;
printf("/memreserve/ %llx %llx;\n",
(unsigned long long)addr, (unsigned long long)size);
}
p = p_struct;
while ((tag = be32_to_cpu(GET_CELL(p))) != OF_DT_END) {
/* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */
if (tag == OF_DT_BEGIN_NODE) {
s = p;
p = PALIGN(p + strlen(s) + 1, 4);
if (*s == '\0')
s = "/";
printf("%*s%s {\n", depth * shift, "", s);
depth++;
continue;
}
if (tag == OF_DT_END_NODE) {
depth--;
printf("%*s};\n", depth * shift, "");
continue;
}
if (tag == OF_DT_NOP) {
printf("%*s// [NOP]\n", depth * shift, "");
continue;
}
if (tag != OF_DT_PROP) {
fprintf(stderr, "%*s ** Unknown tag 0x%08x\n", depth * shift, "", tag);
break;
}
sz = GET_CELL(p);
s = p_strings + be32_to_cpu(GET_CELL(p));
if (version < 0x10 && sz >= 8)
p = PALIGN(p, 8);
t = p;
p = PALIGN(p + sz, 4);
printf("%*s%s", depth * shift, "", s);
print_data(t, sz);
printf(";\n");
}
}
int main(int argc, char *argv[])
{
FILE *fp;
char buf[16384]; /* 16k max */
int size;
if (argc < 2) {
fprintf(stderr, "supply input filename\n");
return 5;
}
fp = fopen(argv[1], "rb");
if (fp == NULL) {
fprintf(stderr, "unable to open %s\n", argv[1]);
return 10;
}
size = fread(buf, 1, sizeof(buf), fp);
if (size == sizeof(buf)) { /* too large */
fprintf(stderr, "file too large\n");
return 10;
}
dump_blob(buf);
fclose(fp);
return 0;
}

230
util/dtc/libdt.c Normal file
View file

@ -0,0 +1,230 @@
/*
* (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 <stdint.h>
#include <string.h>
#include "flat_dt.h"
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define PALIGN(p, a) ((void *)(ALIGN((unsigned long)(p), (a))))
#define GET_CELL(p) (p += 4, *((uint32_t *)(p-4)))
static char *skip_name(char *p)
{
while (*p != '\0')
p++;
return PALIGN(p, sizeof(uint32_t));
}
static char *skip_prop(void *blob, char *p)
{
struct boot_param_header *bph = blob;
uint32_t len, nameoff;
len = GET_CELL(p);
nameoff = GET_CELL(p);
if ((bph->version < 0x10) && (len >= sizeof(uint64_t)))
p = PALIGN(p, sizeof(uint64_t));
return PALIGN(p + len, sizeof(uint32_t));
}
static char *get_unit(char *dtpath)
{
char *p;
if (dtpath[0] != '/')
return dtpath;
p = dtpath + strlen(dtpath);
while (*p != '/')
p--;
return p+1;
}
static int first_seg_len(char *dtpath)
{
int len = 0;
while ((dtpath[len] != '/') && (dtpath[len] != '\0'))
len++;
return len;
}
char *flat_dt_get_string(void *blob, uint32_t offset)
{
struct boot_param_header *bph = blob;
return (char *)blob + bph->off_dt_strings + offset;
}
void *flat_dt_get_subnode(void *blob, void *node, char *uname, int unamelen)
{
struct boot_param_header *bph = blob;
char *p = node;
uint32_t tag;
int depth = 0;
char *nuname;
if (! unamelen)
unamelen = strlen(uname);
do {
tag = GET_CELL(p);
switch (tag) {
case OF_DT_PROP:
p = skip_prop(blob, p);
break;
case OF_DT_BEGIN_NODE:
if (depth == 0) {
nuname = p;
if (bph->version < 0x10)
nuname = get_unit(nuname);
p = skip_name(p);
if (strncmp(nuname, uname, unamelen) == 0)
return p;
}
depth++;
break;
case OF_DT_END_NODE:
depth--;
break;
case OF_DT_END:
/* looks like a malformed tree */
return NULL;
break;
default:
/* FIXME: throw some sort of error */
return NULL;
}
} while (depth >= 0);
return NULL;
}
void *flat_dt_get_node(void *blob, char *path)
{
struct boot_param_header *bph = blob;
char *node;
int seglen;
node = blob + bph->off_dt_struct;
node += sizeof(uint32_t); /* skip initial OF_DT_BEGIN_NODE */
node = skip_name(node); /* skip root node name */
while (node && (*path)) {
if (path[0] == '/')
path++;
seglen = first_seg_len(path);
node = flat_dt_get_subnode(blob, node, path, seglen);
path += seglen;
}
return node;
}
void flat_dt_traverse(void *blob,
int (*fn)(void *blob, void *node, void *priv),
void *private)
{
struct boot_param_header *bph = blob;
char *p;
uint32_t tag;
int depth = 0;
char *uname;
p = (char *)blob + bph->off_dt_struct;
tag = GET_CELL(p);
while (tag != OF_DT_END) {
switch (tag) {
case OF_DT_BEGIN_NODE:
uname = p;
if (bph->version < 0x10)
uname = get_unit(uname);
p = skip_name(p);
(*fn)(blob, p, private);
depth++;
break;
case OF_DT_END_NODE:
depth--;
break;
case OF_DT_PROP:
p = skip_prop(blob, p);
break;
default:
/* FIXME: badly formed tree */
return;
}
}
}
void *flat_dt_get_prop(void *blob, void *node, char *name, uint32_t *len)
{
struct boot_param_header *bph = blob;
char *p = node;
do {
uint32_t tag = GET_CELL(p);
uint32_t sz, noff;
const char *nstr;
if (tag != OF_DT_PROP)
return NULL;
sz = GET_CELL(p);
noff = GET_CELL(p);
/* Old versions have variable alignment of the
* property value */
if ((bph->version < 0x10) && (sz >= 8))
p = PALIGN(p, 8);
nstr = flat_dt_get_string(blob, noff);
if (strcmp(name, nstr) == 0) {
if (len)
*len = sz;
return (void *)p;
}
p = PALIGN(p + sz, sizeof(uint32_t));
} while(1);
}

742
util/dtc/livetree.c Normal file
View file

@ -0,0 +1,742 @@
/*
* (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
*/
struct property *build_property(char *name, struct data val, char *label)
{
struct property *new = xmalloc(sizeof(*new));
new->name = name;
new->val = val;
new->next = NULL;
new->label = label;
return new;
}
struct property *chain_property(struct property *first, struct property *list)
{
assert(first->next == NULL);
first->next = list;
return first;
}
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 = proplist;
new->children = children;
for_each_child(new, child) {
child->parent = new;
}
return new;
}
struct node *name_node(struct node *node, char *name, char * label)
{
assert(node->name == NULL);
node->name = name;
node->label = label;
return node;
}
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 add_child(struct node *parent, struct node *child)
{
struct node **p;
child->next_sibling = NULL;
p = &parent->children;
while (*p)
p = &((*p)->next_sibling);
*p = child;
}
struct reserve_info *build_reserve_entry(u64 address, u64 size, char *label)
{
struct reserve_info *new = xmalloc(sizeof(*new));
new->re.address = address;
new->re.size = size;
new->next = NULL;
new->label = label;
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;
}
/*
* Tree accessor functions
*/
static char *get_unitname(struct node *node)
{
if (node->name[node->basenamelen] == '\0')
return "";
else
return node->name + node->basenamelen + 1;
}
static struct property *get_property(struct node *node, char *propname)
{
struct property *prop;
for_each_property(node, prop)
if (streq(prop->name, propname))
return prop;
return NULL;
}
static cell_t propval_cell(struct property *prop)
{
assert(prop->val.len == sizeof(cell_t));
return be32_to_cpu(*((cell_t *)prop->val.val));
}
static struct node *get_subnode(struct node *node, char *nodename)
{
struct node *child;
for_each_child(node, child)
if (streq(child->name, nodename))
return child;
return NULL;
}
static struct node *get_node_by_path(struct node *tree, char *path)
{
char *p;
struct node *child;
if (!path || ! (*path))
return tree;
while (path[0] == '/')
path++;
p = strchr(path, '/');
for_each_child(tree, child) {
if (p && strneq(path, child->name, p-path))
return get_node_by_path(child, p+1);
else if (!p && streq(path, child->name))
return child;
}
return NULL;
}
static struct node *get_node_by_phandle(struct node *tree, cell_t phandle)
{
struct node *child, *node;
assert((phandle != 0) && (phandle != -1));
if (tree->phandle == phandle)
return tree;
for_each_child(tree, child) {
node = get_node_by_phandle(child, phandle);
if (node)
return node;
}
return NULL;
}
/*
* Tree checking functions
*/
#define ERRMSG(...) fprintf(stderr, "ERROR: " __VA_ARGS__)
#define WARNMSG(...) fprintf(stderr, "Warning: " __VA_ARGS__)
static int must_be_one_cell(struct property *prop, struct node *node)
{
if (prop->val.len != sizeof(cell_t)) {
ERRMSG("\"%s\" property in %s has the wrong length (should be 1 cell)\n",
prop->name, node->fullpath);
return 0;
}
return 1;
}
static int must_be_cells(struct property *prop, struct node *node)
{
if ((prop->val.len % sizeof(cell_t)) != 0) {
ERRMSG("\"%s\" property in %s is not a multiple of cell size\n",
prop->name, node->fullpath);
return 0;
}
return 1;
}
static int must_be_string(struct property *prop, struct node *node)
{
if (! data_is_one_string(prop->val)) {
ERRMSG("\"%s\" property in %s is not a string\n",
prop->name, node->fullpath);
return 0;
}
return 1;
}
static int name_prop_check(struct property *prop, struct node *node)
{
if ((prop->val.len != node->basenamelen+1)
|| !strneq(prop->val.val, node->name, node->basenamelen)) {
ERRMSG("name property \"%s\" does not match node basename in %s\n",
prop->val.val,
node->fullpath);
return 0;
}
return 1;
}
static struct {
char *propname;
int (*check_fn)(struct property *prop, struct node *node);
} prop_checker_table[] = {
{"name", must_be_string},
{"name", name_prop_check},
{"linux,phandle", must_be_one_cell},
{"#address-cells", must_be_one_cell},
{"#size-cells", must_be_one_cell},
{"reg", must_be_cells},
{"model", must_be_string},
{"device_type", must_be_string},
};
#define DO_ERR(...) do {ERRMSG(__VA_ARGS__); ok = 0; } while (0)
static int check_properties(struct node *node)
{
struct property *prop, *prop2;
int ok = 1;
for_each_property(node, prop) {
int i;
/* check for duplicates */
/* FIXME: do this more efficiently */
for (prop2 = prop->next; prop2; prop2 = prop2->next) {
if (streq(prop->name, prop2->name)) {
DO_ERR("Duplicate propertyname %s in node %s\n",
prop->name, node->fullpath);
}
}
/* check name length */
if (strlen(prop->name) > MAX_PROPNAME_LEN)
WARNMSG("Property name %s is too long in %s\n",
prop->name, node->fullpath);
/* check this property */
for (i = 0; i < ARRAY_SIZE(prop_checker_table); i++) {
if (streq(prop->name, prop_checker_table[i].propname))
if (! prop_checker_table[i].check_fn(prop, node)) {
ok = 0;
break;
}
}
}
return ok;
}
static int check_node_name(struct node *node)
{
int ok = 1;
int len = strlen(node->name);
if (len == 0 && node->parent)
DO_ERR("Empty, non-root nodename at %s\n", node->fullpath);
if (len > MAX_NODENAME_LEN)
DO_ERR("Overlength nodename at %s\n", node->fullpath);
return ok;
}
static int check_structure(struct node *tree)
{
struct node *child, *child2;
int ok = 1;
if (! check_node_name(tree))
ok = 0;
if (! check_properties(tree))
ok = 0;
for_each_child(tree, child) {
/* Check for duplicates */
for (child2 = child->next_sibling;
child2;
child2 = child2->next_sibling) {
if (streq(child->name, child2->name))
DO_ERR("Duplicate node name %s\n",
child->fullpath);
}
if (! check_structure(child))
ok = 0;
}
return ok;
}
#define CHECK_HAVE(node, propname) \
do { \
if (! (prop = get_property((node), (propname)))) \
DO_ERR("Missing \"%s\" property in %s\n", (propname), \
(node)->fullpath); \
} while (0);
#define CHECK_HAVE_WARN(node, propname) \
do { \
if (! (prop = get_property((node), (propname)))) \
WARNMSG("%s has no \"%s\" property\n", \
(node)->fullpath, (propname)); \
} while (0)
#define CHECK_HAVE_STRING(node, propname) \
do { \
CHECK_HAVE((node), (propname)); \
if (prop && !data_is_one_string(prop->val)) \
DO_ERR("\"%s\" property in %s is not a string\n", \
(propname), (node)->fullpath); \
} while (0)
#define CHECK_HAVE_STREQ(node, propname, value) \
do { \
CHECK_HAVE_STRING((node), (propname)); \
if (prop && !streq(prop->val.val, (value))) \
DO_ERR("%s has wrong %s, %s (should be %s\n", \
(node)->fullpath, (propname), \
prop->val.val, (value)); \
} while (0)
#define CHECK_HAVE_ONECELL(node, propname) \
do { \
CHECK_HAVE((node), (propname)); \
if (prop && (prop->val.len != sizeof(cell_t))) \
DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
} while (0)
#define CHECK_HAVE_WARN_ONECELL(node, propname) \
do { \
CHECK_HAVE_WARN((node), (propname)); \
if (prop && (prop->val.len != sizeof(cell_t))) \
DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
} while (0)
#define CHECK_HAVE_WARN_PHANDLE(xnode, propname, root) \
do { \
struct node *ref; \
CHECK_HAVE_WARN_ONECELL((xnode), (propname)); \
if (prop) {\
ref = get_node_by_phandle((root), propval_cell(prop)); \
if (! ref) \
DO_ERR("\"%s\" property in %s refers to non-existant phandle %x\n", (propname), (xnode)->fullpath, propval_cell(prop)); \
} \
} while (0)
#define CHECK_HAVE_WARN_STRING(node, propname) \
do { \
CHECK_HAVE_WARN((node), (propname)); \
if (prop && !data_is_one_string(prop->val)) \
DO_ERR("\"%s\" property in %s is not a string\n", \
(propname), (node)->fullpath); \
} while (0)
static int check_root(struct node *root)
{
struct property *prop;
int ok = 1;
CHECK_HAVE_STRING(root, "model");
CHECK_HAVE(root, "#address-cells");
CHECK_HAVE(root, "#size-cells");
CHECK_HAVE_WARN(root, "compatible");
return ok;
}
static int check_cpus(struct node *root, int outversion, int boot_cpuid_phys)
{
struct node *cpus, *cpu;
struct property *prop;
struct node *bootcpu = NULL;
int ok = 1;
cpus = get_subnode(root, "cpus");
if (! cpus) {
ERRMSG("Missing /cpus node\n");
return 0;
}
CHECK_HAVE_WARN(cpus, "#address-cells");
CHECK_HAVE_WARN(cpus, "#size-cells");
for_each_child(cpus, cpu) {
CHECK_HAVE_STREQ(cpu, "device_type", "cpu");
if (cpu->addr_cells != 1)
DO_ERR("%s has bad #address-cells value %d (should be 1)\n",
cpu->fullpath, cpu->addr_cells);
if (cpu->size_cells != 0)
DO_ERR("%s has bad #size-cells value %d (should be 0)\n",
cpu->fullpath, cpu->size_cells);
CHECK_HAVE_ONECELL(cpu, "reg");
if (prop) {
cell_t unitnum;
char *eptr;
unitnum = strtol(get_unitname(cpu), &eptr, 16);
if (*eptr)
WARNMSG("%s has bad format unit name %s (should be CPU number\n",
cpu->fullpath, get_unitname(cpu));
else if (unitnum != propval_cell(prop))
WARNMSG("%s unit name \"%s\" does not match \"reg\" property <%x>\n",
cpu->fullpath, get_unitname(cpu),
propval_cell(prop));
}
/* CHECK_HAVE_ONECELL(cpu, "d-cache-line-size"); */
/* CHECK_HAVE_ONECELL(cpu, "i-cache-line-size"); */
CHECK_HAVE_ONECELL(cpu, "d-cache-size");
CHECK_HAVE_ONECELL(cpu, "i-cache-size");
CHECK_HAVE_WARN_ONECELL(cpu, "clock-frequency");
CHECK_HAVE_WARN_ONECELL(cpu, "timebase-frequency");
prop = get_property(cpu, "linux,boot-cpu");
if (prop) {
if (prop->val.len)
WARNMSG("\"linux,boot-cpu\" property in %s is non-empty\n",
cpu->fullpath);
if (bootcpu)
DO_ERR("Multiple boot cpus (%s and %s)\n",
bootcpu->fullpath, cpu->fullpath);
else
bootcpu = cpu;
}
}
if (outversion < 2) {
if (! bootcpu)
WARNMSG("No cpu has \"linux,boot-cpu\" property\n");
} else {
if (bootcpu)
WARNMSG("\"linux,boot-cpu\" property is deprecated in blob version 2 or higher\n");
if (boot_cpuid_phys == 0xfeedbeef)
WARNMSG("physical boot CPU not set. Use -b option to set\n");
}
return ok;
}
static int check_memory(struct node *root)
{
struct node *mem;
struct property *prop;
int nnodes = 0;
int ok = 1;
for_each_child(root, mem) {
if (! strneq(mem->name, "memory", mem->basenamelen))
continue;
nnodes++;
CHECK_HAVE_STREQ(mem, "device_type", "memory");
CHECK_HAVE(mem, "reg");
}
if (nnodes == 0) {
ERRMSG("No memory nodes\n");
return 0;
}
return ok;
}
static int check_chosen(struct node *root)
{
struct node *chosen;
struct property *prop;
int ok = 1;
chosen = get_subnode(root, "chosen");
if (! chosen) {
ERRMSG("Missing /chosen node\n");
return 0;
}
CHECK_HAVE_ONECELL(chosen, "linux,platform");
CHECK_HAVE_WARN_STRING(chosen, "bootargs");
CHECK_HAVE_WARN_STRING(chosen, "linux,stdout-path");
CHECK_HAVE_WARN_PHANDLE(chosen, "interrupt-controller", root);
return ok;
}
static int check_addr_size_reg(struct node *node,
int p_addr_cells, int p_size_cells)
{
int addr_cells = p_addr_cells;
int size_cells = p_size_cells;
struct property *prop;
struct node *child;
int ok = 1;
node->addr_cells = addr_cells;
node->size_cells = size_cells;
prop = get_property(node, "reg");
if (prop) {
int len = prop->val.len / 4;
if ((len % (addr_cells+size_cells)) != 0)
DO_ERR("\"reg\" property in %s has invalid length (%d) for given #address-cells (%d) and #size-cells (%d)\n",
node->fullpath, prop->val.len,
addr_cells, size_cells);
}
prop = get_property(node, "#address-cells");
if (prop)
addr_cells = propval_cell(prop);
prop = get_property(node, "#size-cells");
if (prop)
size_cells = propval_cell(prop);
for_each_child(node, child) {
ok = ok && check_addr_size_reg(child, addr_cells, size_cells);
}
return ok;
}
static int check_phandles(struct node *root, struct node *node)
{
struct property *prop;
struct node *child, *other;
cell_t phandle;
int ok = 1;
prop = get_property(node, "linux,phandle");
if (prop) {
phandle = propval_cell(prop);
if ((phandle == 0) || (phandle == -1)) {
DO_ERR("%s has invalid linux,phandle %x\n",
node->fullpath, phandle);
} else {
other = get_node_by_phandle(root, phandle);
if (other)
DO_ERR("%s has duplicated phandle %x (seen before at %s)\n",
node->fullpath, phandle, other->fullpath);
node->phandle = phandle;
}
}
for_each_child(node, child)
ok = ok && check_phandles(root, child);
return 1;
}
static cell_t get_node_phandle(struct node *root, struct node *node)
{
static cell_t phandle = 1; /* FIXME: ick, static local */
fprintf(stderr, "get_node_phandle(%s) phandle=%x\n",
node->fullpath, node->phandle);
if ((node->phandle != 0) && (node->phandle != -1))
return node->phandle;
assert(! get_property(node, "linux,phandle"));
while (get_node_by_phandle(root, phandle))
phandle++;
node->phandle = phandle;
add_property(node,
build_property("linux,phandle",
data_append_cell(empty_data, phandle),
NULL));
return node->phandle;
}
static void apply_fixup(struct node *root, struct property *prop,
struct fixup *f)
{
struct node *refnode;
cell_t phandle;
refnode = get_node_by_path(root, f->ref);
if (! refnode)
die("Reference to non-existent node \"%s\"\n", f->ref);
phandle = get_node_phandle(root, refnode);
assert(f->offset + sizeof(cell_t) <= prop->val.len);
*((cell_t *)(prop->val.val + f->offset)) = cpu_to_be32(phandle);
}
static void fixup_phandles(struct node *root, struct node *node)
{
struct property *prop;
struct node *child;
for_each_property(node, prop) {
struct fixup *f = prop->val.refs;
while (f) {
apply_fixup(root, prop, f);
prop->val.refs = f->next;
fixup_free(f);
f = prop->val.refs;
}
}
for_each_child(node, child)
fixup_phandles(root, child);
}
int check_device_tree(struct node *dt, int outversion, int boot_cpuid_phys)
{
int ok = 1;
if (! check_structure(dt))
return 0;
ok = ok && check_addr_size_reg(dt, -1, -1);
ok = ok && check_phandles(dt, dt);
fixup_phandles(dt, dt);
if (! ok)
return 0;
ok = ok && check_root(dt);
ok = ok && check_cpus(dt, outversion, boot_cpuid_phys);
ok = ok && check_memory(dt);
ok = ok && check_chosen(dt);
if (! ok)
return 0;
return 1;
}
struct boot_info *build_boot_info(struct reserve_info *reservelist,
struct node *tree)
{
struct boot_info *bi;
bi = xmalloc(sizeof(*bi));
bi->reservelist = reservelist;
bi->dt = tree;
return bi;
}

116
util/dtc/newstatic.c Normal file
View file

@ -0,0 +1,116 @@
struct root {
u32 model;
u32 Haddress_cells;
u32 Hsize_cells;
u32 compatible;
}; /*root*/
struct cpus {
u32 Haddress_cells;
u32 Hsize_cells;
}; /*cpus*/
struct emulation_qemu_i386 {
u32 name;
u32 device_type;
u32 clock_frequency;
u32 timebase_frequency;
u32 linux_boot_cpu;
u32 reg;
u32 i_cache_size;
u32 d_cache_size;
u32 linux_phandle;
}; /*emulation_qemu_i386*/
struct memory {
u32 device_type;
u32 reg;
}; /*memory*/
struct northbridge_intel_440bx {
u32 associated_cpu;
}; /*northbridge_intel_440bx*/
struct southbridge_intel_piix4 {
}; /*southbridge_intel_piix4*/
struct superio_nsc_sucks {
}; /*superio_nsc_sucks*/
struct uart {
u32 enabled;
}; /*uart*/
struct chosen {
u32 bootargs;
u32 linux_platform;
u32 linux_stdout_path;
}; /*chosen*/
struct options {
u32 normal;
u32 fallback;
}; /*options*/
struct root root = {
u8 model = {71,65,6d,75,00,};
u8 Haddress_cells = {00,00,00,01,};
u8 Hsize_cells = {00,00,00,01,};
u8 compatible = {65,6d,75,6c,61,74,69,6f,6e,2d,69,33,38,36,2c,71,65,6d,75,00,};
}; /*root*/
struct device dev_root = {
.children = dev_cpus
}
struct cpus cpus = {
u8 Haddress_cells = {00,00,00,01,};
u8 Hsize_cells = {00,00,00,00,};
}; /*cpus*/
struct device dev_cpus = {
.sibling = dev_memory_0
.children = dev_emulation_qemu_i386_0
}
struct emulation_qemu_i386 emulation_qemu_i386_0 = {
u8 name = {65,6d,75,6c,61,74,69,6f,6e,2c,71,65,6d,75,2d,69,33,38,36,00,};
u8 device_type = {63,70,75,00,};
u8 clock_frequency = {5f,5e,10,00,};
u8 timebase_frequency = {01,fffffffc,ffffffa0,55,};
u8 reg = {00,00,00,00,};
u8 i_cache_size = {00,00,20,00,};
u8 d_cache_size = {00,00,20,00,};
u8 linux_phandle = {00,00,00,01,};
}; /*emulation_qemu_i386_0*/
struct device dev_emulation_qemu_i386_0 = {
}
struct memory memory_0 = {
u8 device_type = {6d,65,6d,6f,72,79,00,};
u8 reg = {00,00,00,00,20,00,00,00,};
}; /*memory_0*/
struct device dev_memory_0 = {
.sibling = dev_northbridge_intel_440bx
}
struct northbridge_intel_440bx northbridge_intel_440bx = {
u8 associated_cpu = {00,00,00,01,};
}; /*northbridge_intel_440bx*/
struct device dev_northbridge_intel_440bx = {
.sibling = dev_chosen
.children = dev_southbridge_intel_piix4
}
struct southbridge_intel_piix4 southbridge_intel_piix4 = {
}; /*southbridge_intel_piix4*/
struct device dev_southbridge_intel_piix4 = {
.children = dev_superio_nsc_sucks
}
struct superio_nsc_sucks superio_nsc_sucks = {
}; /*superio_nsc_sucks*/
struct device dev_superio_nsc_sucks = {
.children = dev_uart_0
}
struct uart uart_0 = {
u8 enabled = {00,00,00,01,};
}; /*uart_0*/
struct device dev_uart_0 = {
}
struct chosen chosen = {
u8 bootargs = {72,6f,6f,74,3d,2f,64,65,76,2f,73,64,61,32,00,};
u8 linux_platform = {00,00,06,00,};
u8 linux_stdout_path = {2f,64,65,76,2f,74,74,79,53,30,00,};
}; /*chosen*/
struct device dev_chosen = {
.sibling = dev_options
}
struct options options = {
u8 normal = {6e,6f,72,6d,61,6c,00,};
u8 fallback = {66,61,6c,6c,62,61,63,6b,00,};
}; /*options*/
struct device dev_options = {
}

54
util/dtc/test.dts Normal file
View file

@ -0,0 +1,54 @@
/memreserve/ 1000000000000000 0000000002000000;
/memreserve/ 2000000000000000-20ffffffffffffff;
/memreserve/ 0-13;
/ {
model = "MyBoardName";
compatible = "MyBoardFamilyName";
#address-cells = <2>;
#size-cells = <2>;
cpus {
linux,phandle = <1>;
#address-cells = <1>;
#size-cells = <0>;
PowerPC,970@0 {
name = "PowerPC,970";
device_type = "cpu";
reg = <0>;
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
linux,boot-cpu;
i-cache-size = <10000>;
d-cache-size = <8000>;
};
PowerPC,970@1 {
name = "PowerPC,970";
device_type = "cpu";
reg = <1>;
clock-frequency = <5f5e1000>;
timebase-frequency = <1FCA055>;
i-cache-size = <10000>;
d-cache-size = <8000>;
};
};
randomnode {
string = "\xff\0stuffstuff\t\t\t\n\n\n";
blob = [0a 0b 0c 0d de ea ad be ef];
ref = < &/memory@0 >;
};
memory@0 {
device_type = "memory";
memreg: reg = <00000000 00000000 00000000 20000000>;
};
chosen {
bootargs = "root=/dev/sda2";
linux,platform = <00000600>;
};
};

12
util/dtc/tests/Makefile Normal file
View file

@ -0,0 +1,12 @@
DTC = ../dtc
VG_DTC = valgrind --tool=memcheck ../dtc
check: all
./run_all_tests.sh
all:
clean:
rm -f *~

2
util/dtc/tests/empty.dts Normal file
View file

@ -0,0 +1,2 @@
/ {
};

View file

@ -0,0 +1,2 @@
#! /bin/sh

159
util/dtc/treesource.c Normal file
View file

@ -0,0 +1,159 @@
/*
* (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"
extern FILE *yyin;
extern int yyparse(void);
extern void yyerror(char const *);
struct boot_info *the_boot_info;
struct boot_info *dt_from_source(FILE *f)
{
the_boot_info = NULL;
yyin = f;
if (yyparse() != 0)
return NULL;
fill_fullpaths(the_boot_info->dt, "");
return the_boot_info;
}
static void write_prefix(FILE *f, int level)
{
int i;
for (i = 0; i < level; i++)
fputc('\t', f);
}
enum proptype {
PROP_EMPTY,
PROP_STRING,
PROP_CELLS,
PROP_BYTES,
};
static enum proptype guess_type(struct property *prop)
{
int len = prop->val.len;
char *p = prop->val.val;
int nnoprint = 0;
int i;
if (len == 0)
return PROP_EMPTY;
for (i = 0; i < len; i++) {
if (! isprint(p[i]))
nnoprint++;
}
if ((nnoprint == 1) && (p[len-1] == '\0'))
return PROP_STRING;
else if ((len % sizeof(cell_t)) == 0)
return PROP_CELLS;
else
return PROP_BYTES;
}
static void write_tree_source_node(FILE *f, struct node *tree, int level)
{
struct property *prop;
struct node *child;
write_prefix(f, level);
if (tree->name && (*tree->name))
fprintf(f, "%s {\n", tree->name);
else
fprintf(f, "/ {\n");
for_each_property(tree, prop) {
cell_t *cp;
char *bp;
void *propend;
enum proptype type;
write_prefix(f, level);
fprintf(f, "\t%s", prop->name);
type = guess_type(prop);
propend = prop->val.val + prop->val.len;
switch (type) {
case PROP_EMPTY:
fprintf(f, ";\n");
break;
case PROP_STRING:
fprintf(f, " = \"%s\";\n", (char *)prop->val.val);
break;
case PROP_CELLS:
fprintf(f, " = <");
cp = (cell_t *)prop->val.val;
for (;;) {
fprintf(f, "%x", be32_to_cpu(*cp++));
if ((void *)cp >= propend)
break;
fprintf(f, " ");
}
fprintf(f, ">;\n");
break;
case PROP_BYTES:
fprintf(f, " = [");
bp = prop->val.val;
for (;;) {
fprintf(f, "%02hhx", *bp++);
if ((void *)bp >= propend)
break;
fprintf(f, " ");
}
fprintf(f, "];\n");
break;
}
}
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 boot_info *bi)
{
struct reserve_info *re;
for (re = bi->reservelist; re; re = re->next) {
fprintf(f, "/memreserve/\t%016llx-%016llx;\n",
(unsigned long long)re->re.address,
(unsigned long long)(re->re.address + re->re.size - 1));
}
write_tree_source_node(f, bi->dt, 0);
}