filling in
git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@2 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
parent
6897649b6b
commit
a28296a6d2
28 changed files with 8336 additions and 0 deletions
339
COPYING
Normal file
339
COPYING
Normal 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.
|
||||
6
util/dtc/.gitignore
vendored
Normal file
6
util/dtc/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
*.o
|
||||
*.d
|
||||
*.tab.[ch]
|
||||
lex.yy.c
|
||||
dtc
|
||||
ftdump
|
||||
340
util/dtc/COPYING
Normal file
340
util/dtc/COPYING
Normal 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.
|
||||
1420
util/dtc/Documentation/booting-without-of.txt
Normal file
1420
util/dtc/Documentation/booting-without-of.txt
Normal file
File diff suppressed because it is too large
Load diff
43
util/dtc/Documentation/dtc-paper.bib
Normal file
43
util/dtc/Documentation/dtc-paper.bib
Normal 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}",
|
||||
}
|
||||
597
util/dtc/Documentation/dtc-paper.tex
Normal file
597
util/dtc/Documentation/dtc-paper.tex
Normal 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
42
util/dtc/Makefile
Normal 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
14
util/dtc/TODO
Normal 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
38
util/dtc/comment-test.dts
Normal 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
276
util/dtc/data.c
Normal 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
180
util/dtc/dtc-lexer.l
Normal 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
162
util/dtc/dtc-parser.y
Normal 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
209
util/dtc/dtc.c
Normal 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
233
util/dtc/dtc.h
Normal 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
50
util/dtc/dtsqemu
Normal 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
45
util/dtc/flat_dt.h
Normal 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
1389
util/dtc/flattree.c
Normal file
File diff suppressed because it is too large
Load diff
94
util/dtc/fstree.c
Normal file
94
util/dtc/fstree.c
Normal 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
188
util/dtc/ftdump.c
Normal 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
230
util/dtc/libdt.c
Normal 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
742
util/dtc/livetree.c
Normal 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
116
util/dtc/newstatic.c
Normal 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
54
util/dtc/test.dts
Normal 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
12
util/dtc/tests/Makefile
Normal 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
2
util/dtc/tests/empty.dts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/ {
|
||||
};
|
||||
2
util/dtc/tests/run_all_tests.sh
Executable file
2
util/dtc/tests/run_all_tests.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
#! /bin/sh
|
||||
|
||||
159
util/dtc/treesource.c
Normal file
159
util/dtc/treesource.c
Normal 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);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue