mirror of
				https://github.com/meizu-m86/kexec-tools-arm64
				synced 2025-11-04 13:56:01 +08:00 
			
		
		
		
	kexec-tools-1.101
- Initial import into git - initial nbi image formage support - ppc32 initial register setting fixes. - gzipped multiboot file support
This commit is contained in:
		
							
								
								
									
										6
									
								
								AUTHORS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								AUTHORS
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
Eric Biederman <ebiederm@xmission.com>
 | 
			
		||||
Albert Herranz
 | 
			
		||||
Jesse Barnes <jbarnes@sgi.com>
 | 
			
		||||
Khalid Aziz <khalid.aziz@hp.com>
 | 
			
		||||
Hariprasad Nellitheertha <hari@in.ibm.com>
 | 
			
		||||
Tim Deegan <tjd21@cl.cam.ac.uk>
 | 
			
		||||
							
								
								
									
										341
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,341 @@
 | 
			
		||||
 | 
			
		||||
		    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) 19yy  <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) 19yy 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.
 | 
			
		||||
							
								
								
									
										249
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
			
		||||
# Hey Emacs this is a -*- makefile-*-
 | 
			
		||||
include Makefile.conf
 | 
			
		||||
VERSION=1.101
 | 
			
		||||
DATE=15 February 2005
 | 
			
		||||
PACKAGE=kexec-tools
 | 
			
		||||
 | 
			
		||||
pkgdatadir = $(datadir)/$(PACKAGE)
 | 
			
		||||
pkglibdir = $(libdir)/$(PACKAGE)
 | 
			
		||||
pkgincludedir = $(includedir)/$(PACKAGE)
 | 
			
		||||
 | 
			
		||||
# You can specify DESTDIR on the command line to do a add
 | 
			
		||||
# a prefix to the install so it doesn't really happen
 | 
			
		||||
# Useful for building binary packages
 | 
			
		||||
DESTDIR =
 | 
			
		||||
 | 
			
		||||
CPPFLAGS:= -I./include -I./util_lib/include \
 | 
			
		||||
	-DVERSION='"$(VERSION)"' -DRELEASE_DATE='"$(DATE)"' \
 | 
			
		||||
	$(DEFS) $(EXTRA_CFLAGS)
 | 
			
		||||
 | 
			
		||||
PREFIX:=$(OBJDIR)/build
 | 
			
		||||
SBINDIR=$(PREFIX)/sbin
 | 
			
		||||
BINDIR=$(PREFIX)/bin
 | 
			
		||||
LIBEXECDIR=$(PREFIX)/libexec
 | 
			
		||||
DATADIR=$(PREFIX)/share
 | 
			
		||||
SYSCONFDIR=$(PREFIX)/etc
 | 
			
		||||
SHAREDSTATEDIR=$(PREFIX)/com
 | 
			
		||||
LOCALSTATEDIR=$(PREFIX)/var
 | 
			
		||||
LIBDIR=$(PREFIX)/lib
 | 
			
		||||
INFODIR=$(PREFIX)/info
 | 
			
		||||
MANDIR=$(PREFIX)/man
 | 
			
		||||
MAN1DIR=$(MANDIR)/man1
 | 
			
		||||
MAN2DIR=$(MANDIR)/man2
 | 
			
		||||
MAN3DIR=$(MANDIR)/man3
 | 
			
		||||
MAN4DIR=$(MANDIR)/man4
 | 
			
		||||
MAN5DIR=$(MANDIR)/man5
 | 
			
		||||
MAN6DIR=$(MANDIR)/man6
 | 
			
		||||
MAN7DIR=$(MANDIR)/man7
 | 
			
		||||
MAN8DIR=$(MANDIR)/man8
 | 
			
		||||
INCLUDEDIR=$(PREFIX)/include
 | 
			
		||||
 | 
			
		||||
PKGDATADIR=$(DATADIR)/$(PACKAGE)
 | 
			
		||||
PKGLIBDIR=$(LIBDIR)/$(PACKAGE)
 | 
			
		||||
PKGINCLUDEIR=$(INCLUDEDIR)/$(PACKAGE)
 | 
			
		||||
 | 
			
		||||
MAN_PAGES:= kexec/kexec.8
 | 
			
		||||
BINARIES_i386:=  $(SBINDIR)/kexec $(PKGLIBDIR)/kexec_test
 | 
			
		||||
BINARIES_x86_64:=$(SBINDIR)/kexec $(PKGLIBDIR)/kexec_test
 | 
			
		||||
BINARIES:=$(SBINDIR)/kexec $(SBINDIR)/kdump $(BINARIES_$(ARCH)) 
 | 
			
		||||
 | 
			
		||||
TARGETS:=$(BINARIES) $(MAN_PAGES)
 | 
			
		||||
 | 
			
		||||
all: $(TARGETS)
 | 
			
		||||
 | 
			
		||||
# cc-option
 | 
			
		||||
# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
 | 
			
		||||
cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
 | 
			
		||||
             > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
 | 
			
		||||
 | 
			
		||||
# Utility function library
 | 
			
		||||
#
 | 
			
		||||
include util_lib/Makefile
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Stand alone utilities
 | 
			
		||||
#
 | 
			
		||||
include util/Makefile
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# purgatory (code between kernels)
 | 
			
		||||
#
 | 
			
		||||
include purgatory/Makefile
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# kexec (linux booting linux)
 | 
			
		||||
#
 | 
			
		||||
include kexec/Makefile
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# kdump (read a crashdump from memory)
 | 
			
		||||
#
 | 
			
		||||
include kdump/Makefile
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# kexec_test (test program)
 | 
			
		||||
#
 | 
			
		||||
ifeq ($(ARCH),i386)
 | 
			
		||||
include kexec_test/Makefile
 | 
			
		||||
endif
 | 
			
		||||
ifeq ($(ARCH),x86_64)
 | 
			
		||||
include kexec_test/Makefile
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
GENERATED_SRCS:= ./configure
 | 
			
		||||
SPEC=$(OBJDIR)/$(PACKAGE)-$(VERSION).spec
 | 
			
		||||
TARBALL=$(OBJDIR)/$(PACKAGE)-$(VERSION).tar.gz
 | 
			
		||||
SRCS:=$(shell $(FIND) \
 | 
			
		||||
	./AUTHORS ./COPYING ./News ./TODO \
 | 
			
		||||
	./Makefile ./Makefile.conf.in ./configure.ac \
 | 
			
		||||
	./kexec-tools.spec.in ./config ./doc \
 | 
			
		||||
	./include ./kexec ./purgatory ./kexec_test ./kdump ./util ./util_lib \
 | 
			
		||||
	! -path '*CVS*' ! -name '*~' ! -name '.*' \
 | 
			
		||||
	-type f -print )
 | 
			
		||||
SRCS+=$(GENERATED_SRCS)
 | 
			
		||||
PSRCS:=$(patsubst ./%,$(PACKAGE)-$(VERSION)/%,$(SRCS))
 | 
			
		||||
PSRCS+=$(PACKAGE)-$(VERSION).spec
 | 
			
		||||
 | 
			
		||||
Makefile.conf: Makefile.conf.in configure
 | 
			
		||||
	/bin/sh ./configure
 | 
			
		||||
 | 
			
		||||
configure: configure.ac
 | 
			
		||||
	autoconf
 | 
			
		||||
	$(RM) -rf autom4te.cache
 | 
			
		||||
 | 
			
		||||
tarball: $(TARBALL)
 | 
			
		||||
 | 
			
		||||
$(TARBALL): $(SRCS) $(SPEC)
 | 
			
		||||
	$(MKDIR) -p $(OBJDIR)
 | 
			
		||||
	$(RM) -f $(OBJDIR)/$(PACKAGE)-$(VERSION)
 | 
			
		||||
	$(LN) -s .. $(OBJDIR)/$(PACKAGE)-$(VERSION)
 | 
			
		||||
	(cd $(OBJDIR); $(TAR) -cf - $(PSRCS) | gzip -9) > $@
 | 
			
		||||
 | 
			
		||||
rpm: $(TARBALL)
 | 
			
		||||
	$(MKDIR) -p $(OBJDIR)/RPM $(OBJDIR)/SRPM $(OBJDIR)/BUILD $(OBJDIR)/SPECS \
 | 
			
		||||
		$(OBJDIR)/TMP $(OBJDIR)/SOURCES
 | 
			
		||||
	unset MAKEFLAGS MAKELEVEL; \
 | 
			
		||||
	$(RPMBUILD) -ta \
 | 
			
		||||
		--define '_rpmdir $(OBJDIR)/RPM' \
 | 
			
		||||
		--define '_srcrpmdir $(OBJDIR)/SRPM' \
 | 
			
		||||
		--define '_builddir $(OBJDIR)/BUILD' \
 | 
			
		||||
		--define '_specdir $(OBJDIR)/SPECS' \
 | 
			
		||||
		--define '_tmppath $(OBJDIR)/TMP' \
 | 
			
		||||
		--define '_sourcedir $(OBJDIR)/SOURCES' \
 | 
			
		||||
		$(TARBALL)
 | 
			
		||||
 | 
			
		||||
$(SPEC): kexec-tools.spec.in Makefile
 | 
			
		||||
	$(SED) -e 's,^Version: $$,Version: $(VERSION),' $< > $@
 | 
			
		||||
 | 
			
		||||
echo::
 | 
			
		||||
	@echo ARCH=$(ARCH)
 | 
			
		||||
	@echo BINARIES=$(BINARIES)
 | 
			
		||||
	@echo TARGETS=$(TARGETS)
 | 
			
		||||
	@echo CC=$(CC)
 | 
			
		||||
	@echo AR=$(AR)
 | 
			
		||||
	@echo LD=$(LD)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	@$(FIND) $(OBJDIR) ! -name '*.d' -type f | $(XARGS) $(RM) rm -f
 | 
			
		||||
	@$(RM) -rf rpm
 | 
			
		||||
	@$(RM) -f config.log config.status config.cache
 | 
			
		||||
	@$(RM) -f $(TARBALL)
 | 
			
		||||
 | 
			
		||||
dist-clean: clean
 | 
			
		||||
	@$(RM) -rf $(OBJDIR)
 | 
			
		||||
	@$(FIND) . -type f -name '*~' -o -name '*.orig' | $(XARGS) $(RM) -f
 | 
			
		||||
	@$(RM) -f Makefile.conf
 | 
			
		||||
 | 
			
		||||
maintainer-clean: dist-clean
 | 
			
		||||
	@$(RM) -f $(GENERATED_SRCS)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
install: $(TARGETS)
 | 
			
		||||
	for file in $(TARGETS) ; do \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(SBINDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(sbindir)/; \
 | 
			
		||||
			$(INSTALL) -m 555  $$file $(DESTDIR)/$(sbindir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(BINDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(bindir)/; \
 | 
			
		||||
			$(INSTALL) -m 555 $$file $(DESTDIR)/$(bindir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(LIBEXECDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(libexecdir)/; \
 | 
			
		||||
			$(INSTALL) -m 555 $$file $(DESTDIR)/$(libexecdir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(DATADIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(datadir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(datadir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(SYSCONFDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(sysconfdir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(sysconfdir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(SHAREDSTATEDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(sharedstatedir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(sharedstatedir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(LOCALSTATEDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(localstatedir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(localstatedir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(LIBDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(libdir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(libdir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(INFODIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(infodir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(infodir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN1DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man1; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man1; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN2DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man2; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man2; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN3DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man3/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man3/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN4DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man4/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man4/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN5DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man5/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man5/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN6DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man6/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man6/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN7DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man7/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man7/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(MAN8DIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(mandir)/man8/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(mandir)/man8/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(INCLUDEDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(includedir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(includedir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(PKGDATADIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(pkgdatadir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(pkgdatadir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(PKGLIBDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(pkglibdir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(pkglibdir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
		if test `$(DIRNAME) $$file` =     "$(PKGINCLUDEDIR)" ; then \
 | 
			
		||||
			$(MKDIR) -p     $(DESTDIR)/$(pkgincludedir)/; \
 | 
			
		||||
			$(INSTALL) -m 444 $$file $(DESTDIR)/$(pkgincludedir)/; \
 | 
			
		||||
		fi; \
 | 
			
		||||
	done
 | 
			
		||||
 | 
			
		||||
.PHONY: echo install all clean dist-clean maintainer-clean tarball rpm
 | 
			
		||||
							
								
								
									
										52
									
								
								Makefile.conf.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								Makefile.conf.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
# Hey Emacs this is a -*- makefile-*-
 | 
			
		||||
 | 
			
		||||
prefix=@prefix@
 | 
			
		||||
exec_prefix=@exec_prefix@
 | 
			
		||||
 | 
			
		||||
bindir=@bindir@
 | 
			
		||||
sbindir=@sbindir@
 | 
			
		||||
libexecdir=@libexecdir@
 | 
			
		||||
datadir=@datadir@
 | 
			
		||||
sysconfdir=@sysconfdir@
 | 
			
		||||
sharedstatedir=@sharedstatedir@
 | 
			
		||||
localstatedir=@localstatedir@
 | 
			
		||||
libdir=@libdir@
 | 
			
		||||
infodir=@infodir@
 | 
			
		||||
mandir=@mandir@
 | 
			
		||||
includedir=@includedir@
 | 
			
		||||
 | 
			
		||||
DEFS=@DEFS@
 | 
			
		||||
LIBS=@LIBS@
 | 
			
		||||
 | 
			
		||||
# The target architecture
 | 
			
		||||
ARCH  =@ARCH@
 | 
			
		||||
OBJDIR=@OBJDIR@
 | 
			
		||||
 | 
			
		||||
# Compiler for building kexec
 | 
			
		||||
CC          =@CC@
 | 
			
		||||
CPP         =@CPP@
 | 
			
		||||
LD          =@LD@
 | 
			
		||||
AS          =@AS@
 | 
			
		||||
OBJCOPY     =@OBJCOPY@
 | 
			
		||||
AR          =@AR@
 | 
			
		||||
CFLAGS      =@CFLAGS@
 | 
			
		||||
EXTRA_CFLAGS=@EXTRA_CFLAGS@
 | 
			
		||||
LDFLAGS     =@LDFLAGS@ 
 | 
			
		||||
 | 
			
		||||
# Utilities called by the makefiles
 | 
			
		||||
INSTALL=@INSTALL@
 | 
			
		||||
MKDIR=@MKDIR@
 | 
			
		||||
RM=@RM@
 | 
			
		||||
CP=@CP@
 | 
			
		||||
LN=@LN@
 | 
			
		||||
TAR=@TAR@
 | 
			
		||||
RPMBUILD=@RPMBUILD@
 | 
			
		||||
SED=@SED@
 | 
			
		||||
FIND=@FIND@
 | 
			
		||||
XARGS=@XARGS@
 | 
			
		||||
DIRNAME=@DIRNAME@
 | 
			
		||||
 | 
			
		||||
# C compiler for building utilities to use
 | 
			
		||||
# during the build
 | 
			
		||||
BUILD_CC=@BUILD_CC@
 | 
			
		||||
BUILD_CFLAGS=@BUILD_CFLAGS@  $(DEFS)
 | 
			
		||||
							
								
								
									
										73
									
								
								News
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								News
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
* 2.0
 | 
			
		||||
  - In purgatory added -fno-zero-initialized-in-bss to prevent issues with
 | 
			
		||||
    recent versions of gcc
 | 
			
		||||
  - Add an option to configure to disable zlib support
 | 
			
		||||
  - Add mismatched architecture support
 | 
			
		||||
  - Updated the x86 architecture help
 | 
			
		||||
  - Updated the x86_64 architecture help
 | 
			
		||||
  - Fixed bzImage support
 | 
			
		||||
  - Added support for finding either the highest or lowest usable window.
 | 
			
		||||
  - Change the version number to 2.0 to reflect the major change in
 | 
			
		||||
    the code base.  1.99 was effectively the release canidate.
 | 
			
		||||
* 1.99
 | 
			
		||||
  - Rearchitect so the code is maintainable.
 | 
			
		||||
  - Add multiboot support
 | 
			
		||||
  - Add ia64 support
 | 
			
		||||
  - Add beoboot image support
 | 
			
		||||
  - Create generic elf loader code.
 | 
			
		||||
  - Created the relocated shared object purgatory to hold
 | 
			
		||||
    the code that runs between kernels.
 | 
			
		||||
  - Added a configure script
 | 
			
		||||
  - Added an rpm target
 | 
			
		||||
  - Added kexec on panic support
 | 
			
		||||
  - Initial stab at adding documentation
 | 
			
		||||
  - Added loader support for ET_DYN objects
 | 
			
		||||
* 1.98
 | 
			
		||||
  - Add mysteriously dropped changes to make x86_64 work
 | 
			
		||||
  - Update the distclean target to remove *.orig and *~ files
 | 
			
		||||
* 1.97 
 | 
			
		||||
  - Add support for cross compiling x86_64
 | 
			
		||||
* 1.96
 | 
			
		||||
  - add x86_64 support
 | 
			
		||||
  - add support for linux style arguments to the elf32-x86 loader
 | 
			
		||||
  - disable clearing of cr4 on x86
 | 
			
		||||
* 1.95
 | 
			
		||||
  - add kexec-zImage-ppc64.c source file
 | 
			
		||||
  - GameCube/PPC32 sync'ed to 1.94
 | 
			
		||||
  - use syscall() to call sys_kexec_load() and reboot()
 | 
			
		||||
  - add kexec-syscall.h, remove kexec-syscall.c
 | 
			
		||||
  - makefiles know about ARCH-es
 | 
			
		||||
  - add noifdown kexec option (Albert Herranz)
 | 
			
		||||
* 1.94
 | 
			
		||||
  - revert a bad 1.92 change (not setting optind & opterr for subsequent
 | 
			
		||||
    calls to getopt_long())
 | 
			
		||||
* 1.93
 | 
			
		||||
  - restored "shutdown" functionality;
 | 
			
		||||
  - more help/usage text clarification;
 | 
			
		||||
  - add GPLv2 license to source files (with permission from Eric Biederman)
 | 
			
		||||
* 1.92
 | 
			
		||||
  - my_kexec(): call kexec() only one time;
 | 
			
		||||
  - add "unload" option;
 | 
			
		||||
  - fix some compiler warnings about "<var> might be used uninitialized";
 | 
			
		||||
  - commented out shutdown capability since it was unreachable;
 | 
			
		||||
* 1.91
 | 
			
		||||
  - fix "-t" option: strcmp() was inverted (Albert Herranz)
 | 
			
		||||
  - check specified kernel image file for file type (Albert Herranz)
 | 
			
		||||
* 1.9
 | 
			
		||||
  - change reboot function to return type long (was int)
 | 
			
		||||
  - use kexec reserved syscall numbers (in Linux 2.6.6-mm3)
 | 
			
		||||
* 1.8
 | 
			
		||||
  - Fixed bug where ramdisk wasn't loaded when specified
 | 
			
		||||
  - Memory information is now read from /proc/iomem.
 | 
			
		||||
    Information that is not needed is ignored.
 | 
			
		||||
* 1.7
 | 
			
		||||
  - Update to new tentative syscall number....
 | 
			
		||||
* 1.6
 | 
			
		||||
  - Redo all of the command line arguments.
 | 
			
		||||
  - Use the 32-bit kernel entry point.
 | 
			
		||||
  - Work around a failure to clear %cr4.
 | 
			
		||||
* 1.5
 | 
			
		||||
  - Port to a new kernel interface (Hopefully the final one).
 | 
			
		||||
  - Start working on setting up legacy hardware
 | 
			
		||||
  - Add --load and --exec options so the parts can be done at different times.
 | 
			
		||||
###
 | 
			
		||||
							
								
								
									
										11
									
								
								TODO
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								TODO
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
- Restore enough state that DOS/arbitrary BIOS calls can be run on some
 | 
			
		||||
  platforms.  Currently disk-related calls are quite likely to blow up.
 | 
			
		||||
- x86 filling in other kernel parameters.
 | 
			
		||||
- Merge reboot via kexec functionality into /sbin/reboot
 | 
			
		||||
- In the kexec-on-panic case preserving memory the both kernels
 | 
			
		||||
  must use.
 | 
			
		||||
- Finish the kexec-on-panic case.
 | 
			
		||||
- Improve the documentation 
 | 
			
		||||
- Add support for loading a boot sector
 | 
			
		||||
- Autobuilding of initramfs
 | 
			
		||||
###
 | 
			
		||||
							
								
								
									
										1441
									
								
								config/config.guess
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										1441
									
								
								config/config.guess
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1552
									
								
								config/config.sub
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										1552
									
								
								config/config.sub
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										251
									
								
								config/install-sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										251
									
								
								config/install-sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,251 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# install - install a program, script, or datafile
 | 
			
		||||
# This comes from X11R5 (mit/util/scripts/install.sh).
 | 
			
		||||
#
 | 
			
		||||
# Copyright 1991 by the Massachusetts Institute of Technology
 | 
			
		||||
#
 | 
			
		||||
# Permission to use, copy, modify, distribute, and sell this software and its
 | 
			
		||||
# documentation for any purpose is hereby granted without fee, provided that
 | 
			
		||||
# the above copyright notice appear in all copies and that both that
 | 
			
		||||
# copyright notice and this permission notice appear in supporting
 | 
			
		||||
# documentation, and that the name of M.I.T. not be used in advertising or
 | 
			
		||||
# publicity pertaining to distribution of the software without specific,
 | 
			
		||||
# written prior permission.  M.I.T. makes no representations about the
 | 
			
		||||
# suitability of this software for any purpose.  It is provided "as is"
 | 
			
		||||
# without express or implied warranty.
 | 
			
		||||
#
 | 
			
		||||
# Calling this script install-sh is preferred over install.sh, to prevent
 | 
			
		||||
# `make' implicit rules from creating a file called install from it
 | 
			
		||||
# when there is no Makefile.
 | 
			
		||||
#
 | 
			
		||||
# This script is compatible with the BSD install script, but was written
 | 
			
		||||
# from scratch.  It can only install one file at a time, a restriction
 | 
			
		||||
# shared with many OS's install programs.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# set DOITPROG to echo to test this script
 | 
			
		||||
 | 
			
		||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
 | 
			
		||||
doit="${DOITPROG-}"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# put in absolute paths if you don't have them in your path; or use env. vars.
 | 
			
		||||
 | 
			
		||||
mvprog="${MVPROG-mv}"
 | 
			
		||||
cpprog="${CPPROG-cp}"
 | 
			
		||||
chmodprog="${CHMODPROG-chmod}"
 | 
			
		||||
chownprog="${CHOWNPROG-chown}"
 | 
			
		||||
chgrpprog="${CHGRPPROG-chgrp}"
 | 
			
		||||
stripprog="${STRIPPROG-strip}"
 | 
			
		||||
rmprog="${RMPROG-rm}"
 | 
			
		||||
mkdirprog="${MKDIRPROG-mkdir}"
 | 
			
		||||
 | 
			
		||||
transformbasename=""
 | 
			
		||||
transform_arg=""
 | 
			
		||||
instcmd="$mvprog"
 | 
			
		||||
chmodcmd="$chmodprog 0755"
 | 
			
		||||
chowncmd=""
 | 
			
		||||
chgrpcmd=""
 | 
			
		||||
stripcmd=""
 | 
			
		||||
rmcmd="$rmprog -f"
 | 
			
		||||
mvcmd="$mvprog"
 | 
			
		||||
src=""
 | 
			
		||||
dst=""
 | 
			
		||||
dir_arg=""
 | 
			
		||||
 | 
			
		||||
while [ x"$1" != x ]; do
 | 
			
		||||
    case $1 in
 | 
			
		||||
	-c) instcmd="$cpprog"
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	-d) dir_arg=true
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	-m) chmodcmd="$chmodprog $2"
 | 
			
		||||
	    shift
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	-o) chowncmd="$chownprog $2"
 | 
			
		||||
	    shift
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	-g) chgrpcmd="$chgrpprog $2"
 | 
			
		||||
	    shift
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	-s) stripcmd="$stripprog"
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
 | 
			
		||||
	*)  if [ x"$src" = x ]
 | 
			
		||||
	    then
 | 
			
		||||
		src=$1
 | 
			
		||||
	    else
 | 
			
		||||
		# this colon is to work around a 386BSD /bin/sh bug
 | 
			
		||||
		:
 | 
			
		||||
		dst=$1
 | 
			
		||||
	    fi
 | 
			
		||||
	    shift
 | 
			
		||||
	    continue;;
 | 
			
		||||
    esac
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
if [ x"$src" = x ]
 | 
			
		||||
then
 | 
			
		||||
	echo "install:	no input file specified"
 | 
			
		||||
	exit 1
 | 
			
		||||
else
 | 
			
		||||
	true
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ x"$dir_arg" != x ]; then
 | 
			
		||||
	dst=$src
 | 
			
		||||
	src=""
 | 
			
		||||
	
 | 
			
		||||
	if [ -d $dst ]; then
 | 
			
		||||
		instcmd=:
 | 
			
		||||
		chmodcmd=""
 | 
			
		||||
	else
 | 
			
		||||
		instcmd=mkdir
 | 
			
		||||
	fi
 | 
			
		||||
else
 | 
			
		||||
 | 
			
		||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
 | 
			
		||||
# might cause directories to be created, which would be especially bad 
 | 
			
		||||
# if $src (and thus $dsttmp) contains '*'.
 | 
			
		||||
 | 
			
		||||
	if [ -f $src -o -d $src ]
 | 
			
		||||
	then
 | 
			
		||||
		true
 | 
			
		||||
	else
 | 
			
		||||
		echo "install:  $src does not exist"
 | 
			
		||||
		exit 1
 | 
			
		||||
	fi
 | 
			
		||||
	
 | 
			
		||||
	if [ x"$dst" = x ]
 | 
			
		||||
	then
 | 
			
		||||
		echo "install:	no destination specified"
 | 
			
		||||
		exit 1
 | 
			
		||||
	else
 | 
			
		||||
		true
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
# If destination is a directory, append the input filename; if your system
 | 
			
		||||
# does not like double slashes in filenames, you may need to add some logic
 | 
			
		||||
 | 
			
		||||
	if [ -d $dst ]
 | 
			
		||||
	then
 | 
			
		||||
		dst="$dst"/`basename $src`
 | 
			
		||||
	else
 | 
			
		||||
		true
 | 
			
		||||
	fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
## this sed command emulates the dirname command
 | 
			
		||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
 | 
			
		||||
 | 
			
		||||
# Make sure that the destination directory exists.
 | 
			
		||||
#  this part is taken from Noah Friedman's mkinstalldirs script
 | 
			
		||||
 | 
			
		||||
# Skip lots of stat calls in the usual case.
 | 
			
		||||
if [ ! -d "$dstdir" ]; then
 | 
			
		||||
defaultIFS='	
 | 
			
		||||
'
 | 
			
		||||
IFS="${IFS-${defaultIFS}}"
 | 
			
		||||
 | 
			
		||||
oIFS="${IFS}"
 | 
			
		||||
# Some sh's can't handle IFS=/ for some reason.
 | 
			
		||||
IFS='%'
 | 
			
		||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
 | 
			
		||||
IFS="${oIFS}"
 | 
			
		||||
 | 
			
		||||
pathcomp=''
 | 
			
		||||
 | 
			
		||||
while [ $# -ne 0 ] ; do
 | 
			
		||||
	pathcomp="${pathcomp}${1}"
 | 
			
		||||
	shift
 | 
			
		||||
 | 
			
		||||
	if [ ! -d "${pathcomp}" ] ;
 | 
			
		||||
        then
 | 
			
		||||
		$mkdirprog "${pathcomp}"
 | 
			
		||||
	else
 | 
			
		||||
		true
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
	pathcomp="${pathcomp}/"
 | 
			
		||||
done
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ x"$dir_arg" != x ]
 | 
			
		||||
then
 | 
			
		||||
	$doit $instcmd $dst &&
 | 
			
		||||
 | 
			
		||||
	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
 | 
			
		||||
	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
 | 
			
		||||
	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
 | 
			
		||||
	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
 | 
			
		||||
else
 | 
			
		||||
 | 
			
		||||
# If we're going to rename the final executable, determine the name now.
 | 
			
		||||
 | 
			
		||||
	if [ x"$transformarg" = x ] 
 | 
			
		||||
	then
 | 
			
		||||
		dstfile=`basename $dst`
 | 
			
		||||
	else
 | 
			
		||||
		dstfile=`basename $dst $transformbasename | 
 | 
			
		||||
			sed $transformarg`$transformbasename
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
# don't allow the sed command to completely eliminate the filename
 | 
			
		||||
 | 
			
		||||
	if [ x"$dstfile" = x ] 
 | 
			
		||||
	then
 | 
			
		||||
		dstfile=`basename $dst`
 | 
			
		||||
	else
 | 
			
		||||
		true
 | 
			
		||||
	fi
 | 
			
		||||
 | 
			
		||||
# Make a temp file name in the proper directory.
 | 
			
		||||
 | 
			
		||||
	dsttmp=$dstdir/#inst.$$#
 | 
			
		||||
 | 
			
		||||
# Move or copy the file name to the temp name
 | 
			
		||||
 | 
			
		||||
	$doit $instcmd $src $dsttmp &&
 | 
			
		||||
 | 
			
		||||
	trap "rm -f ${dsttmp}" 0 &&
 | 
			
		||||
 | 
			
		||||
# and set any options; do chmod last to preserve setuid bits
 | 
			
		||||
 | 
			
		||||
# If any of these fail, we abort the whole thing.  If we want to
 | 
			
		||||
# ignore errors from any of these, just make sure not to ignore
 | 
			
		||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
 | 
			
		||||
 | 
			
		||||
	if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
 | 
			
		||||
	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
 | 
			
		||||
	if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
 | 
			
		||||
	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
 | 
			
		||||
 | 
			
		||||
# Now rename the file to the real destination.
 | 
			
		||||
 | 
			
		||||
	$doit $rmcmd -f $dstdir/$dstfile &&
 | 
			
		||||
	$doit $mvcmd $dsttmp $dstdir/$dstfile 
 | 
			
		||||
 | 
			
		||||
fi &&
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
exit 0
 | 
			
		||||
							
								
								
									
										129
									
								
								configure.ac
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								configure.ac
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
			
		||||
dnl 
 | 
			
		||||
dnl configure.ac for mkelfImage
 | 
			
		||||
dnl 
 | 
			
		||||
dnl 
 | 
			
		||||
 | 
			
		||||
dnl ---Required
 | 
			
		||||
AC_INIT(Makefile.conf.in)
 | 
			
		||||
AC_CONFIG_AUX_DIR(./config)
 | 
			
		||||
 | 
			
		||||
dnl -- Compilation platform configuration
 | 
			
		||||
AC_CANONICAL_HOST
 | 
			
		||||
dnl Currentl AC_CANONICAL_HOST is sufficient for my needs
 | 
			
		||||
dnl as there are only a small number of targets that kexec
 | 
			
		||||
dnl can support on a given host system.  If it stops making
 | 
			
		||||
dnl sense compile support for all possible targets a given
 | 
			
		||||
dnl host can support AC_CANONICAL_TARGET may help
 | 
			
		||||
dnl AC_CANONICAL_TARGET
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dnl Compute host cpu
 | 
			
		||||
case $host_cpu in 
 | 
			
		||||
	i?86 )	
 | 
			
		||||
		host_cpu="i386"
 | 
			
		||||
		;;
 | 
			
		||||
	powerpc )
 | 
			
		||||
		host_cpu="ppc"
 | 
			
		||||
		;;
 | 
			
		||||
	* ) 
 | 
			
		||||
		host_cpu="$host_cpu"
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
case $host_cpu in
 | 
			
		||||
	i386|ppc|x86_64|alpha|ppc64|ia64)
 | 
			
		||||
		;;
 | 
			
		||||
	* )
 | 
			
		||||
		AC_MSG_ERROR([ unsupported architecture $host_cpu])
 | 
			
		||||
		;;
 | 
			
		||||
esac
 | 
			
		||||
ARCH=$host_cpu
 | 
			
		||||
 | 
			
		||||
dnl ---Options
 | 
			
		||||
 | 
			
		||||
OBJDIR=`pwd`/objdir
 | 
			
		||||
if test "${host_alias}" ; then
 | 
			
		||||
	OBJDIR="$OBJDIR-${host_alias}"
 | 
			
		||||
fi 
 | 
			
		||||
EXTRA_CFLAGS=""
 | 
			
		||||
AC_ARG_WITH([objdir], AC_HELP_STRING([--with-objdir=<dir>],[select directory for object files]),
 | 
			
		||||
	[ OBJDIR="$withval" ], [ OBJDIR="$OBJDIR" ])
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH([gamecube], AC_HELP_STRING([--with-gamecube],[enable gamecube support]),
 | 
			
		||||
	[ EXTRA_CFLAGS="$EXTRA_CFLAGS -DCONFIG_GAMECUBE=1" ])
 | 
			
		||||
 | 
			
		||||
AC_ARG_WITH([zlib], AC_HELP_STRING([--without-zlib],[disable gamecube support]),
 | 
			
		||||
	[ with_zlib="$withval"], [ with_zlib=yes ] )
 | 
			
		||||
 | 
			
		||||
dnl ---Programs
 | 
			
		||||
dnl To specify a different compiler, just 'export CC=/path/to/compiler'
 | 
			
		||||
 | 
			
		||||
AC_PROG_CC
 | 
			
		||||
 | 
			
		||||
if test "${build}" != "${host}" ; then
 | 
			
		||||
	BUILD_CC=${CC_FOR_BUILD-gcc}
 | 
			
		||||
else
 | 
			
		||||
	BUILD_CC="\$(CC)"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dnl Find the compiler tool chain
 | 
			
		||||
AC_PROG_CPP
 | 
			
		||||
AC_CHECK_TOOL([LD], ld, "no", $PATH)
 | 
			
		||||
AC_CHECK_TOOL([AS], as, "no", $PATH)
 | 
			
		||||
AC_CHECK_TOOL([OBJCOPY], objcopy, "no", $PATH)
 | 
			
		||||
AC_CHECK_TOOL([AR], ar, "", $PATH)
 | 
			
		||||
 | 
			
		||||
dnl Find the helper functions
 | 
			
		||||
AC_PROG_INSTALL
 | 
			
		||||
AC_CHECK_PROG([MKDIR],    mkdir,    mkdir,    "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([RM],       rm,       rm,       "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([CP],       cp,       cp,       "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([LN],       ln,       ln,       "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([TAR],      tar,      tar,      "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([RPMBUILD], rpmbuild, rpmbuild, "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([SED],      sed,      sed,      "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([FIND],     find,     find,     "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([XARGS],    xargs,    xargs,    "no", [$PATH])
 | 
			
		||||
AC_CHECK_PROG([DIRNAME],  dirname,  dirname,  "no", [$PATH])
 | 
			
		||||
 | 
			
		||||
dnl See if I have a usable copy of zlib available
 | 
			
		||||
if test "$with_zlib" = yes ; then
 | 
			
		||||
	AC_CHECK_HEADER(zlib.h, AC_CHECK_LIB(z, inflateInit_, [AC_DEFINE(HAVE_ZLIB_H, 1) LIBS="$LIBS -lz"]))
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
dnl ---Hard codes
 | 
			
		||||
 | 
			
		||||
CFLAGS='-Wall -g -fno-strict-aliasing $(CPPFLAGS)'
 | 
			
		||||
BUILD_CFLAGS='-O2 -Wall $(CPPFLAGS)'
 | 
			
		||||
 | 
			
		||||
dnl ---Sanity checks
 | 
			
		||||
if test "$CC"      = "no"; then AC_MSG_ERROR([cc not found]) fi
 | 
			
		||||
if test "$CPP"     = "no"; then AC_MSG_ERROR([cpp not found]) fi
 | 
			
		||||
if test "$LD"      = "no"; then AC_MSG_ERROR([ld not found]) fi
 | 
			
		||||
if test "$AS"      = "no"; then AC_MSG_ERROR([as not found]) fi
 | 
			
		||||
if test "$OBJCOPY" = "no"; then	AC_MSG_ERROR([objcopy not found]) fi
 | 
			
		||||
if test "$AR"      = "no"; then	AC_MSG_ERROR([ar not found]) fi
 | 
			
		||||
 | 
			
		||||
if test "$MKDIR"   = "no"; then AC_MSG_ERROR([ mkdir not found]) fi 
 | 
			
		||||
if test "$RM"      = "no"; then AC_MSG_ERROR([ rm not found]) fi    
 | 
			
		||||
if test "$CP"      = "no"; then AC_MSG_ERROR([ cp not found]) fi    
 | 
			
		||||
if test "$LN"      = "no"; then AC_MSG_ERROR([ ln not found]) fi    
 | 
			
		||||
if test "$TAR"     = "no"; then AC_MSG_ERROR([ tar not found]) fi   
 | 
			
		||||
if test "$RPM"     = "no"; then AC_MSG_ERROR([ rpm not found]) fi   
 | 
			
		||||
if test "$SED"     = "no"; then AC_MSG_ERROR([ sed not found]) fi   
 | 
			
		||||
if test "$FIND"    = "no"; then AC_MSG_ERROR([ find not found]) fi  
 | 
			
		||||
if test "$XARGS"   = "no"; then AC_MSG_ERROR([ xargs not found]) fi 
 | 
			
		||||
if test "$DIRNAME" = "no"; then AC_MSG_ERROR([ dirname not found]) fi 
 | 
			
		||||
 | 
			
		||||
dnl ---Output variables...
 | 
			
		||||
 | 
			
		||||
AC_SUBST([BUILD_CC])
 | 
			
		||||
AC_SUBST([BUILD_CFLAGS])
 | 
			
		||||
 | 
			
		||||
AC_SUBST([EXTRA_CFLAGS])
 | 
			
		||||
AC_SUBST([ARCH])
 | 
			
		||||
AC_SUBST([OBJDIR])
 | 
			
		||||
AC_SUBST([INSTALL])
 | 
			
		||||
 | 
			
		||||
dnl ---Output
 | 
			
		||||
AC_OUTPUT([Makefile.conf])
 | 
			
		||||
							
								
								
									
										438
									
								
								doc/linux-i386-boot.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										438
									
								
								doc/linux-i386-boot.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,438 @@
 | 
			
		||||
		     THE LINUX/I386 BOOT PROTOCOL
 | 
			
		||||
		     ----------------------------
 | 
			
		||||
 | 
			
		||||
		    H. Peter Anvin <hpa@zytor.com>
 | 
			
		||||
			Last update 2002-01-01
 | 
			
		||||
 | 
			
		||||
On the i386 platform, the Linux kernel uses a rather complicated boot
 | 
			
		||||
convention.  This has evolved partially due to historical aspects, as
 | 
			
		||||
well as the desire in the early days to have the kernel itself be a
 | 
			
		||||
bootable image, the complicated PC memory model and due to changed
 | 
			
		||||
expectations in the PC industry caused by the effective demise of
 | 
			
		||||
real-mode DOS as a mainstream operating system.
 | 
			
		||||
 | 
			
		||||
Currently, four versions of the Linux/i386 boot protocol exist.
 | 
			
		||||
 | 
			
		||||
Old kernels:	zImage/Image support only.  Some very early kernels
 | 
			
		||||
		may not even support a command line.
 | 
			
		||||
 | 
			
		||||
Protocol 2.00:	(Kernel 1.3.73) Added bzImage and initrd support, as
 | 
			
		||||
		well as a formalized way to communicate between the
 | 
			
		||||
		boot loader and the kernel.  setup.S made relocatable,
 | 
			
		||||
		although the traditional setup area still assumed
 | 
			
		||||
		writable.
 | 
			
		||||
 | 
			
		||||
Protocol 2.01:	(Kernel 1.3.76) Added a heap overrun warning.
 | 
			
		||||
 | 
			
		||||
Protocol 2.02:	(Kernel 2.4.0-test3-pre3) New command line protocol.
 | 
			
		||||
		Lower the conventional memory ceiling.	No overwrite
 | 
			
		||||
		of the traditional setup area, thus making booting
 | 
			
		||||
		safe for systems which use the EBDA from SMM or 32-bit
 | 
			
		||||
		BIOS entry points.  zImage deprecated but still
 | 
			
		||||
		supported.
 | 
			
		||||
 | 
			
		||||
Protocol 2.03:	(Kernel 2.4.18-pre1) Explicitly makes the highest possible
 | 
			
		||||
		initrd address available to the bootloader.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** MEMORY LAYOUT
 | 
			
		||||
 | 
			
		||||
The traditional memory map for the kernel loader, used for Image or
 | 
			
		||||
zImage kernels, typically looks like:
 | 
			
		||||
 | 
			
		||||
	|			 |
 | 
			
		||||
0A0000	+------------------------+
 | 
			
		||||
	|  Reserved for BIOS	 |	Do not use.  Reserved for BIOS EBDA.
 | 
			
		||||
09A000	+------------------------+
 | 
			
		||||
	|  Stack/heap/cmdline	 |	For use by the kernel real-mode code.
 | 
			
		||||
098000	+------------------------+	
 | 
			
		||||
	|  Kernel setup		 |	The kernel real-mode code.
 | 
			
		||||
090200	+------------------------+
 | 
			
		||||
	|  Kernel boot sector	 |	The kernel legacy boot sector.
 | 
			
		||||
090000	+------------------------+
 | 
			
		||||
	|  Protected-mode kernel |	The bulk of the kernel image.
 | 
			
		||||
010000	+------------------------+
 | 
			
		||||
	|  Boot loader		 |	<- Boot sector entry point 0000:7C00
 | 
			
		||||
001000	+------------------------+
 | 
			
		||||
	|  Reserved for MBR/BIOS |
 | 
			
		||||
000800	+------------------------+
 | 
			
		||||
	|  Typically used by MBR |
 | 
			
		||||
000600	+------------------------+ 
 | 
			
		||||
	|  BIOS use only	 |
 | 
			
		||||
000000	+------------------------+
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
When using bzImage, the protected-mode kernel was relocated to
 | 
			
		||||
0x100000 ("high memory"), and the kernel real-mode block (boot sector,
 | 
			
		||||
setup, and stack/heap) was made relocatable to any address between
 | 
			
		||||
0x10000 and end of low memory.	Unfortunately, in protocols 2.00 and
 | 
			
		||||
2.01 the command line is still required to live in the 0x9XXXX memory
 | 
			
		||||
range, and that memory range is still overwritten by the early kernel.
 | 
			
		||||
The 2.02 protocol resolves that problem.
 | 
			
		||||
 | 
			
		||||
It is desirable to keep the "memory ceiling" -- the highest point in
 | 
			
		||||
low memory touched by the boot loader -- as low as possible, since
 | 
			
		||||
some newer BIOSes have begun to allocate some rather large amounts of
 | 
			
		||||
memory, called the Extended BIOS Data Area, near the top of low
 | 
			
		||||
memory.	 The boot loader should use the "INT 12h" BIOS call to verify
 | 
			
		||||
how much low memory is available.
 | 
			
		||||
 | 
			
		||||
Unfortunately, if INT 12h reports that the amount of memory is too
 | 
			
		||||
low, there is usually nothing the boot loader can do but to report an
 | 
			
		||||
error to the user.  The boot loader should therefore be designed to
 | 
			
		||||
take up as little space in low memory as it reasonably can.  For
 | 
			
		||||
zImage or old bzImage kernels, which need data written into the
 | 
			
		||||
0x90000 segment, the boot loader should make sure not to use memory
 | 
			
		||||
above the 0x9A000 point; too many BIOSes will break above that point.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** THE REAL-MODE KERNEL HEADER
 | 
			
		||||
 | 
			
		||||
In the following text, and anywhere in the kernel boot sequence, "a
 | 
			
		||||
sector" refers to 512 bytes.  It is independent of the actual sector
 | 
			
		||||
size of the underlying medium.
 | 
			
		||||
 | 
			
		||||
The first step in loading a Linux kernel should be to load the
 | 
			
		||||
real-mode code (boot sector and setup code) and then examine the
 | 
			
		||||
following header at offset 0x01f1.  The real-mode code can total up to
 | 
			
		||||
32K, although the boot loader may choose to load only the first two
 | 
			
		||||
sectors (1K) and then examine the bootup sector size.
 | 
			
		||||
 | 
			
		||||
The header looks like:
 | 
			
		||||
 | 
			
		||||
Offset	Proto	Name		Meaning
 | 
			
		||||
/Size
 | 
			
		||||
 | 
			
		||||
01F1/1	ALL	setup_sects	The size of the setup in sectors
 | 
			
		||||
01F2/2	ALL	root_flags	If set, the root is mounted readonly
 | 
			
		||||
01F4/2	ALL	syssize		DO NOT USE - for bootsect.S use only
 | 
			
		||||
01F6/2	ALL	swap_dev	DO NOT USE - obsolete
 | 
			
		||||
01F8/2	ALL	ram_size	DO NOT USE - for bootsect.S use only
 | 
			
		||||
01FA/2	ALL	vid_mode	Video mode control
 | 
			
		||||
01FC/2	ALL	root_dev	Default root device number
 | 
			
		||||
01FE/2	ALL	boot_flag	0xAA55 magic number
 | 
			
		||||
0200/2	2.00+	jump		Jump instruction
 | 
			
		||||
0202/4	2.00+	header		Magic signature "HdrS"
 | 
			
		||||
0206/2	2.00+	version		Boot protocol version supported
 | 
			
		||||
0208/4	2.00+	realmode_swtch	Boot loader hook (see below)
 | 
			
		||||
020C/2	2.00+	start_sys	The load-low segment (0x1000) (obsolete)
 | 
			
		||||
020E/2	2.00+	kernel_version	Pointer to kernel version string
 | 
			
		||||
0210/1	2.00+	type_of_loader	Boot loader identifier
 | 
			
		||||
0211/1	2.00+	loadflags	Boot protocol option flags
 | 
			
		||||
0212/2	2.00+	setup_move_size	Move to high memory size (used with hooks)
 | 
			
		||||
0214/4	2.00+	code32_start	Boot loader hook (see below)
 | 
			
		||||
0218/4	2.00+	ramdisk_image	initrd load address (set by boot loader)
 | 
			
		||||
021C/4	2.00+	ramdisk_size	initrd size (set by boot loader)
 | 
			
		||||
0220/4	2.00+	bootsect_kludge	DO NOT USE - for bootsect.S use only
 | 
			
		||||
0224/2	2.01+	heap_end_ptr	Free memory after setup end
 | 
			
		||||
0226/2	N/A	pad1		Unused
 | 
			
		||||
0228/4	2.02+	cmd_line_ptr	32-bit pointer to the kernel command line
 | 
			
		||||
022C/4	2.03+	initrd_addr_max	Highest legal initrd address
 | 
			
		||||
 | 
			
		||||
For backwards compatibility, if the setup_sects field contains 0, the
 | 
			
		||||
real value is 4.
 | 
			
		||||
 | 
			
		||||
If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
 | 
			
		||||
the boot protocol version is "old".  Loading an old kernel, the
 | 
			
		||||
following parameters should be assumed:
 | 
			
		||||
 | 
			
		||||
	Image type = zImage
 | 
			
		||||
	initrd not supported
 | 
			
		||||
	Real-mode kernel must be located at 0x90000.
 | 
			
		||||
 | 
			
		||||
Otherwise, the "version" field contains the protocol version,
 | 
			
		||||
e.g. protocol version 2.01 will contain 0x0201 in this field.  When
 | 
			
		||||
setting fields in the header, you must make sure only to set fields
 | 
			
		||||
supported by the protocol version in use.
 | 
			
		||||
 | 
			
		||||
The "kernel_version" field, if set to a nonzero value, contains a
 | 
			
		||||
pointer to a null-terminated human-readable kernel version number
 | 
			
		||||
string, less 0x200.  This can be used to display the kernel version to
 | 
			
		||||
the user.  This value should be less than (0x200*setup_sects).  For
 | 
			
		||||
example, if this value is set to 0x1c00, the kernel version number
 | 
			
		||||
string can be found at offset 0x1e00 in the kernel file.  This is a
 | 
			
		||||
valid value if and only if the "setup_sects" field contains the value
 | 
			
		||||
14 or higher.
 | 
			
		||||
 | 
			
		||||
Most boot loaders will simply load the kernel at its target address
 | 
			
		||||
directly.  Such boot loaders do not need to worry about filling in
 | 
			
		||||
most of the fields in the header.  The following fields should be
 | 
			
		||||
filled out, however:
 | 
			
		||||
 | 
			
		||||
  vid_mode:
 | 
			
		||||
	Please see the section on SPECIAL COMMAND LINE OPTIONS.
 | 
			
		||||
 | 
			
		||||
  type_of_loader:
 | 
			
		||||
	If your boot loader has an assigned id (see table below), enter
 | 
			
		||||
	0xTV here, where T is an identifier for the boot loader and V is
 | 
			
		||||
	a version number.  Otherwise, enter 0xFF here.
 | 
			
		||||
 | 
			
		||||
	Assigned boot loader ids:
 | 
			
		||||
	0  LILO
 | 
			
		||||
	1  Loadlin
 | 
			
		||||
	2  bootsect-loader
 | 
			
		||||
	3  SYSLINUX
 | 
			
		||||
	4  EtherBoot
 | 
			
		||||
 | 
			
		||||
	Please contact <hpa@zytor.com> if you need a bootloader ID
 | 
			
		||||
	value assigned.
 | 
			
		||||
 | 
			
		||||
  loadflags, heap_end_ptr:
 | 
			
		||||
	If the protocol version is 2.01 or higher, enter the
 | 
			
		||||
	offset limit of the setup heap into heap_end_ptr and set the
 | 
			
		||||
	0x80 bit (CAN_USE_HEAP) of loadflags.  heap_end_ptr appears to
 | 
			
		||||
	be relative to the start of setup (offset 0x0200).
 | 
			
		||||
 | 
			
		||||
  setup_move_size: 
 | 
			
		||||
	When using protocol 2.00 or 2.01, if the real mode
 | 
			
		||||
	kernel is not loaded at 0x90000, it gets moved there later in
 | 
			
		||||
	the loading sequence.  Fill in this field if you want
 | 
			
		||||
	additional data (such as the kernel command line) moved in
 | 
			
		||||
	addition to the real-mode kernel itself.
 | 
			
		||||
 | 
			
		||||
  ramdisk_image, ramdisk_size:
 | 
			
		||||
	If your boot loader has loaded an initial ramdisk (initrd),
 | 
			
		||||
	set ramdisk_image to the 32-bit pointer to the ramdisk data
 | 
			
		||||
	and the ramdisk_size to the size of the ramdisk data.
 | 
			
		||||
 | 
			
		||||
	The initrd should typically be located as high in memory as
 | 
			
		||||
	possible, as it may otherwise get overwritten by the early
 | 
			
		||||
	kernel initialization sequence.	 However, it must never be
 | 
			
		||||
	located above the address specified in the initrd_addr_max
 | 
			
		||||
	field.	The initrd should be at least 4K page aligned.
 | 
			
		||||
 | 
			
		||||
  cmd_line_ptr:
 | 
			
		||||
	If the protocol version is 2.02 or higher, this is a 32-bit
 | 
			
		||||
	pointer to the kernel command line.  The kernel command line
 | 
			
		||||
	can be located anywhere between the end of setup and 0xA0000.
 | 
			
		||||
	Fill in this field even if your boot loader does not support a
 | 
			
		||||
	command line, in which case you can point this to an empty
 | 
			
		||||
	string (or better yet, to the string "auto".)  If this field
 | 
			
		||||
	is left at zero, the kernel will assume that your boot loader
 | 
			
		||||
	does not support the 2.02+ protocol.
 | 
			
		||||
 | 
			
		||||
  ramdisk_max:
 | 
			
		||||
	The maximum address that may be occupied by the initrd
 | 
			
		||||
	contents.  For boot protocols 2.02 or earlier, this field is
 | 
			
		||||
	not present, and the maximum address is 0x37FFFFFF.  (This
 | 
			
		||||
	address is defined as the address of the highest safe byte, so
 | 
			
		||||
	if your ramdisk is exactly 131072 bytes long and this field is
 | 
			
		||||
	0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** THE KERNEL COMMAND LINE
 | 
			
		||||
 | 
			
		||||
The kernel command line has become an important way for the boot
 | 
			
		||||
loader to communicate with the kernel.  Some of its options are also
 | 
			
		||||
relevant to the boot loader itself, see "special command line options"
 | 
			
		||||
below.
 | 
			
		||||
 | 
			
		||||
The kernel command line is a null-terminated string up to 255
 | 
			
		||||
characters long, plus the final null.
 | 
			
		||||
 | 
			
		||||
If the boot protocol version is 2.02 or later, the address of the
 | 
			
		||||
kernel command line is given by the header field cmd_line_ptr (see
 | 
			
		||||
above.)
 | 
			
		||||
 | 
			
		||||
If the protocol version is *not* 2.02 or higher, the kernel
 | 
			
		||||
command line is entered using the following protocol:
 | 
			
		||||
 | 
			
		||||
	At offset 0x0020 (word), "cmd_line_magic", enter the magic
 | 
			
		||||
	number 0xA33F.
 | 
			
		||||
 | 
			
		||||
	At offset 0x0022 (word), "cmd_line_offset", enter the offset
 | 
			
		||||
	of the kernel command line (relative to the start of the
 | 
			
		||||
	real-mode kernel).
 | 
			
		||||
	
 | 
			
		||||
	The kernel command line *must* be within the memory region
 | 
			
		||||
	covered by setup_move_size, so you may need to adjust this
 | 
			
		||||
	field.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** SAMPLE BOOT CONFIGURATION
 | 
			
		||||
 | 
			
		||||
As a sample configuration, assume the following layout of the real
 | 
			
		||||
mode segment:
 | 
			
		||||
 | 
			
		||||
	0x0000-0x7FFF	Real mode kernel
 | 
			
		||||
	0x8000-0x8FFF	Stack and heap
 | 
			
		||||
	0x9000-0x90FF	Kernel command line
 | 
			
		||||
 | 
			
		||||
Such a boot loader should enter the following fields in the header:
 | 
			
		||||
 | 
			
		||||
	unsigned long base_ptr;	/* base address for real-mode segment */
 | 
			
		||||
 | 
			
		||||
	if ( setup_sects == 0 ) {
 | 
			
		||||
		setup_sects = 4;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ( protocol >= 0x0200 ) {
 | 
			
		||||
		type_of_loader = <type code>;
 | 
			
		||||
		if ( loading_initrd ) {
 | 
			
		||||
			ramdisk_image = <initrd_address>;
 | 
			
		||||
			ramdisk_size = <initrd_size>;
 | 
			
		||||
		}
 | 
			
		||||
		if ( protocol >= 0x0201 ) {
 | 
			
		||||
			heap_end_ptr = 0x9000 - 0x200;
 | 
			
		||||
			loadflags |= 0x80; /* CAN_USE_HEAP */
 | 
			
		||||
		}
 | 
			
		||||
		if ( protocol >= 0x0202 ) {
 | 
			
		||||
			cmd_line_ptr = base_ptr + 0x9000;
 | 
			
		||||
		} else {
 | 
			
		||||
			cmd_line_magic	= 0xA33F;
 | 
			
		||||
			cmd_line_offset = 0x9000;
 | 
			
		||||
			setup_move_size = 0x9100;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Very old kernel */
 | 
			
		||||
 | 
			
		||||
		cmd_line_magic	= 0xA33F;
 | 
			
		||||
		cmd_line_offset = 0x9000;
 | 
			
		||||
 | 
			
		||||
		/* A very old kernel MUST have its real-mode code
 | 
			
		||||
		   loaded at 0x90000 */
 | 
			
		||||
 | 
			
		||||
		if ( base_ptr != 0x90000 ) {
 | 
			
		||||
			/* Copy the real-mode kernel */
 | 
			
		||||
			memcpy(0x90000, base_ptr, (setup_sects+1)*512);
 | 
			
		||||
			/* Copy the command line */
 | 
			
		||||
			memcpy(0x99000, base_ptr+0x9000, 256);
 | 
			
		||||
 | 
			
		||||
			base_ptr = 0x90000;		 /* Relocated */
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* It is recommended to clear memory up to the 32K mark */
 | 
			
		||||
		memset(0x90000 + (setup_sects+1)*512, 0,
 | 
			
		||||
		       (64-(setup_sects+1))*512);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** LOADING THE REST OF THE KERNEL
 | 
			
		||||
 | 
			
		||||
The non-real-mode kernel starts at offset (setup_sects+1)*512 in the
 | 
			
		||||
kernel file (again, if setup_sects == 0 the real value is 4.)  It
 | 
			
		||||
should be loaded at address 0x10000 for Image/zImage kernels and
 | 
			
		||||
0x100000 for bzImage kernels.
 | 
			
		||||
 | 
			
		||||
The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
 | 
			
		||||
bit (LOAD_HIGH) in the loadflags field is set:
 | 
			
		||||
 | 
			
		||||
	is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
 | 
			
		||||
	load_address = is_bzImage ? 0x100000 : 0x10000;
 | 
			
		||||
 | 
			
		||||
Note that Image/zImage kernels can be up to 512K in size, and thus use
 | 
			
		||||
the entire 0x10000-0x90000 range of memory.  This means it is pretty
 | 
			
		||||
much a requirement for these kernels to load the real-mode part at
 | 
			
		||||
0x90000.  bzImage kernels allow much more flexibility.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** SPECIAL COMMAND LINE OPTIONS
 | 
			
		||||
 | 
			
		||||
If the command line provided by the boot loader is entered by the
 | 
			
		||||
user, the user may expect the following command line options to work.
 | 
			
		||||
They should normally not be deleted from the kernel command line even
 | 
			
		||||
though not all of them are actually meaningful to the kernel.  Boot
 | 
			
		||||
loader authors who need additional command line options for the boot
 | 
			
		||||
loader itself should get them registered in
 | 
			
		||||
Documentation/kernel-parameters.txt to make sure they will not
 | 
			
		||||
conflict with actual kernel options now or in the future.
 | 
			
		||||
 | 
			
		||||
  vga=<mode>
 | 
			
		||||
	<mode> here is either an integer (in C notation, either
 | 
			
		||||
	decimal, octal, or hexadecimal) or one of the strings
 | 
			
		||||
	"normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
 | 
			
		||||
	(meaning 0xFFFD).  This value should be entered into the
 | 
			
		||||
	vid_mode field, as it is used by the kernel before the command
 | 
			
		||||
	line is parsed.
 | 
			
		||||
 | 
			
		||||
  mem=<size>
 | 
			
		||||
	<size> is an integer in C notation optionally followed by K, M
 | 
			
		||||
	or G (meaning << 10, << 20 or << 30).  This specifies the end
 | 
			
		||||
	of memory to the kernel. This affects the possible placement
 | 
			
		||||
	of an initrd, since an initrd should be placed near end of
 | 
			
		||||
	memory.  Note that this is an option to *both* the kernel and
 | 
			
		||||
	the bootloader!
 | 
			
		||||
 | 
			
		||||
  initrd=<file>
 | 
			
		||||
	An initrd should be loaded.  The meaning of <file> is
 | 
			
		||||
	obviously bootloader-dependent, and some boot loaders
 | 
			
		||||
	(e.g. LILO) do not have such a command.
 | 
			
		||||
 | 
			
		||||
In addition, some boot loaders add the following options to the
 | 
			
		||||
user-specified command line:
 | 
			
		||||
 | 
			
		||||
  BOOT_IMAGE=<file>
 | 
			
		||||
	The boot image which was loaded.  Again, the meaning of <file>
 | 
			
		||||
	is obviously bootloader-dependent.
 | 
			
		||||
 | 
			
		||||
  auto
 | 
			
		||||
	The kernel was booted without explicit user intervention.
 | 
			
		||||
 | 
			
		||||
If these options are added by the boot loader, it is highly
 | 
			
		||||
recommended that they are located *first*, before the user-specified
 | 
			
		||||
or configuration-specified command line.  Otherwise, "init=/bin/sh"
 | 
			
		||||
gets confused by the "auto" option.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** RUNNING THE KERNEL
 | 
			
		||||
 | 
			
		||||
The kernel is started by jumping to the kernel entry point, which is
 | 
			
		||||
located at *segment* offset 0x20 from the start of the real mode
 | 
			
		||||
kernel.  This means that if you loaded your real-mode kernel code at
 | 
			
		||||
0x90000, the kernel entry point is 9020:0000.
 | 
			
		||||
 | 
			
		||||
At entry, ds = es = ss should point to the start of the real-mode
 | 
			
		||||
kernel code (0x9000 if the code is loaded at 0x90000), sp should be
 | 
			
		||||
set up properly, normally pointing to the top of the heap, and
 | 
			
		||||
interrupts should be disabled.  Furthermore, to guard against bugs in
 | 
			
		||||
the kernel, it is recommended that the boot loader sets fs = gs = ds =
 | 
			
		||||
es = ss.
 | 
			
		||||
 | 
			
		||||
In our example from above, we would do:
 | 
			
		||||
 | 
			
		||||
	/* Note: in the case of the "old" kernel protocol, base_ptr must
 | 
			
		||||
	   be == 0x90000 at this point; see the previous sample code */
 | 
			
		||||
 | 
			
		||||
	seg = base_ptr >> 4;
 | 
			
		||||
 | 
			
		||||
	cli();	/* Enter with interrupts disabled! */
 | 
			
		||||
 | 
			
		||||
	/* Set up the real-mode kernel stack */
 | 
			
		||||
	_SS = seg;
 | 
			
		||||
	_SP = 0x9000;	/* Load SP immediately after loading SS! */
 | 
			
		||||
 | 
			
		||||
	_DS = _ES = _FS = _GS = seg;
 | 
			
		||||
	jmp_far(seg+0x20, 0);	/* Run the kernel */
 | 
			
		||||
 | 
			
		||||
If your boot sector accesses a floppy drive, it is recommended to
 | 
			
		||||
switch off the floppy motor before running the kernel, since the
 | 
			
		||||
kernel boot leaves interrupts off and thus the motor will not be
 | 
			
		||||
switched off, especially if the loaded kernel has the floppy driver as
 | 
			
		||||
a demand-loaded module!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**** ADVANCED BOOT TIME HOOKS
 | 
			
		||||
 | 
			
		||||
If the boot loader runs in a particularly hostile environment (such as
 | 
			
		||||
LOADLIN, which runs under DOS) it may be impossible to follow the
 | 
			
		||||
standard memory location requirements.  Such a boot loader may use the
 | 
			
		||||
following hooks that, if set, are invoked by the kernel at the
 | 
			
		||||
appropriate time.  The use of these hooks should probably be
 | 
			
		||||
considered an absolutely last resort!
 | 
			
		||||
 | 
			
		||||
IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
 | 
			
		||||
%edi across invocation.
 | 
			
		||||
 | 
			
		||||
  realmode_swtch:
 | 
			
		||||
	A 16-bit real mode far subroutine invoked immediately before
 | 
			
		||||
	entering protected mode.  The default routine disables NMI, so
 | 
			
		||||
	your routine should probably do so, too.
 | 
			
		||||
 | 
			
		||||
  code32_start:
 | 
			
		||||
	A 32-bit flat-mode routine *jumped* to immediately after the
 | 
			
		||||
	transition to protected mode, but before the kernel is
 | 
			
		||||
	uncompressed.  No segments, except CS, are set up; you should
 | 
			
		||||
	set them up to KERNEL_DS (0x18) yourself.
 | 
			
		||||
 | 
			
		||||
	After completing your hook, you should jump to the address
 | 
			
		||||
	that was in this field before your boot loader overwrote it.
 | 
			
		||||
							
								
								
									
										79
									
								
								doc/linux-i386-zero-page.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								doc/linux-i386-zero-page.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
Summary of boot_params layout (kernel point of view)
 | 
			
		||||
     ( collected by Hans Lermen and Martin Mares )
 | 
			
		||||
 
 | 
			
		||||
The contents of boot_params are used to pass parameters from the
 | 
			
		||||
16-bit realmode code of the kernel to the 32-bit part. References/settings
 | 
			
		||||
to it mainly are in:
 | 
			
		||||
 | 
			
		||||
  arch/i386/boot/setup.S
 | 
			
		||||
  arch/i386/boot/video.S
 | 
			
		||||
  arch/i386/kernel/head.S
 | 
			
		||||
  arch/i386/kernel/setup.c
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
Offset	Type		Description
 | 
			
		||||
------  ----		-----------
 | 
			
		||||
    0	32 bytes	struct screen_info, SCREEN_INFO
 | 
			
		||||
			ATTENTION, overlaps the following !!!
 | 
			
		||||
    2	unsigned short	EXT_MEM_K, extended memory size in Kb (from int 0x15)
 | 
			
		||||
 0x20	unsigned short	CL_MAGIC, commandline magic number (=0xA33F)
 | 
			
		||||
 0x22	unsigned short	CL_OFFSET, commandline offset
 | 
			
		||||
			Address of commandline is calculated:
 | 
			
		||||
			  0x90000 + contents of CL_OFFSET
 | 
			
		||||
			(only taken, when CL_MAGIC = 0xA33F)
 | 
			
		||||
 0x40	20 bytes	struct apm_bios_info, APM_BIOS_INFO
 | 
			
		||||
 0x60	16 bytes	Intel SpeedStep (IST) BIOS support information
 | 
			
		||||
 0x80	16 bytes	hd0-disk-parameter from intvector 0x41
 | 
			
		||||
 0x90	16 bytes	hd1-disk-parameter from intvector 0x46
 | 
			
		||||
 | 
			
		||||
 0xa0	16 bytes	System description table truncated to 16 bytes.
 | 
			
		||||
			( struct sys_desc_table_struct )
 | 
			
		||||
 0xb0 - 0x1c3		Free. Add more parameters here if you really need them.
 | 
			
		||||
 | 
			
		||||
0x1c4	unsigned long	EFI system table pointer
 | 
			
		||||
0x1c8	unsigned long	EFI memory descriptor size
 | 
			
		||||
0x1cc	unsigned long	EFI memory descriptor version
 | 
			
		||||
0x1d0	unsigned long	EFI memory descriptor map pointer
 | 
			
		||||
0x1d4	unsigned long	EFI memory descriptor map size
 | 
			
		||||
0x1e0	unsigned long	ALT_MEM_K, alternative mem check, in Kb
 | 
			
		||||
0x1e8	char		number of entries in E820MAP (below)
 | 
			
		||||
0x1e9	unsigned char	number of entries in EDDBUF (below)
 | 
			
		||||
0x1ea	unsigned char	number of entries in EDD_MBR_SIG_BUFFER (below)
 | 
			
		||||
0x1f1	char		size of setup.S, number of sectors
 | 
			
		||||
0x1f2	unsigned short	MOUNT_ROOT_RDONLY (if !=0)
 | 
			
		||||
0x1f4	unsigned short	size of compressed kernel-part in the
 | 
			
		||||
			(b)zImage-file (in 16 byte units, rounded up)
 | 
			
		||||
0x1f6	unsigned short	swap_dev (unused AFAIK)
 | 
			
		||||
0x1f8	unsigned short	RAMDISK_FLAGS
 | 
			
		||||
0x1fa	unsigned short	VGA-Mode (old one)
 | 
			
		||||
0x1fc	unsigned short	ORIG_ROOT_DEV (high=Major, low=minor)
 | 
			
		||||
0x1ff	char		AUX_DEVICE_INFO
 | 
			
		||||
 | 
			
		||||
0x200	short jump to start of setup code aka "reserved" field.
 | 
			
		||||
0x202	4 bytes		Signature for SETUP-header, ="HdrS"
 | 
			
		||||
0x206	unsigned short	Version number of header format
 | 
			
		||||
			Current version is 0x0201...
 | 
			
		||||
0x208	8 bytes		(used by setup.S for communication with boot loaders,
 | 
			
		||||
			 look there)
 | 
			
		||||
0x210	char		LOADER_TYPE, = 0, old one
 | 
			
		||||
			else it is set by the loader:
 | 
			
		||||
			0xTV: T=0 for LILO
 | 
			
		||||
				1 for Loadlin
 | 
			
		||||
				2 for bootsect-loader
 | 
			
		||||
				3 for SYSLINUX
 | 
			
		||||
				4 for ETHERBOOT
 | 
			
		||||
				V = version
 | 
			
		||||
0x211	char		loadflags:
 | 
			
		||||
			bit0 = 1: kernel is loaded high (bzImage)
 | 
			
		||||
			bit7 = 1: Heap and pointer (see below) set by boot
 | 
			
		||||
				  loader.
 | 
			
		||||
0x212	unsigned short	(setup.S)
 | 
			
		||||
0x214	unsigned long	KERNEL_START, where the loader started the kernel
 | 
			
		||||
0x218	unsigned long	INITRD_START, address of loaded ramdisk image
 | 
			
		||||
0x21c	unsigned long	INITRD_SIZE, size in bytes of ramdisk image
 | 
			
		||||
0x220	4 bytes		(setup.S)
 | 
			
		||||
0x224	unsigned short	setup.S heap end pointer
 | 
			
		||||
0x290 - 0x2cf		EDD_MBR_SIG_BUFFER (edd.S)
 | 
			
		||||
0x2d0 - 0x600		E820MAP
 | 
			
		||||
0x600 - 0x7ff		EDDBUF (edd.S) for disk signature read sector
 | 
			
		||||
0x600 - 0x7eb		EDDBUF (edd.S) for edd data
 | 
			
		||||
							
								
								
									
										664
									
								
								doc/multiboot.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										664
									
								
								doc/multiboot.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,664 @@
 | 
			
		||||
<HTML>
 | 
			
		||||
 | 
			
		||||
<HEAD>
 | 
			
		||||
<TITLE>Multiboot Standard</TITLE>
 | 
			
		||||
</HEAD>
 | 
			
		||||
 | 
			
		||||
<BODY>
 | 
			
		||||
 | 
			
		||||
<CENTER><H1>Multiboot Standard</H1></CENTER>
 | 
			
		||||
<CENTER><H3>Version 0.6</H3></CENTER>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2>Contents</H2>
 | 
			
		||||
 | 
			
		||||
<UL>
 | 
			
		||||
<LI> <A HREF="#motivation">Motivation</A>
 | 
			
		||||
<LI> <A HREF="#terminology">Terminology</A>
 | 
			
		||||
<LI> <A HREF="#scope">Scope and Requirements</A>
 | 
			
		||||
<LI> <A HREF="#details">Details</A>
 | 
			
		||||
<LI> <A HREF="#author">Authors</A>
 | 
			
		||||
<LI> <B>NOTE: The following items are not part of the standards document,
 | 
			
		||||
but are included for prospective OS and bootloader writers.</B>
 | 
			
		||||
<LI> <A HREF="#notes">Notes on PCs</A>
 | 
			
		||||
<LI> <A HREF="#example_os">Example OS Code</A>
 | 
			
		||||
<LI> <A HREF="#example_boot">Example Bootloader Code</A>
 | 
			
		||||
</UL>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME="motivation">Motivation</A></H2>
 | 
			
		||||
 | 
			
		||||
Every OS ever created tends to have its own boot loader.  Installing a new
 | 
			
		||||
OS on a machine generally involves installing a whole new set of boot
 | 
			
		||||
mechanisms, each with completely different install-time and boot-time user
 | 
			
		||||
interfaces.   Getting multiple operating systems to coexist reliably on one
 | 
			
		||||
machine through typical "chaining" mechanisms can be a nightmare.  There is
 | 
			
		||||
little or no choice of boot loaders for a particular operating system - if
 | 
			
		||||
the one that comes with the OS doesn't do exactly what you want, or doesn't
 | 
			
		||||
work on your machine, you're screwed.<P>
 | 
			
		||||
 | 
			
		||||
While we may not be able to fix this problem in existing commercial
 | 
			
		||||
operating systems, it shouldn't be too difficult for a few people in the
 | 
			
		||||
free OS communities to put their heads together and solve this problem for
 | 
			
		||||
the popular free operating systems.  That's what this standard aims for.
 | 
			
		||||
Basically, it specifies an interface between a boot loader and a operating
 | 
			
		||||
system, such that any complying boot loader should be able to load any
 | 
			
		||||
complying operating system.  This standard does NOT specify how boot
 | 
			
		||||
loaders should work - only how they must interface with the OS being
 | 
			
		||||
loaded.<P>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME="terminology">Terminology</A></H2>
 | 
			
		||||
 | 
			
		||||
Throughout this document, the term "boot loader" means whatever program or
 | 
			
		||||
set of programs loads the image of the final operating system to be run on
 | 
			
		||||
the machine.  The boot loader may itself consist of several stages, but
 | 
			
		||||
that is an implementation detail not relevant to this standard.  Only the
 | 
			
		||||
"final" stage of the boot loader - the stage that eventually transfers
 | 
			
		||||
control to the OS - needs to follow the rules specified in this document
 | 
			
		||||
in order to be "MultiBoot compliant"; earlier boot loader stages can be
 | 
			
		||||
designed in whatever way is most convenient.<P>
 | 
			
		||||
 | 
			
		||||
The term "OS image" is used to refer to the initial binary image that the
 | 
			
		||||
boot loader loads into memory and transfers control to to start the OS.
 | 
			
		||||
The OS image is typically an executable containing the OS kernel.<P>
 | 
			
		||||
 | 
			
		||||
The term "boot module" refers to other auxiliary files that the boot loader
 | 
			
		||||
loads into memory along with the OS image, but does not interpret in any
 | 
			
		||||
way other than passing their locations to the OS when it is invoked.<P>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME="scope">Scope and Requirements</A></H2>
 | 
			
		||||
 | 
			
		||||
<H3>Architectures</H3>
 | 
			
		||||
 | 
			
		||||
This standard is primarily targetted at PC's, since they are the most
 | 
			
		||||
common and have the largest variety of OS's and boot loaders.  However, to
 | 
			
		||||
the extent that certain other architectures may need a boot standard and do
 | 
			
		||||
not have one already, a variation of this standard, stripped of the
 | 
			
		||||
x86-specific details, could be adopted for them as well.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Operating systems</H3>
 | 
			
		||||
 | 
			
		||||
This standard is targetted toward free 32-bit operating systems that can be
 | 
			
		||||
fairly easily modified to support the standard without going through lots of
 | 
			
		||||
bureaucratic rigmarole.  The particular free OS's that this standard is
 | 
			
		||||
being primarily designed for are Linux, FreeBSD, NetBSD, Mach, and VSTa.
 | 
			
		||||
It is hoped that other emerging free OS's will adopt it from the start, and
 | 
			
		||||
thus immediately be able to take advantage of existing boot loaders.  It
 | 
			
		||||
would be nice if commercial operating system vendors eventually adopted
 | 
			
		||||
this standard as well, but that's probably a pipe dream.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Boot sources</H3>
 | 
			
		||||
 | 
			
		||||
It should be possible to write compliant boot loaders that
 | 
			
		||||
load the OS image from a variety of sources, including floppy disk, hard
 | 
			
		||||
disk, and across a network.<P>
 | 
			
		||||
 | 
			
		||||
Disk-based boot loaders may use a variety of techniques to find the
 | 
			
		||||
relevant OS image and boot module data on disk, such as by interpretation
 | 
			
		||||
of specific file systems (e.g. the BSD/Mach boot loader), using
 | 
			
		||||
precalculated "block lists" (e.g. LILO), loading from a special "boot
 | 
			
		||||
partition" (e.g. OS/2), or even loading from within another operating
 | 
			
		||||
system (e.g. the VSTa boot code, which loads from DOS).  Similarly,
 | 
			
		||||
network-based boot loaders could use a variety of network hardware and
 | 
			
		||||
protocols.<P>
 | 
			
		||||
 | 
			
		||||
It is hoped that boot loaders will be created that support multiple loading
 | 
			
		||||
mechanisms, increasing their portability, robustness, and
 | 
			
		||||
user-friendliness.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Boot-time configuration</H3>
 | 
			
		||||
 | 
			
		||||
It is often necessary for one reason or another for the user to be able to
 | 
			
		||||
provide some configuration information to the OS dynamically at boot time.
 | 
			
		||||
While this standard should not dictate how this configuration information
 | 
			
		||||
is obtained by the boot loader, it should provide a standard means for the
 | 
			
		||||
boot loader to pass such information to the OS.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Convenience to the OS</H3>
 | 
			
		||||
 | 
			
		||||
OS images should be easy to generate.  Ideally, an OS image should simply
 | 
			
		||||
be an ordinary 32-bit executable file in whatever file format the OS
 | 
			
		||||
normally uses.  It should be possible to 'nm' or disassemble OS images just
 | 
			
		||||
like normal executables.  Specialized tools should not be needed to create
 | 
			
		||||
OS images in a "special" file format.  If this means shifting some work
 | 
			
		||||
from the OS to the boot loader, that is probably appropriate, because all
 | 
			
		||||
the memory consumed by the boot loader will typically be made available
 | 
			
		||||
again after the boot process is created, whereas every bit of code in the
 | 
			
		||||
OS image typically has to remain in memory forever.  The OS should not have
 | 
			
		||||
to worry about getting into 32-bit mode initially, because mode switching
 | 
			
		||||
code generally needs to be in the boot loader anyway in order to load OS
 | 
			
		||||
data above the 1MB boundary, and forcing the OS to do this makes creation
 | 
			
		||||
of OS images much more difficult.<P>
 | 
			
		||||
 | 
			
		||||
Unfortunately, there is a horrendous variety of executable file formats
 | 
			
		||||
even among free Unix-like PC-based OS's - generally a different format for
 | 
			
		||||
each OS.  Most of the relevant free OS's use some variant of a.out format,
 | 
			
		||||
but some are moving to ELF.  It is highly desirable for boot loaders not to
 | 
			
		||||
have to be able to interpret all the different types of executable file
 | 
			
		||||
formats in existence in order to load the OS image - otherwise the boot
 | 
			
		||||
loader effectively becomes OS-specific again.<P>
 | 
			
		||||
 | 
			
		||||
This standard adopts a compromise solution to this problem.
 | 
			
		||||
MultiBoot compliant boot images always either (a) are in ELF format, or (b)
 | 
			
		||||
contain a "magic MultiBoot header", described below, which allows the boot
 | 
			
		||||
loader to load the image without having to understand numerous a.out
 | 
			
		||||
variants or other executable formats.  This magic header does not need
 | 
			
		||||
to be at the very beginning of the executable file, so kernel images can
 | 
			
		||||
still conform to the local a.out format variant in addition to being
 | 
			
		||||
MultiBoot compliant.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Boot modules</H3>
 | 
			
		||||
 | 
			
		||||
Many modern operating system kernels, such as those of VSTa and Mach, do
 | 
			
		||||
not by themselves contain enough mechanism to get the system fully
 | 
			
		||||
operational: they require the presence of additional software modules at
 | 
			
		||||
boot time in order to access devices, mount file systems, etc.  While these
 | 
			
		||||
additional modules could be embedded in the main OS image along with the
 | 
			
		||||
kernel itself, and the resulting image be split apart manually by the OS
 | 
			
		||||
when it receives control, it is often more flexible, more space-efficient,
 | 
			
		||||
and more convenient to the OS and user if the boot loader can load these
 | 
			
		||||
additional modules independently in the first place.<P>
 | 
			
		||||
 | 
			
		||||
Thus, this standard should provide a standard method for a boot loader to
 | 
			
		||||
indicate to the OS what auxiliary boot modules were loaded, and where they
 | 
			
		||||
can be found.  Boot loaders don't have to support multiple boot modules,
 | 
			
		||||
but they are strongly encouraged to, because some OS's will be unable to
 | 
			
		||||
boot without them.<P>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME="details">Details</H2>
 | 
			
		||||
 | 
			
		||||
There are three main aspects of the boot-loader/OS image interface this
 | 
			
		||||
standard must specify:<P>
 | 
			
		||||
 | 
			
		||||
<UL>
 | 
			
		||||
<LI>The format of the OS image as seen by the boot loader.
 | 
			
		||||
<LI>The state of the machine when the boot loader starts the OS.
 | 
			
		||||
<LI>The format of the information passed by the boot loader to the OS.
 | 
			
		||||
</UL>
 | 
			
		||||
 | 
			
		||||
<H3>OS Image Format</H3>
 | 
			
		||||
 | 
			
		||||
An OS image is generally just an ordinary 32-bit executable file in the
 | 
			
		||||
standard format for that particular OS, except that it may be linked at a
 | 
			
		||||
non-default load address to avoid loading on top of the PC's I/O region
 | 
			
		||||
or other reserved areas, and of course it can't use shared libraries or
 | 
			
		||||
other fancy features.  Initially, only images in a.out format are
 | 
			
		||||
supported; ELF support will probably later be specified in the standard.<P>
 | 
			
		||||
 | 
			
		||||
Unfortunately, the exact meaning of the text, data, bss, and entry fields
 | 
			
		||||
of a.out headers tends to vary widely between different executable flavors,
 | 
			
		||||
and it is sometimes very difficult to distinguish one flavor from another
 | 
			
		||||
(e.g. Linux ZMAGIC executables and Mach ZMAGIC executables).  Furthermore,
 | 
			
		||||
there is no simple, reliable way of determining at what address in memory
 | 
			
		||||
the text segment is supposed to start.  Therefore, this standard requires
 | 
			
		||||
that an additional header, known as a 'multiboot_header', appear somewhere
 | 
			
		||||
near the beginning of the executable file.  In general it should come "as
 | 
			
		||||
early as possible", and is typically embedded in the beginning of the text
 | 
			
		||||
segment after the "real" executable header.  It _must_ be contained
 | 
			
		||||
completely within the first 8192 bytes of the executable file, and must be
 | 
			
		||||
longword (32-bit) aligned.  These rules allow the boot loader to find and
 | 
			
		||||
synchronize with the text segment in the a.out file without knowing
 | 
			
		||||
beforehand the details of the a.out variant.  The layout of the header is
 | 
			
		||||
as follows:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
	+-------------------+
 | 
			
		||||
0	| magic: 0x1BADB002 |	(required)
 | 
			
		||||
4	| flags		    |	(required)
 | 
			
		||||
8	| checksum	    |	(required)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
8	| header_addr	    |	(present if flags[16] is set)
 | 
			
		||||
12	| load_addr	    |	(present if flags[16] is set)
 | 
			
		||||
16	| load_end_addr	    |	(present if flags[16] is set)
 | 
			
		||||
20	| bss_end_addr	    |	(present if flags[16] is set)
 | 
			
		||||
24	| entry_addr	    |	(present if flags[16] is set)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
All fields are in little-endian byte order, of course.  The first field is
 | 
			
		||||
the magic number identifying the header, which must be the hex value
 | 
			
		||||
0x1BADB002.<P>
 | 
			
		||||
 | 
			
		||||
The flags field specifies features that the OS image requests or requires
 | 
			
		||||
of the boot loader.  Bits 0-15 indicate requirements; if the boot loader
 | 
			
		||||
sees any of these bits set but doesn't understand the flag or can't fulfill
 | 
			
		||||
the requirements it indicates for some reason, it must notify the user and
 | 
			
		||||
fail to load the OS image.  Bits 16-31 indicate optional features; if any
 | 
			
		||||
bits in this range are set but the boot loader doesn't understand them, it
 | 
			
		||||
can simply ignore them and proceed as usual.  Naturally, all
 | 
			
		||||
as-yet-undefined bits in the flags word must be set to zero in OS
 | 
			
		||||
images.  This way, the flags fields serves for version control as well as
 | 
			
		||||
simple feature selection.<P>
 | 
			
		||||
 | 
			
		||||
If bit 0 in the flags word is set, then all boot modules loaded along with
 | 
			
		||||
the OS must be aligned on page (4KB) boundaries.  Some OS's expect to be
 | 
			
		||||
able to map the pages containing boot modules directly into a paged address
 | 
			
		||||
space during startup, and thus need the boot modules to be page-aligned.<P>
 | 
			
		||||
 | 
			
		||||
If bit 1 in the flags word is set, then information on available memory
 | 
			
		||||
via at least the 'mem_*' fields of the multiboot_info structure defined
 | 
			
		||||
below must be included.  If the bootloader is capable of passing a memory
 | 
			
		||||
map (the 'mmap_*' fields) and one exists, then it must be included as
 | 
			
		||||
well.<P>
 | 
			
		||||
 | 
			
		||||
If bit 16 in the flags word is set, then the fields at offsets 8-24 in the
 | 
			
		||||
multiboot_header are valid, and the boot loader should use them instead of
 | 
			
		||||
the fields in the actual executable header to calculate where to load the
 | 
			
		||||
OS image.  This information does not need to be provided if the kernel
 | 
			
		||||
image is in ELF format, but it should be provided if the images is in a.out
 | 
			
		||||
format or in some other format.  Compliant boot loaders must be able to
 | 
			
		||||
load images that either are in ELF format or contain the load address
 | 
			
		||||
information embedded in the multiboot_header; they may also directly
 | 
			
		||||
support other executable formats, such as particular a.out variants, but
 | 
			
		||||
are not required to.<P>
 | 
			
		||||
 | 
			
		||||
All of the address fields enabled by flag bit 16 are physical addresses.
 | 
			
		||||
The meaning of each is as follows:<P>
 | 
			
		||||
 | 
			
		||||
<UL>
 | 
			
		||||
<LI><B>header_addr</B> -- Contains the address corresponding to the
 | 
			
		||||
beginning of the multiboot_header - the physical memory location at which
 | 
			
		||||
the magic value is supposed to be loaded.  This field serves to "synchronize"
 | 
			
		||||
the mapping between OS image offsets and physical memory addresses.
 | 
			
		||||
<LI><B>load_addr</B> -- Contains the physical address of the beginning
 | 
			
		||||
of the text segment.  The offset in the OS image file at which to start
 | 
			
		||||
loading is defined by the offset at which the header was found, minus
 | 
			
		||||
(header_addr - load_addr).  load_addr must be less than or equal to
 | 
			
		||||
header_addr.
 | 
			
		||||
<LI><B>load_end_addr</B> -- Contains the physical address of the end of the
 | 
			
		||||
data segment.  (load_end_addr - load_addr) specifies how much data to load.
 | 
			
		||||
This implies that the text and data segments must be consecutive in the
 | 
			
		||||
OS image; this is true for existing a.out executable formats.
 | 
			
		||||
<LI><B>bss_end_addr</B> -- Contains the physical address of the end of
 | 
			
		||||
the bss segment.  The boot loader initializes this area to zero, and
 | 
			
		||||
reserves the memory it occupies to avoid placing boot modules and other
 | 
			
		||||
data relevant to the OS in that area.
 | 
			
		||||
<LI><B>entry</B> -- The physical address to which the boot loader should
 | 
			
		||||
jump in order to start running the OS.
 | 
			
		||||
</UL>
 | 
			
		||||
 | 
			
		||||
The checksum is a 32-bit unsigned value which, when added to
 | 
			
		||||
the other required fields, must have a 32-bit unsigned sum of zero.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Machine State</H3>
 | 
			
		||||
 | 
			
		||||
When the boot loader invokes the 32-bit operating system,
 | 
			
		||||
the machine must have the following state:<P>
 | 
			
		||||
 | 
			
		||||
<UL>
 | 
			
		||||
<LI>CS must be a 32-bit read/execute code segment with an offset of 0
 | 
			
		||||
and a limit of 0xffffffff.
 | 
			
		||||
<LI>DS, ES, FS, GS, and SS must be a 32-bit read/write data segment with
 | 
			
		||||
an offset of 0 and a limit of 0xffffffff.
 | 
			
		||||
<LI>The address 20 line must be usable for standard linear 32-bit
 | 
			
		||||
addressing of memory (in standard PC hardware, it is wired to
 | 
			
		||||
0 at bootup, forcing addresses in the 1-2 MB range to be mapped to the
 | 
			
		||||
0-1 MB range, 3-4 is mapped to 2-3, etc.).
 | 
			
		||||
<LI>Paging must be turned off.
 | 
			
		||||
<LI>The processor interrupt flag must be turned off.
 | 
			
		||||
<LI>EAX must contain the magic value 0x2BADB002; the presence of this value
 | 
			
		||||
indicates to the OS that it was loaded by a MultiBoot-compliant boot
 | 
			
		||||
loader (e.g. as opposed to another type of boot loader that the OS can
 | 
			
		||||
also be loaded from).
 | 
			
		||||
<LI>EBX must contain the 32-bit physical address of the multiboot_info
 | 
			
		||||
structure provided by the boot loader (see below).
 | 
			
		||||
</UL>
 | 
			
		||||
 | 
			
		||||
All other processor registers and flag bits are undefined.  This includes,
 | 
			
		||||
in particular:<P>
 | 
			
		||||
 | 
			
		||||
<UL>
 | 
			
		||||
<LI>ESP: the 32-bit OS must create its own stack as soon as it needs one.
 | 
			
		||||
<LI>GDTR: Even though the segment registers are set up as described above,
 | 
			
		||||
the GDTR may be invalid, so the OS must not load any segment registers
 | 
			
		||||
(even just reloading the same values!) until it sets up its own GDT.
 | 
			
		||||
<LI>IDTR: The OS must leave interrupts disabled until it sets up its own IDT.
 | 
			
		||||
</UL>
 | 
			
		||||
 | 
			
		||||
However, other machine state should be left by the boot loader in "normal
 | 
			
		||||
working order", i.e. as initialized by the BIOS (or DOS, if that's what
 | 
			
		||||
the boot loader runs from).  In other words, the OS should be able to make
 | 
			
		||||
BIOS calls and such after being loaded, as long as it does not overwrite
 | 
			
		||||
the BIOS data structures before doing so.  Also, the boot loader must leave
 | 
			
		||||
the PIC programmed with the normal BIOS/DOS values, even if it changed them
 | 
			
		||||
during the switch to 32-bit mode.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Boot Information Format</H3>
 | 
			
		||||
 | 
			
		||||
Upon entry to the OS, the EBX register contains the physical address of
 | 
			
		||||
a 'multiboot_info' data structure, through which the boot loader
 | 
			
		||||
communicates vital information to the OS.  The OS can use or ignore any
 | 
			
		||||
parts of the structure as it chooses; all information passed by the boot
 | 
			
		||||
loader is advisory only.<P>
 | 
			
		||||
 | 
			
		||||
The multiboot_info structure and its related substructures may be placed
 | 
			
		||||
anywhere in memory by the boot loader (with the exception of the memory
 | 
			
		||||
reserved for the kernel and boot modules, of course).  It is the OS's
 | 
			
		||||
responsibility to avoid overwriting this memory until it is done using it.<P>
 | 
			
		||||
 | 
			
		||||
The format of the multiboot_info structure (as defined so far) follows:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
	+-------------------+
 | 
			
		||||
0	| flags		    |	(required)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
4	| mem_lower	    |	(present if flags[0] is set)
 | 
			
		||||
8	| mem_upper	    |	(present if flags[0] is set)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
12	| boot_device	    |	(present if flags[1] is set)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
16	| cmdline	    |	(present if flags[2] is set)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
20	| mods_count	    |	(present if flags[3] is set)
 | 
			
		||||
24	| mods_addr	    |	(present if flags[3] is set)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
28 - 40 | syms		    |   (present if flags[4] or flags[5] is set)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
44	| mmap_length	    |	(present if flags[6] is set)
 | 
			
		||||
48	| mmap_addr	    |	(present if flags[6] is set)
 | 
			
		||||
	+-------------------+
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
The first longword indicates the presence and validity of other fields in
 | 
			
		||||
the multiboot_info structure.  All as-yet-undefined bits must be set to
 | 
			
		||||
zero by the boot loader.   Any set bits that the OS does not understand
 | 
			
		||||
should be ignored.  Thus, the flags field also functions as a version
 | 
			
		||||
indicator, allowing the multiboot_info structure to be expanded in the
 | 
			
		||||
future without breaking anything.<P>
 | 
			
		||||
 | 
			
		||||
If bit 0 in the multiboot_info.flags word is set, then the 'mem_*' fields
 | 
			
		||||
are valid.  'mem_lower' and 'mem_upper' indicate the amount of lower and upper
 | 
			
		||||
memory, respectively, in kilobytes.  Lower memory starts at address 0, and
 | 
			
		||||
upper memory starts at address 1 megabyte.  The maximum possible
 | 
			
		||||
value for lower memory is 640 kilobytes.  The value returned for upper
 | 
			
		||||
memory is maximally the address of the first upper memory hole minus
 | 
			
		||||
1 megabyte.  It is not guaranteed to be this value.<P>
 | 
			
		||||
 | 
			
		||||
If bit 1 in the multiboot_info.flags word is set, then the 'boot_device'
 | 
			
		||||
field is valid, and indicates which BIOS disk device the boot loader loaded
 | 
			
		||||
the OS from.  If the OS was not loaded from a BIOS disk, then this field
 | 
			
		||||
must not be present (bit 3 must be clear).  The OS may use this field as a
 | 
			
		||||
hint for determining its own "root" device, but is not required to.  The
 | 
			
		||||
boot_device field is layed out in four one-byte subfields as follows:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
	+-------+-------+-------+-------+
 | 
			
		||||
	| drive | part1 | part2 | part3 |
 | 
			
		||||
	+-------+-------+-------+-------+
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
The first byte contains the BIOS drive number as understood by the BIOS
 | 
			
		||||
INT 0x13 low-level disk interface: e.g. 0x00 for the first floppy disk or
 | 
			
		||||
0x80 for the first hard disk.<P>
 | 
			
		||||
 | 
			
		||||
The three remaining bytes specify the boot partition.  'part1' specifies
 | 
			
		||||
the "top-level" partition number, 'part2' specifies a "sub-partition" in
 | 
			
		||||
the top-level partition, etc.  Partition numbers always start from zero.
 | 
			
		||||
Unused partition bytes must be set to 0xFF.  For example, if the disk is
 | 
			
		||||
partitioned using a simple one-level DOS partitioning scheme, then 'part1'
 | 
			
		||||
contains the DOS partition number, and 'part2' and 'part3' are both zero.
 | 
			
		||||
As another example, if a disk is partitioned first into DOS partitions, and
 | 
			
		||||
then one of those DOS partitions is subdivided into several BSD partitions
 | 
			
		||||
using BSD's "disklabel" strategy, then 'part1' contains the DOS partition
 | 
			
		||||
number, 'part2' contains the BSD sub-partition within that DOS partition,
 | 
			
		||||
and 'part3' is 0xFF.<P>
 | 
			
		||||
 | 
			
		||||
DOS extended partitions are indicated as partition numbers starting from 4
 | 
			
		||||
and increasing, rather than as nested sub-partitions, even though the 
 | 
			
		||||
underlying disk layout of extended partitions is hierarchical in nature.
 | 
			
		||||
For example, if the boot loader boots from the second extended partition
 | 
			
		||||
on a disk partitioned in conventional DOS style, then 'part1' will be 5,
 | 
			
		||||
and 'part2' and 'part3' will both be 0xFF.<P>
 | 
			
		||||
 | 
			
		||||
If bit 2 of the flags longword is set, the 'cmdline' field is valid, and 
 | 
			
		||||
contains the physical address of the the command line to be passed to the
 | 
			
		||||
kernel.  The command line is a normal C-style null-terminated string.<P>
 | 
			
		||||
 | 
			
		||||
If bit 3 of the flags is set, then the 'mods' fields indicate to the kernel
 | 
			
		||||
what boot modules were loaded along with the kernel image, and where they
 | 
			
		||||
can be found.  'mods_count' contains the number of modules loaded;
 | 
			
		||||
'mods_addr' contains the physical address of the first module structure.
 | 
			
		||||
'mods_count' may be zero, indicating no boot modules were loaded, even if
 | 
			
		||||
bit 1 of 'flags' is set.  Each module structure is formatted as follows:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
	+-------------------+
 | 
			
		||||
0	| mod_start	    |
 | 
			
		||||
4	| mod_end	    |
 | 
			
		||||
	+-------------------+
 | 
			
		||||
8	| string	    |
 | 
			
		||||
	+-------------------+
 | 
			
		||||
12	| reserved (0)	    |
 | 
			
		||||
	+-------------------+
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
The first two fields contain the start and end addresses of the boot module
 | 
			
		||||
itself.  The 'string' field provides an arbitrary string to be associated
 | 
			
		||||
with that particular boot module; it is a null-terminated ASCII string,
 | 
			
		||||
just like the kernel command line.  The 'string' field may be 0 if there is
 | 
			
		||||
no string associated with the module.  Typically the string might be a
 | 
			
		||||
command line (e.g. if the OS treats boot modules as executable programs),
 | 
			
		||||
or a pathname (e.g. if the OS treats boot modules as files in a file
 | 
			
		||||
system), but its exact use is specific to the OS.  The 'reserved' field
 | 
			
		||||
must be set to 0 by the boot loader and ignored by the OS.<P>
 | 
			
		||||
 | 
			
		||||
NOTE:  Bits 4 & 5 are mutually exclusive.<P>
 | 
			
		||||
 | 
			
		||||
If bit 4 in the multiboot_info.flags word is set, then the following
 | 
			
		||||
fields in the multiboot_info structure starting at byte 28 are valid:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
	+-------------------+
 | 
			
		||||
28	| tabsize	    |
 | 
			
		||||
32	| strsize	    |
 | 
			
		||||
36	| addr		    |
 | 
			
		||||
40	| reserved (0)	    |
 | 
			
		||||
	+-------------------+
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
These indicate where the symbol table from an a.out kernel image can be
 | 
			
		||||
found.  'addr' is the physical address of the size (4-byte unsigned
 | 
			
		||||
long) of an array of a.out-format 'nlist' structures, followed immediately
 | 
			
		||||
by the array itself, then the size (4-byte unsigned long) of a set of
 | 
			
		||||
null-terminated ASCII strings (plus sizeof(unsigned long) in this case),
 | 
			
		||||
and finally the set of strings itself.  'tabsize' is equal to it's size
 | 
			
		||||
parameter (found at the beginning of the symbol section), and 'strsize'
 | 
			
		||||
is equal to it's size parameter (found at the beginning of the string section)
 | 
			
		||||
of the following string table to which the symbol table refers.   Note that
 | 
			
		||||
'tabsize' may be 0, indicating no symbols, even if bit 4 in the flags
 | 
			
		||||
word is set.<P>
 | 
			
		||||
 | 
			
		||||
If bit 5 in the multiboot_info.flags word is set, then the following
 | 
			
		||||
fields in the multiboot_info structure starting at byte 28 are valid:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
	+-------------------+
 | 
			
		||||
28	| num		    |
 | 
			
		||||
32	| size		    |
 | 
			
		||||
36	| addr		    |
 | 
			
		||||
40	| shndx		    |
 | 
			
		||||
	+-------------------+
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
These indicate where the section header table from an ELF kernel is, the
 | 
			
		||||
size of each entry, number of entries, and the string table used as the
 | 
			
		||||
index of names.  They correspond to the 'shdr_*' entries ('shdr_num', etc.)
 | 
			
		||||
in the Executable and Linkable Format (ELF) specification in the program
 | 
			
		||||
header.  All sections are loaded, and the physical address fields
 | 
			
		||||
of the elf section header then refer to where the sections are in memory
 | 
			
		||||
(refer to the i386 ELF documentation for details as to how to read the
 | 
			
		||||
section header(s)).  Note that 'shdr_num' may be 0, indicating no symbols,
 | 
			
		||||
even if bit 5 in the flags word is set.<P>
 | 
			
		||||
 | 
			
		||||
If bit 6 in the multiboot_info.flags word is set, then the 'mmap_*' fields
 | 
			
		||||
are valid, and indicate the address and length of a buffer containing a
 | 
			
		||||
memory map of the machine provided by the BIOS.  'mmap_addr' is the address,
 | 
			
		||||
and 'mmap_length' is the total size of the buffer.  The buffer consists of
 | 
			
		||||
one or more of the following size/structure pairs ('size' is really used
 | 
			
		||||
for skipping to the next pair):<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
	+-------------------+
 | 
			
		||||
-4	| size		    |
 | 
			
		||||
	+-------------------+
 | 
			
		||||
0	| BaseAddrLow	    |
 | 
			
		||||
4	| BaseAddrHigh	    |
 | 
			
		||||
8	| LengthLow	    |
 | 
			
		||||
12	| LengthHigh	    |
 | 
			
		||||
16	| Type		    |
 | 
			
		||||
	+-------------------+
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
where 'size' is the size of the associated structure in bytes, which can
 | 
			
		||||
be greater than the minimum of 20 bytes.  'BaseAddrLow' is the lower 32
 | 
			
		||||
bits of the starting address, and 'BaseAddrHigh' is the upper 32 bits,
 | 
			
		||||
for a total of a 64-bit starting address.  'LengthLow' is the lower 32 bits
 | 
			
		||||
of the size of the memory region in bytes, and 'LengthHigh' is the upper 32
 | 
			
		||||
bits, for a total of a 64-bit length.  'Type' is the variety of address
 | 
			
		||||
range represented, where a value of 1 indicates available RAM, and all
 | 
			
		||||
other values currently indicated a reserved area.<P>
 | 
			
		||||
 | 
			
		||||
The map provided is guaranteed to list all standard RAM that should
 | 
			
		||||
be available for normal use.<P>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME="author">Authors</A></H2>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
Bryan Ford
 | 
			
		||||
Computer Systems Laboratory
 | 
			
		||||
University of Utah
 | 
			
		||||
Salt Lake City, UT 84112
 | 
			
		||||
(801) 581-4280
 | 
			
		||||
baford@cs.utah.edu
 | 
			
		||||
 | 
			
		||||
Erich Stefan Boleyn
 | 
			
		||||
924 S.W. 16th Ave, #202
 | 
			
		||||
Portland, OR, USA  97205
 | 
			
		||||
(503) 226-0741
 | 
			
		||||
erich@uruk.org
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
We would also like to thank the many other people have provided comments,
 | 
			
		||||
ideas, information, and other forms of support for our work.<P>
 | 
			
		||||
 | 
			
		||||
<H3>Revision History</H3>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
Version 0.6   3/29/96  (a few wording changes, header checksum, and
 | 
			
		||||
                        clarification of machine state passed to the OS)
 | 
			
		||||
Version 0.5   2/23/96  (name change)
 | 
			
		||||
Version 0.4   2/1/96   (major changes plus HTMLification)
 | 
			
		||||
Version 0.3   12/23/95
 | 
			
		||||
Version 0.2   10/22/95
 | 
			
		||||
Version 0.1   6/26/95
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME="notes">Notes on PCs</A></H2>
 | 
			
		||||
 | 
			
		||||
In reference to bit 0 of the multiboot_info.flags parameter,
 | 
			
		||||
if the bootloader
 | 
			
		||||
in question uses older BIOS interfaces, or the newest ones are not
 | 
			
		||||
available (see description about bit 6), then a maximum of either
 | 
			
		||||
15 or 63 megabytes of memory may be reported.  It is HIGHLY recommended
 | 
			
		||||
that bootloaders perform a thorough memory probe.<P>
 | 
			
		||||
 | 
			
		||||
In reference to bit 1 of the multiboot_info.flags parameter, it is
 | 
			
		||||
recognized that determination of which BIOS drive maps to which
 | 
			
		||||
OS-level device-driver is non-trivial, at best.  Many kludges have
 | 
			
		||||
been made to various OSes instead of solving this problem, most of
 | 
			
		||||
them breaking under many conditions.  To encourage the use of
 | 
			
		||||
general-purpose solutions to this problem, here are 2
 | 
			
		||||
<A HREF=bios_mapping.txt>BIOS Device Mapping Techniques</A>.<P>
 | 
			
		||||
 | 
			
		||||
In reference to bit 6 of the multiboot_info.flags parameter, it is
 | 
			
		||||
important to note that the data structure used there
 | 
			
		||||
(starting with 'BaseAddrLow') is the data returned by the
 | 
			
		||||
<A HREF=mem64mb.html>INT 15h, AX=E820h
 | 
			
		||||
- Query System Address Map</A> call.  More information
 | 
			
		||||
on reserved memory regions is defined on that web page.
 | 
			
		||||
The interface here is meant to allow a bootloader to
 | 
			
		||||
work unmodified with any reasonable extensions of the BIOS interface,
 | 
			
		||||
passing along any extra data to be interpreted by the OS as desired.<P>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME="example_os">Example OS Code</A> (from Bryan Ford)</H2>
 | 
			
		||||
 | 
			
		||||
EDITOR'S NOTE:  These examples are relevant to the Proposal version 0.5,
 | 
			
		||||
which is basically identical except for the multiboot OS header, which was
 | 
			
		||||
missing the checksum.  A patch to bring Mach4 UK22 up to version 0.6 is
 | 
			
		||||
available in the GRUB FTP area mentioned in the
 | 
			
		||||
<A HREF="#example_boot">Example Bootloader Code</A> section below.<P>
 | 
			
		||||
 | 
			
		||||
The Mach 4 distribution, available by anonymous FTP from
 | 
			
		||||
flux.cs.utah.edu:/flux, contains a C header file that defines the
 | 
			
		||||
MultiBoot data structures described above; anyone is welcome to rip it
 | 
			
		||||
out and use it for other boot loaders and OS's:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
        mach4-i386/include/mach/machine/multiboot.h
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
This distribution also contains code implementing a "Linux boot adaptor",
 | 
			
		||||
which collects a MultiBoot-compliant OS image and an optional set of boot
 | 
			
		||||
modules, compresses them, and packages them into a single traditional Linux
 | 
			
		||||
boot image that can be loaded from LILO or other Linux boot loaders.  There
 | 
			
		||||
is also a corresponding "BSD boot adaptor" which can be used to wrap a
 | 
			
		||||
MultiBoot kernel and set of modules and produce an image that can be loaded
 | 
			
		||||
from the FreeBSD and NetBSD boot loaders.  All of this code can be used as-is
 | 
			
		||||
or as a basis for other boot loaders.  These are the directories of primary
 | 
			
		||||
relevance:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
        mach4-i386/boot
 | 
			
		||||
        mach4-i386/boot/bsd
 | 
			
		||||
        mach4-i386/boot/linux
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
The Mach kernel itself in this distribution contains code that demonstrates
 | 
			
		||||
how to create a compliant OS.  The following files are of primary
 | 
			
		||||
relevance:<P>
 | 
			
		||||
 | 
			
		||||
<pre>
 | 
			
		||||
        mach4-i386/kernel/i386at/boothdr.S
 | 
			
		||||
        mach4-i386/kernel/i386at/model_dep.c
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
Finally, I have created patches against the Linux 1.2.2 and FreeBSD 2.0
 | 
			
		||||
kernels, in order to make them compliant with this proposed standard.
 | 
			
		||||
These patches are available in kahlua.cs.utah.edu:/private/boot.<P>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<H2><A NAME"example_boot">Example Bootloader Code</A> (from Erich Boleyn)</H2>
 | 
			
		||||
 | 
			
		||||
The <A HREF=http://www.uruk.org/grub/>GRUB</A> bootloader project
 | 
			
		||||
will be fully
 | 
			
		||||
Multiboot-compliant, supporting all required and optional
 | 
			
		||||
features present in this standard.<P>
 | 
			
		||||
 | 
			
		||||
A final release has not been made, but both the GRUB beta release
 | 
			
		||||
(which is quite stable) and a patch for Multiboot version 0.6 for
 | 
			
		||||
Mach4 UK22 are available in the GRUB
 | 
			
		||||
<A HREF=ftp://ftp.uruk.org/public/grub/>public release</A>
 | 
			
		||||
area.<P>
 | 
			
		||||
 | 
			
		||||
<HR>
 | 
			
		||||
 | 
			
		||||
<A HREF=mailto:erich@uruk.org><I>erich@uruk.org</I></A><P>
 | 
			
		||||
 | 
			
		||||
</BODY>
 | 
			
		||||
</HTML>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										660
									
								
								doc/nbi-spec.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										660
									
								
								doc/nbi-spec.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,660 @@
 | 
			
		||||
  Draft Net Boot Image Proposal 0.3
 | 
			
		||||
  Jamie Honan and Gero Kuhlmann, gero@minix.han.de
 | 
			
		||||
  June 15, 1997
 | 
			
		||||
 | 
			
		||||
  This is the specification of the "tagged image" format
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
  Table of Contents
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  1. Note
 | 
			
		||||
 | 
			
		||||
  2. Preamble - the why
 | 
			
		||||
 | 
			
		||||
  3. The target
 | 
			
		||||
 | 
			
		||||
  4. Net Boot Process Description.
 | 
			
		||||
 | 
			
		||||
  5. Image Format with Initial Magic Number.
 | 
			
		||||
 | 
			
		||||
  6. Boot prom entry points.
 | 
			
		||||
 | 
			
		||||
  7. Example of a boot image.
 | 
			
		||||
 | 
			
		||||
  8. Terms
 | 
			
		||||
 | 
			
		||||
  9. References
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
  11..  NNoottee
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  In order to provide more functionality to the boot rom code I changed
 | 
			
		||||
  Jamie's draft a little bit. All my changes are preceded and followed
 | 
			
		||||
  by ((ggkk)).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Gero Kuhlmann
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  22..  PPrreeaammbbllee -- tthhee wwhhyy
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Whilst researching what other boot proms do (at least those
 | 
			
		||||
  implementing TCP/IP protocols) it is clear that each 'does their own
 | 
			
		||||
  thing' in terms of what they expect in a boot image.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  If we could all agree on working toward an open standard, O/S
 | 
			
		||||
  suppliers and boot rom suppliers can build their products to this
 | 
			
		||||
  norm, and be confident that they will work with each other.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  This is a description of how I will implement the boot rom for Linux.
 | 
			
		||||
  I  believe it to be flexible enough for any OS that will be loaded
 | 
			
		||||
  when a PC boots from a network in the TCP/IP environment.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  It would be good if this could be turned into some form of standard.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  This is very much a first draft. I am inviting comment.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The ideas presented here should be independant of any implementation.
 | 
			
		||||
  In the end, where there is a conflict between the final of this draft,
 | 
			
		||||
  and an implementation, this description should prevail.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The terms I use are defined at the end.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ((ggkk))IMPORTANT NOTE: The scope of this document starts at the point
 | 
			
		||||
  where the net boot process gains control from the BIOS, to where the
 | 
			
		||||
  booted image reaches a state from which there is no return to the net
 | 
			
		||||
  boot program possible.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  33..  TThhee ttaarrggeett
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The target is to have a PC retrieve a boot image from a network in the
 | 
			
		||||
  TCP/IP environment.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ((ggkk))The boot may take place from a network adaptor rom, from a boot
 | 
			
		||||
  floppy.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  44..  NNeett BBoooott PPrroocceessss DDeessccrriippttiioonn..
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ((ggkk))The net boot process is started as a result of the PC boot
 | 
			
		||||
  process. The net boot program can reside on a rom, e.g. on an adaptor
 | 
			
		||||
  card, or in ram as a result of reading off disk.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The boot process may execute in any mode (e.g. 8086, 80386) it
 | 
			
		||||
  desires.  When it jumps to the start location in the boot image, it
 | 
			
		||||
  must be in 8086 mode and be capable of going into any mode supported
 | 
			
		||||
  by the underlying processor.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The image cannot be loaded into address spaces below 10000h, or
 | 
			
		||||
  between A0000h through FFFFFh, or between 98000h through 9FFFFh.
 | 
			
		||||
  ((ggkk))Only when the image is not going to return to the boot process,
 | 
			
		||||
  all the memory is available to it once it has been started, so it can
 | 
			
		||||
  relocate parts of itself to these areas.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The boot process must be capable of loading the image into all other
 | 
			
		||||
  memory locations. Specifically, where the machine supports this, this
 | 
			
		||||
  means memory over 100000h.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The net boot process must execute the bootp protocol, followed by the
 | 
			
		||||
  tftp protocol, as defined in the relevant rfc's.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The file name used in the tftp protocol must be that given by the
 | 
			
		||||
  bootp record.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  If less than 512 bytes are loaded, the net boot process attempts to
 | 
			
		||||
  display on the screen any ascii data at the start of the image. The
 | 
			
		||||
  net boot process then exits in the normal manner. For a boot prom,
 | 
			
		||||
  this will allow normal disk booting. ((ggkk))Reference to DOS deleted.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  When the first 512 bytes have been loaded, the boot process checks for
 | 
			
		||||
  an initial magic number, which is defined later. If this number is
 | 
			
		||||
  present, the net process continues loading under the control of the
 | 
			
		||||
  image format. The image, which is described later, tells the net boot
 | 
			
		||||
  process where to put this record and all subsequent data.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  If no initial magic number is present the net boot process checks for
 | 
			
		||||
  a second magic number at offset 510. If the magic number 510 = 55h,
 | 
			
		||||
  511 = AAh, then the net process continues. If this second magic number
 | 
			
		||||
  is not present, then the net boot process terminates the tftp
 | 
			
		||||
  protocol, displays an error message and exits in the normal manner.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  If no initial magic number is present and the second one is, the net
 | 
			
		||||
  boot process relocates the 512 bytes to location 7c00h. The net boot
 | 
			
		||||
  process continues to load any further image data to 10000h up. This
 | 
			
		||||
  data can overwrite the first 512 boot bytes. If the image reaches
 | 
			
		||||
  98000h, then any further data is continued to be loaded above 100000h.
 | 
			
		||||
  When all the data has been loaded, the net boot process jumps to
 | 
			
		||||
  location 0:7c00.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ((ggkk))When the net boot program calls the image, it places 2 far
 | 
			
		||||
  pointers onto the stack, in standard intel order (e.g.  segment:offset
 | 
			
		||||
  representation).  The first far pointer which immediately follows the
 | 
			
		||||
  return address on the stack, points to the loaded boot image header.
 | 
			
		||||
  The second far pointer which is placed above the first one, shows to
 | 
			
		||||
  the memory area where the net boot process saved the bootp reply.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  If the boot image is flagged as being returnable to the boot process,
 | 
			
		||||
  the boot program has to provide the boot image with interrupt vector
 | 
			
		||||
  78h. It's an interface to services provided by the net boot program
 | 
			
		||||
  (see below for further description).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  If the boot image is not flagged as being returnable to the boot
 | 
			
		||||
  process, before the boot image is called, the boot program has to set
 | 
			
		||||
  the system into a state in which it was before the net boot process
 | 
			
		||||
  has started.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  55..  IImmaaggee FFoorrmmaatt wwiitthh IInniittiiaall MMaaggiicc NNuummbbeerr..
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The first 512 bytes of the image file contain the image header, and
 | 
			
		||||
  image loading information records. This contains all the information
 | 
			
		||||
  needed by the net boot process as to where data is to be loaded.
 | 
			
		||||
 | 
			
		||||
  The magic number (in time-honoured tradition (well why not?)) is:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
          0 = 36h
 | 
			
		||||
          1 = 13h
 | 
			
		||||
          2 = 03h
 | 
			
		||||
          3 = 1Bh
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Apart from the two magic numbers, all words and double words are in PC
 | 
			
		||||
  native endian.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Including the initial magic number the header record is:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
          +---------------------+
 | 
			
		||||
          |                     |
 | 
			
		||||
          | Initial Magic No.   |  4 bytes
 | 
			
		||||
          +---------------------+
 | 
			
		||||
          |                     |
 | 
			
		||||
          | Flags and length    |  double word
 | 
			
		||||
          +---------------------+
 | 
			
		||||
          |                     |
 | 
			
		||||
          | Location Address    |  double word in ds:bx format
 | 
			
		||||
          +---------------------+
 | 
			
		||||
          |                     |
 | 
			
		||||
          | Execute Address     |  double word in cs:ip format
 | 
			
		||||
          +---------------------+
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The Location address is where to place the 512 bytes. The net boot
 | 
			
		||||
  process does this before loading the rest of the image. The location
 | 
			
		||||
  address cannot be one of the reserved locations mentioned above, but
 | 
			
		||||
  must be an address lower than 100000h.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The rest of the image must not overwrite these initial 512 bytes,
 | 
			
		||||
  placed at the required location. The writing of data by the net boot
 | 
			
		||||
  process into these 512 bytes is deprecated. These 512 bytes must be
 | 
			
		||||
  available for the image to interogate once it is loaded and running.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The execute address is the location in cs:ip of the initial
 | 
			
		||||
  instruction once the full image has been loaded. This must be lower
 | 
			
		||||
  than 100000h, since the initial instructions will be executed in 8086
 | 
			
		||||
  mode. When the jump (actaully a far call) is made to the boot image,
 | 
			
		||||
  the stack contains a far return address, with a far pointer parameter
 | 
			
		||||
  above that, pointing to the location of this header.
 | 
			
		||||
 | 
			
		||||
  The flags and length field is broken up in the following way:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 0 to 3 (lowest 4 bits) define the length of the non vendor header
 | 
			
		||||
  in double words. Currently the value is 4.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 4 to 7 define the length required by the vendor extra information
 | 
			
		||||
  in double words. A value of zero indicates no extra vendor
 | 
			
		||||
  information.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ((ggkk))Bit 8 is set if the boot image can return to the net boot process
 | 
			
		||||
  after execution. If this bit is not set the boot image does never
 | 
			
		||||
  return to the net boot process, and the net boot program has to set
 | 
			
		||||
  the system into a clean state before calling the boot image.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 9 to 31 are reserved for future use and must be set to zero.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  After this header, and any vendor header, come the image loading
 | 
			
		||||
  information records. These specify where data is to be loaded, how
 | 
			
		||||
  long it is, and communicates to the loaded image what sort of data it
 | 
			
		||||
  is.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The format of each image loading information record is :
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
            +---------------------+
 | 
			
		||||
            | Flags, tags and     |  double word
 | 
			
		||||
            | lengths             |
 | 
			
		||||
            +---------------------+
 | 
			
		||||
            |                     |
 | 
			
		||||
            | Load Address        |  double word
 | 
			
		||||
            +---------------------+
 | 
			
		||||
            |                     |
 | 
			
		||||
            | Image Length        |  double word
 | 
			
		||||
            +---------------------+
 | 
			
		||||
            |                     |
 | 
			
		||||
            | Memory Length       |  double word
 | 
			
		||||
            +---------------------+
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Each image loading information record follows the previous, or the
 | 
			
		||||
  header.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The memory length, image length and load address fields are unsigned
 | 
			
		||||
  32 numbers. They do not have the segment:offset format used by the
 | 
			
		||||
  8086.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The flags, tags and lengths field is broken up as follows:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 0 to 3 (lowest 4 bits) are the length of the non vendor part of
 | 
			
		||||
  this header in double words. Currently this value is 4.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 4 to 7 indicate the length of any vendor information, in double
 | 
			
		||||
  words.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 8 to 15 are for vendor's tags. The vendor tag is a private number
 | 
			
		||||
  that the loaded image can use to determine what sort of image is at
 | 
			
		||||
  this particular location.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 16 to 23 are for future expansion and should be set to zero.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 24 to 31 are for flags, which are defined later.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Vendors may place further information after this information record,
 | 
			
		||||
  and before the next. Each information record may have a different
 | 
			
		||||
  vendor length.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  There are two restrictions on vendor information.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  One is that the header and all information records that the net boot
 | 
			
		||||
  process is to use fall within the first 512 bytes.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The second restriction is that the net boot process must ignore all
 | 
			
		||||
  vendor additions. The net boot process may not overwrite vendor
 | 
			
		||||
  supplied information, or other undefined data in the initial 512
 | 
			
		||||
  bytes.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The flags are used to modify the load address field, and to indicate
 | 
			
		||||
  that this is the last information record that the net boot process
 | 
			
		||||
  should use.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bit 24 works in conjunction with bit 25 to specify the meaning of the
 | 
			
		||||
  load address.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
            B24    B25
 | 
			
		||||
 | 
			
		||||
             0     0    load address is an absolute 32 number
 | 
			
		||||
 | 
			
		||||
             1     0    add the load address to the location one past the last byte
 | 
			
		||||
                        of the memory area required by the last image loaded.
 | 
			
		||||
                        If the first image, then add to 512 plus the location
 | 
			
		||||
                        where the 512 bytes were placed
 | 
			
		||||
 | 
			
		||||
             0     1    subtract the load address from the one past the
 | 
			
		||||
                        last writeable location in memory. Thus 1 would
 | 
			
		||||
                        be the last location one could write in memory.
 | 
			
		||||
 | 
			
		||||
             1     1    load address is subtracted from the start of
 | 
			
		||||
                        the last image loaded. If the first image, then
 | 
			
		||||
                        subtract from the start of where the 512 bytes were
 | 
			
		||||
                        placed
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  (For convenience bit 24 is byte 0 of the flag field)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bit 26 is the end marker for the net boot process. It is set when this
 | 
			
		||||
  is the last information record the net boot process should look at.
 | 
			
		||||
  More records may be present, but the net boot process will not look at
 | 
			
		||||
  them. (Vendors can continue information records out past the 512
 | 
			
		||||
  boundary for private use in this manner).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The image length tells the net boot process how many bytes are to be
 | 
			
		||||
  loaded.  Zero is a valid value. This can be used to mark memory areas
 | 
			
		||||
  such as shared memory for interprocessor communication, flash eproms,
 | 
			
		||||
  data in eproms.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The image length can also be different from the memory length. This
 | 
			
		||||
  allows decompression programs to fluff up the kernel image. It also
 | 
			
		||||
  allows a file system to be larger then the loaded file system image.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Bits 27 through 31 are not defined as yet and must be set to zero
 | 
			
		||||
  until they are.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  66..  BBoooott pprroomm eennttrryy ppooiinnttss..
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ((ggkk))As mentioned above the net boot process has to provide interrupt
 | 
			
		||||
  78h as an entry point in case, the returnable flag (bit 9 of the flags
 | 
			
		||||
  field in the image header) of the boot image has been set.  When
 | 
			
		||||
  calling this interface interrupt, the caller has to load the AH
 | 
			
		||||
  register with a value indicating the type of operation requested:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
         00h  -  Installation check
 | 
			
		||||
                 Input:  none
 | 
			
		||||
                 Output: AX  -  returns the value 474Bh
 | 
			
		||||
                         BX  -  flags indicating what further services are
 | 
			
		||||
                                provided by the net boot program:
 | 
			
		||||
                                 Bit 0 - packet driver interface (see below)
 | 
			
		||||
                                 Bits 1 to 15 are unused and have to be zero
 | 
			
		||||
 | 
			
		||||
         01h  -  Cleanup and terminate the boot process services. This will
 | 
			
		||||
                 also remove the services provided by interrupt 87h.
 | 
			
		||||
                 Input:  none
 | 
			
		||||
                 Output: none
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Further functions are not yet defined. These functions are only
 | 
			
		||||
  available to boot images which have the first magic number at the
 | 
			
		||||
  beginning of the image header, and have the returnable flag set in the
 | 
			
		||||
  flags field.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  In order to provide compatibility with net boot programs written to
 | 
			
		||||
  match an earlier version of this document, the loaded image should
 | 
			
		||||
  check for the existence of interrupt 78h by looking at it's vector. If
 | 
			
		||||
  that's 0:0, or if it does not return a proper magic ID after calling
 | 
			
		||||
  the installation check function, the boot image has to assume that the
 | 
			
		||||
  net boot program does not support this services interrupt.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  If the bit 0 of register BX of function 00h is set, the boot program
 | 
			
		||||
  has to provide a packet driver <http://www.crynwr.com> interface at
 | 
			
		||||
  interrupt 79h as described in the packet driver interface standard,
 | 
			
		||||
  version 1.09, published by FTP Software, Inc., which is not repeated
 | 
			
		||||
  here. It serves as an interface to the system's network card. It is
 | 
			
		||||
  important to note that the net boot process has to provide a clean
 | 
			
		||||
  packet driver interface without any handles being defined when the
 | 
			
		||||
  boot image gets started. It is expected that the boot image sets up
 | 
			
		||||
  it's own TCP/IP or other network's stack on top of this packet driver
 | 
			
		||||
  interface.  When the boot image returns to the net boot process, it
 | 
			
		||||
  has to return a clean packet driver interface as well, without any
 | 
			
		||||
  handles being defined.((ggkk))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  77..  EExxaammppllee ooff aa bboooott iimmaaggee..
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Here is an example of how the boot image would look for Linux:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
            0x1B031336,  /* magic number */
 | 
			
		||||
            0x4,         /* length of header is 16 bytes, no vendor info */
 | 
			
		||||
            0x90000000,  /* location in ds:bx format */
 | 
			
		||||
            0x90000200,  /* execute address in cs:ip format */
 | 
			
		||||
 | 
			
		||||
                         /* 2048 setup.S bytes */
 | 
			
		||||
            0x4,         /* flags, not end, absolute address, 16 bytes this
 | 
			
		||||
                            record, no vendor info */
 | 
			
		||||
            0x90200,     /* load address - note format */
 | 
			
		||||
            0x800,       /* 4 8 512 byte blocks for linux */
 | 
			
		||||
            0x800,
 | 
			
		||||
 | 
			
		||||
                         /* kernel image */
 | 
			
		||||
            0x4,         /* flags, not end, absolute address, 16 bytes this
 | 
			
		||||
                            record, no vendor info */
 | 
			
		||||
            0x10000,     /* load address - note format */
 | 
			
		||||
            0x80000,     /* 512K (this could be shorter */
 | 
			
		||||
            0x80000,
 | 
			
		||||
 | 
			
		||||
                         /* ramdisk for root file system */
 | 
			
		||||
            0x04000004,  /* flags = last, absolute address, 16 bytes this
 | 
			
		||||
                            record, no vendor info *//
 | 
			
		||||
            0x100000,    /* load address - in extended memory */
 | 
			
		||||
            0x80000,     /* 512K for instance */
 | 
			
		||||
            0x80000,
 | 
			
		||||
 | 
			
		||||
                         /* Then follows linux specific information */
 | 
			
		||||
  ______________________________________________________________________
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  88..  TTeerrmmss
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  When I say 'the net boot process', I mean the act of loading the image
 | 
			
		||||
  into memory, setting up any tables, up until the jump to the required
 | 
			
		||||
  location in the image.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The net booting program executes the net boot process. The net boot
 | 
			
		||||
  program may be a rom, but not neccassarily. It is a set of
 | 
			
		||||
  instructions and data residing on the booting machine.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The image, or boot image,  consists of the data loaded by the net boot
 | 
			
		||||
  process.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  When I say 'the PC boot process', I mean the general PC rom bios boot
 | 
			
		||||
  process, the setting up of hardware, the scanning for adaptor roms,
 | 
			
		||||
  the execution of adaptor roms, the loading in of the initial boot
 | 
			
		||||
  track. The PC boot process will include the net boot process, if one
 | 
			
		||||
  is present.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  When I say client, I mean the PC booting up.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  When I say 'image host', I mean the host where the boot image is
 | 
			
		||||
  comming from.  This may not have the same architecture as the client.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  The bootp protocol is defined in RFC951 and RFC1084. The tftp protocol
 | 
			
		||||
  is defined in RFC783. These are available on many sites.  See Comer
 | 
			
		||||
  1991 for details on how to obtain them.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  A bootp server is the machine that answers the bootp request. It is
 | 
			
		||||
  not neccessarily the image host.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  "Can" and "may" means doesn't have to, but is allowed to and might.
 | 
			
		||||
  "Must" means just that. "Cannot" means must not.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  99..  RReeffeerreenncceess
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Comer, D.E. 1991, Internetworking with TCP/IP Vol I: Principles,
 | 
			
		||||
  Protocols, and Architecture Second Edition, Prentice Hall, Englewood
 | 
			
		||||
  Cliffs, N.J., 1991
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Stevens, W.R 1990, Unix Network Programming, Prentice Hall, Englewood
 | 
			
		||||
  Cliffs, N.J., 1990
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										39
									
								
								include/boot/beoboot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/boot/beoboot.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
 | 
			
		||||
/*--- Boot image definitions ---------------------------------------*/
 | 
			
		||||
struct beoboot_header {
 | 
			
		||||
    char magic[4];
 | 
			
		||||
    uint8_t  arch;
 | 
			
		||||
    uint8_t  flags;
 | 
			
		||||
    uint16_t cmdline_size;/* length of command line (including null) */
 | 
			
		||||
    /* The alpha chunk is a backward compatibility hack.  The original
 | 
			
		||||
     * assumption was that integer sizes didn't matter because we
 | 
			
		||||
     * would never mix architectures.  x86_64 + i386 broke that
 | 
			
		||||
     * assumption.  It's fixed for that combination and the future.
 | 
			
		||||
     * However, alpha needs a little hack now... */
 | 
			
		||||
#ifdef __alpha__
 | 
			
		||||
    unsigned long kernel_size;
 | 
			
		||||
    unsigned long initrd_size;
 | 
			
		||||
#else
 | 
			
		||||
    uint32_t kernel_size;
 | 
			
		||||
    uint32_t initrd_size;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
#define BEOBOOT_MAGIC     "BeoB"
 | 
			
		||||
#define BEOBOOT_ARCH_I386  1
 | 
			
		||||
#define BEOBOOT_ARCH_ALPHA 2
 | 
			
		||||
#define BEOBOOT_ARCH_PPC   3
 | 
			
		||||
#define BEOBOOT_ARCH_PPC64 4
 | 
			
		||||
#if defined(__i386__) || defined(__x86_64__)
 | 
			
		||||
#define BEOBOOT_ARCH BEOBOOT_ARCH_I386
 | 
			
		||||
#elif defined(__alpha__)
 | 
			
		||||
#define BEOBOOT_ARCH BEOBOOT_ARCH_ALPHA
 | 
			
		||||
#elif defined(powerpc)
 | 
			
		||||
#define BEOBOOT_ARCH BEOBOOT_ARCH_PPC
 | 
			
		||||
#elif defined(__powerpc64__)
 | 
			
		||||
#define BEOBOOT_ARCH BEOBOOT_ARCH_PPC64
 | 
			
		||||
#else
 | 
			
		||||
#error Unsupported architecture.
 | 
			
		||||
#endif
 | 
			
		||||
#define BEOBOOT_INITRD_PRESENT 1
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										104
									
								
								include/boot/elf_boot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								include/boot/elf_boot.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
#ifndef ELF_BOOT_H 
 | 
			
		||||
#define ELF_BOOT_H 
 | 
			
		||||
 | 
			
		||||
/* This defines the structure of a table of parameters useful for ELF
 | 
			
		||||
 * bootable images.  These parameters are all passed and generated
 | 
			
		||||
 * by the bootloader to the booted image.  For simplicity and
 | 
			
		||||
 * consistency the Elf Note format is reused.
 | 
			
		||||
 *
 | 
			
		||||
 * All of the information must be Position Independent Data.
 | 
			
		||||
 * That is it must be safe to relocate the whole ELF boot parameter
 | 
			
		||||
 * block without changing the meaning or correctnes of the data.
 | 
			
		||||
 * Additionally it must be safe to permute the order of the ELF notes
 | 
			
		||||
 * to any possible permutation without changing the meaning or correctness
 | 
			
		||||
 * of the data.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ELF_BOOT_MAGIC		0x0E1FB007
 | 
			
		||||
 | 
			
		||||
#ifndef ASSEMBLY
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
typedef uint16_t Elf_Half;
 | 
			
		||||
typedef uint32_t Elf_Word;
 | 
			
		||||
typedef uint64_t Elf_Xword;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Elf boot notes...
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct Elf_Bhdr
 | 
			
		||||
{
 | 
			
		||||
	Elf_Word b_signature; /* "0x0E1FB007" */
 | 
			
		||||
	Elf_Word b_size;
 | 
			
		||||
	Elf_Half b_checksum;
 | 
			
		||||
	Elf_Half b_records;
 | 
			
		||||
} Elf_Bhdr;
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * ELF Notes.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct Elf_Nhdr
 | 
			
		||||
{
 | 
			
		||||
	Elf_Word n_namesz;		/* Length of the note's name.  */
 | 
			
		||||
	Elf_Word n_descsz;		/* Length of the note's descriptor.  */
 | 
			
		||||
	Elf_Word n_type;		/* Type of the note.  */
 | 
			
		||||
} Elf_Nhdr;
 | 
			
		||||
 | 
			
		||||
#endif /* ASSEMBLY */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Standardized Elf image notes for booting... The name for all of these is ELFBoot */
 | 
			
		||||
#define ELF_NOTE_BOOT		"ELFBoot"
 | 
			
		||||
 | 
			
		||||
#define EIN_PROGRAM_NAME	0x00000001
 | 
			
		||||
/* The program in this ELF file */
 | 
			
		||||
#define EIN_PROGRAM_VERSION	0x00000002
 | 
			
		||||
/* The version of the program in this ELF file */
 | 
			
		||||
#define EIN_PROGRAM_CHECKSUM	0x00000003
 | 
			
		||||
/* ip style checksum of the memory image. */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Linux image notes for booting... The name for all of these is Linux */
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
#define LIN_COMMAND_LINE_PTR	0x00000006
 | 
			
		||||
/* Pointer to the command line to pass to the loaded kernel. */
 | 
			
		||||
#define LIN_INITRD_START_PTR	0x00000007
 | 
			
		||||
/* Pointer to the start of the ramdisk in bytes */
 | 
			
		||||
#define LIN_INITRD_SIZE_PTR	0x00000008
 | 
			
		||||
/* Pointer to the size of the ramdisk in bytes */
 | 
			
		||||
#define LIN_VID_MODE_PTR	0x00000009
 | 
			
		||||
/* Pointer to the vid_mode parameter */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Etherboot specific notes */
 | 
			
		||||
#define EB_PARAM_NOTE		"Etherboot"
 | 
			
		||||
#define EB_IA64_SYSTAB		0x00000001
 | 
			
		||||
#define EB_IA64_MEMMAP		0x00000002
 | 
			
		||||
#define EB_IA64_FPSWA		0x00000003
 | 
			
		||||
#define EB_IA64_CONINFO		0x00000004
 | 
			
		||||
#define EB_BOOTP_DATA		0x00000005
 | 
			
		||||
#define EB_HEADER		0x00000006
 | 
			
		||||
#define EB_IA64_IMAGE_HANDLE	0x00000007
 | 
			
		||||
#define EB_I386_MEMMAP		0x00000008
 | 
			
		||||
 | 
			
		||||
/* For standard notes n_namesz must be zero */
 | 
			
		||||
/* All of the following standard note types provide a single null
 | 
			
		||||
 * terminated string in the descriptor.
 | 
			
		||||
 */
 | 
			
		||||
#define EBN_FIRMWARE_TYPE	0x00000001
 | 
			
		||||
/* On platforms that support multiple classes of firmware this field
 | 
			
		||||
 * specifies the class of firmware you are loaded under.
 | 
			
		||||
 */
 | 
			
		||||
#define EBN_BOOTLOADER_NAME	0x00000002
 | 
			
		||||
/* This specifies just the name of the bootloader for easy comparison */
 | 
			
		||||
#define EBN_BOOTLOADER_VERSION	0x00000003
 | 
			
		||||
/* This specifies the version of the bootlader */
 | 
			
		||||
#define EBN_COMMAND_LINE	0x00000004
 | 
			
		||||
/* This specifies a command line that can be set by user interaction,
 | 
			
		||||
 * and is provided as a free form string to the loaded image.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#endif /* ELF_BOOT_H */
 | 
			
		||||
							
								
								
									
										82
									
								
								include/boot/linuxbios_tables.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								include/boot/linuxbios_tables.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
#ifndef LINUXBIOS_TABLES_H
 | 
			
		||||
#define LINUXBIOS_TABLES_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/* The linuxbios table information is for conveying information
 | 
			
		||||
 * from the firmware to the loaded OS image.  Primarily this
 | 
			
		||||
 * is expected to be information that cannot be discovered by
 | 
			
		||||
 * other means, such as quering the hardware directly.
 | 
			
		||||
 *
 | 
			
		||||
 * All of the information should be Position Independent Data.  
 | 
			
		||||
 * That is it should be safe to relocated any of the information
 | 
			
		||||
 * without it's meaning/correctnes changing.   For table that
 | 
			
		||||
 * can reasonably be used on multiple architectures the data
 | 
			
		||||
 * size should be fixed.  This should ease the transition between
 | 
			
		||||
 * 32 bit and 64 bit architectures etc.
 | 
			
		||||
 *
 | 
			
		||||
 * The completeness test for the information in this table is:
 | 
			
		||||
 * - Can all of the hardware be detected?
 | 
			
		||||
 * - Are the per motherboard constants available?
 | 
			
		||||
 * - Is there enough to allow a kernel to run that was written before
 | 
			
		||||
 *   a particular motherboard is constructed? (Assuming the kernel
 | 
			
		||||
 *   has drivers for all of the hardware but it does not have
 | 
			
		||||
 *   assumptions on how the hardware is connected together).
 | 
			
		||||
 *
 | 
			
		||||
 * With this test it should be straight forward to determine if a
 | 
			
		||||
 * table entry is required or not.  This should remove much of the
 | 
			
		||||
 * long term compatibility burden as table entries which are
 | 
			
		||||
 * irrelevant or have been replaced by better alternatives may be
 | 
			
		||||
 * dropped.  Of course it is polite and expidite to include extra
 | 
			
		||||
 * table entries and be backwards compatible, but it is not required.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct lb_header
 | 
			
		||||
{
 | 
			
		||||
	uint8_t  signature[4]; /* LBIO */
 | 
			
		||||
	uint32_t header_bytes;
 | 
			
		||||
	uint32_t header_checksum;
 | 
			
		||||
	uint32_t table_bytes;
 | 
			
		||||
	uint32_t table_checksum;
 | 
			
		||||
	uint32_t table_entries;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Every entry in the boot enviroment list will correspond to a boot
 | 
			
		||||
 * info record.  Encoding both type and size.  The type is obviously
 | 
			
		||||
 * so you can tell what it is.  The size allows you to skip that
 | 
			
		||||
 * boot enviroment record if you don't know what it easy.  This allows
 | 
			
		||||
 * forward compatibility with records not yet defined.
 | 
			
		||||
 */
 | 
			
		||||
struct lb_record {
 | 
			
		||||
	uint32_t tag;		/* tag ID */
 | 
			
		||||
	uint32_t size;		/* size of record (in bytes) */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define LB_TAG_UNUSED	0x0000
 | 
			
		||||
 | 
			
		||||
#define LB_TAG_MEMORY	0x0001
 | 
			
		||||
 | 
			
		||||
struct lb_memory_range {
 | 
			
		||||
	uint64_t start;
 | 
			
		||||
	uint64_t size;
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
#define LB_MEM_RAM      1
 | 
			
		||||
#define LB_MEM_RESERVED 2
 | 
			
		||||
	
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct lb_memory {
 | 
			
		||||
	uint32_t tag;
 | 
			
		||||
	uint32_t size;
 | 
			
		||||
	struct lb_memory_range map[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define LB_TAG_HWRPB	0x0002
 | 
			
		||||
struct lb_hwrpb {
 | 
			
		||||
	uint32_t tag;
 | 
			
		||||
	uint32_t size;
 | 
			
		||||
	uint64_t hwrpb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* LINUXBIOS_TABLES_H */
 | 
			
		||||
							
								
								
									
										2367
									
								
								include/elf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2367
									
								
								include/elf.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										90
									
								
								include/x86/mb_header.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								include/x86/mb_header.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  GRUB  --  GRand Unified Bootloader
 | 
			
		||||
 *  Copyright (C) 2000   Free Software Foundation, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License as published by
 | 
			
		||||
 *  the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 *  (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  MultiBoot Header description
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct multiboot_header
 | 
			
		||||
{
 | 
			
		||||
	/* Must be MULTIBOOT_MAGIC - see below.  */
 | 
			
		||||
	uint32_t magic;
 | 
			
		||||
	
 | 
			
		||||
	/* Feature flags - see below.  */
 | 
			
		||||
	uint32_t flags;
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
	 * Checksum
 | 
			
		||||
	 *
 | 
			
		||||
	 * The above fields plus this one must equal 0 mod 2^32.
 | 
			
		||||
	 */
 | 
			
		||||
	uint32_t checksum;
 | 
			
		||||
	
 | 
			
		||||
	/* These are only valid if MULTIBOOT_AOUT_KLUDGE is set.  */
 | 
			
		||||
	uint32_t header_addr;
 | 
			
		||||
	uint32_t load_addr;
 | 
			
		||||
	uint32_t load_end_addr;
 | 
			
		||||
	uint32_t bss_end_addr;
 | 
			
		||||
	uint32_t entry_addr;
 | 
			
		||||
	
 | 
			
		||||
	/* These are only valid if MULTIBOOT_VIDEO_MODE is set.  */
 | 
			
		||||
	uint32_t mode_type;
 | 
			
		||||
	uint32_t width;
 | 
			
		||||
	uint32_t height;
 | 
			
		||||
	uint32_t depth;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The entire multiboot_header must be contained
 | 
			
		||||
 * within the first MULTIBOOT_SEARCH bytes of the kernel image.
 | 
			
		||||
 */
 | 
			
		||||
#define MULTIBOOT_SEARCH		8192
 | 
			
		||||
#define MULTIBOOT_FOUND(addr, len) \
 | 
			
		||||
  (! ((addr) & 0x3) \
 | 
			
		||||
   && (len) >= 12 \
 | 
			
		||||
   && *((int *) (addr)) == MULTIBOOT_MAGIC \
 | 
			
		||||
   && ! (*((uint32_t *) (addr)) + *((uint32_t *) (addr + 4)) \
 | 
			
		||||
	 + *((uint32_t *) (addr + 8))) \
 | 
			
		||||
   && (! (MULTIBOOT_AOUT_KLUDGE & *((int *) (addr + 4))) || (len) >= 32) \
 | 
			
		||||
   && (! (MULTIBOOT_VIDEO_MODE & *((int *) (addr + 4))) || (len) >= 48))
 | 
			
		||||
 | 
			
		||||
/* Magic value identifying the multiboot_header.  */
 | 
			
		||||
#define MULTIBOOT_MAGIC			0x1BADB002
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Features flags for 'flags'.
 | 
			
		||||
 * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set
 | 
			
		||||
 * and it doesn't understand it, it must fail.
 | 
			
		||||
 */
 | 
			
		||||
#define MULTIBOOT_MUSTKNOW		0x0000FFFF
 | 
			
		||||
 | 
			
		||||
/* currently unsupported flags...  this is a kind of version number.  */
 | 
			
		||||
#define MULTIBOOT_UNSUPPORTED		0x0000FFF8
 | 
			
		||||
 | 
			
		||||
/* Align all boot modules on i386 page (4KB) boundaries.  */
 | 
			
		||||
#define MULTIBOOT_PAGE_ALIGN		0x00000001
 | 
			
		||||
 | 
			
		||||
/* Must pass memory information to OS.  */
 | 
			
		||||
#define MULTIBOOT_MEMORY_INFO		0x00000002
 | 
			
		||||
 | 
			
		||||
/* Must pass video information to OS.  */
 | 
			
		||||
#define MULTIBOOT_VIDEO_MODE		0x00000004
 | 
			
		||||
 | 
			
		||||
/* This flag indicates the use of the address fields in the header.  */
 | 
			
		||||
#define MULTIBOOT_AOUT_KLUDGE		0x00010000
 | 
			
		||||
							
								
								
									
										219
									
								
								include/x86/mb_info.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								include/x86/mb_info.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,219 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  GRUB  --  GRand Unified Bootloader
 | 
			
		||||
 *  Copyright (C) 2000  Free Software Foundation, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License as published by
 | 
			
		||||
 *  the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 *  (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  The structure type "mod_list" is used by the "multiboot_info" structure.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct mod_list
 | 
			
		||||
{
 | 
			
		||||
	/* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */
 | 
			
		||||
	uint32_t mod_start;
 | 
			
		||||
	uint32_t mod_end;
 | 
			
		||||
	
 | 
			
		||||
	/* Module command line */
 | 
			
		||||
	uint32_t cmdline;
 | 
			
		||||
  
 | 
			
		||||
	/* padding to take it to 16 bytes (must be zero) */
 | 
			
		||||
	uint32_t pad;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  INT-15, AX=E820 style "AddressRangeDescriptor"
 | 
			
		||||
 *  ...with a "size" parameter on the front which is the structure size - 4,
 | 
			
		||||
 *  pointing to the next one, up until the full buffer length of the memory
 | 
			
		||||
 *  map has been reached.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct AddrRangeDesc
 | 
			
		||||
{
 | 
			
		||||
	uint32_t size;
 | 
			
		||||
	uint32_t base_addr_low;
 | 
			
		||||
	uint32_t base_addr_high;
 | 
			
		||||
	uint32_t length_low;
 | 
			
		||||
	uint32_t length_high;
 | 
			
		||||
	uint32_t Type;
 | 
			
		||||
  
 | 
			
		||||
  /* unspecified optional padding... */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* usable memory "Type", all others are reserved.  */
 | 
			
		||||
#define MB_ARD_MEMORY		1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Drive Info structure.  */
 | 
			
		||||
struct drive_info
 | 
			
		||||
{
 | 
			
		||||
	/* The size of this structure.  */
 | 
			
		||||
	uint32_t size;
 | 
			
		||||
 | 
			
		||||
	/* The BIOS drive number.  */
 | 
			
		||||
	uint8_t drive_number;
 | 
			
		||||
	
 | 
			
		||||
	/* The access mode (see below).  */
 | 
			
		||||
	uint8_t drive_mode;
 | 
			
		||||
	
 | 
			
		||||
	/* The BIOS geometry.  */
 | 
			
		||||
	uint16_t drive_cylinders;
 | 
			
		||||
	uint8_t drive_heads;
 | 
			
		||||
	uint8_t drive_sectors;
 | 
			
		||||
	
 | 
			
		||||
	/* The array of I/O ports used for the drive.  */
 | 
			
		||||
	uint16_t drive_ports[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Drive Mode.  */
 | 
			
		||||
#define MB_DI_CHS_MODE		0
 | 
			
		||||
#define MB_DI_LBA_MODE		1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* APM BIOS info.  */
 | 
			
		||||
struct apm_info
 | 
			
		||||
{
 | 
			
		||||
	uint16_t version;
 | 
			
		||||
	uint16_t cseg;
 | 
			
		||||
	uint32_t offset;
 | 
			
		||||
	uint32_t cseg_16;
 | 
			
		||||
	uint32_t dseg_16;
 | 
			
		||||
	uint32_t cseg_len;
 | 
			
		||||
	uint32_t cseg_16_len;
 | 
			
		||||
	uint32_t dseg_16_len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  MultiBoot Info description
 | 
			
		||||
 *
 | 
			
		||||
 *  This is the struct passed to the boot image.  This is done by placing
 | 
			
		||||
 *  its address in the EAX register.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct multiboot_info
 | 
			
		||||
{
 | 
			
		||||
	/* MultiBoot info version number */
 | 
			
		||||
	uint32_t flags;
 | 
			
		||||
	
 | 
			
		||||
	/* Available memory from BIOS */
 | 
			
		||||
	uint32_t mem_lower;
 | 
			
		||||
	uint32_t mem_upper;
 | 
			
		||||
	
 | 
			
		||||
	/* "root" partition */
 | 
			
		||||
	uint32_t boot_device;
 | 
			
		||||
	
 | 
			
		||||
	/* Kernel command line */
 | 
			
		||||
	uint32_t cmdline;
 | 
			
		||||
	
 | 
			
		||||
	/* Boot-Module list */
 | 
			
		||||
	uint32_t mods_count;
 | 
			
		||||
	uint32_t mods_addr;
 | 
			
		||||
	
 | 
			
		||||
	union
 | 
			
		||||
	{
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			/* (a.out) Kernel symbol table info */
 | 
			
		||||
			uint32_t tabsize;
 | 
			
		||||
			uint32_t strsize;
 | 
			
		||||
			uint32_t addr;
 | 
			
		||||
			uint32_t pad;
 | 
			
		||||
		}
 | 
			
		||||
		a;
 | 
			
		||||
		
 | 
			
		||||
		struct
 | 
			
		||||
		{
 | 
			
		||||
			/* (ELF) Kernel section header table */
 | 
			
		||||
			uint32_t num;
 | 
			
		||||
			uint32_t size;
 | 
			
		||||
			uint32_t addr;
 | 
			
		||||
			uint32_t shndx;
 | 
			
		||||
		}
 | 
			
		||||
		e;
 | 
			
		||||
	}
 | 
			
		||||
	syms;
 | 
			
		||||
	
 | 
			
		||||
	/* Memory Mapping buffer */
 | 
			
		||||
	uint32_t mmap_length;
 | 
			
		||||
	uint32_t mmap_addr;
 | 
			
		||||
	
 | 
			
		||||
	/* Drive Info buffer */
 | 
			
		||||
	uint32_t drives_length;
 | 
			
		||||
	uint32_t drives_addr;
 | 
			
		||||
	
 | 
			
		||||
	/* ROM configuration table */
 | 
			
		||||
	uint32_t config_table;
 | 
			
		||||
	
 | 
			
		||||
	/* Boot Loader Name */
 | 
			
		||||
	uint32_t boot_loader_name;
 | 
			
		||||
	
 | 
			
		||||
	/* APM table */
 | 
			
		||||
	uint32_t apm_table;
 | 
			
		||||
	
 | 
			
		||||
	/* Video */
 | 
			
		||||
	uint32_t vbe_control_info;
 | 
			
		||||
	uint32_t vbe_mode_info;
 | 
			
		||||
	uint16_t vbe_mode;
 | 
			
		||||
	uint16_t vbe_interface_seg;
 | 
			
		||||
	uint16_t vbe_interface_off;
 | 
			
		||||
	uint16_t vbe_interface_len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  Flags to be set in the 'flags' parameter above
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* is there basic lower/upper memory information? */
 | 
			
		||||
#define MB_INFO_MEMORY			0x00000001
 | 
			
		||||
/* is there a boot device set? */
 | 
			
		||||
#define MB_INFO_BOOTDEV			0x00000002
 | 
			
		||||
/* is the command-line defined? */
 | 
			
		||||
#define MB_INFO_CMDLINE			0x00000004
 | 
			
		||||
/* are there modules to do something with? */
 | 
			
		||||
#define MB_INFO_MODS			0x00000008
 | 
			
		||||
 | 
			
		||||
/* These next two are mutually exclusive */
 | 
			
		||||
 | 
			
		||||
/* is there a symbol table loaded? */
 | 
			
		||||
#define MB_INFO_AOUT_SYMS		0x00000010
 | 
			
		||||
/* is there an ELF section header table? */
 | 
			
		||||
#define MB_INFO_ELF_SHDR		0x00000020
 | 
			
		||||
 | 
			
		||||
/* is there a full memory map? */
 | 
			
		||||
#define MB_INFO_MEM_MAP			0x00000040
 | 
			
		||||
 | 
			
		||||
/* Is there drive info?  */
 | 
			
		||||
#define MB_INFO_DRIVE_INFO		0x00000080
 | 
			
		||||
 | 
			
		||||
/* Is there a config table?  */
 | 
			
		||||
#define MB_INFO_CONFIG_TABLE		0x00000100
 | 
			
		||||
 | 
			
		||||
/* Is there a boot loader name?  */
 | 
			
		||||
#define MB_INFO_BOOT_LOADER_NAME	0x00000200
 | 
			
		||||
 | 
			
		||||
/* Is there a APM table?  */
 | 
			
		||||
#define MB_INFO_APM_TABLE		0x00000400
 | 
			
		||||
 | 
			
		||||
/* Is there video information?  */
 | 
			
		||||
#define MB_INFO_VIDEO_INFO		0x00000800
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  The following value must be present in the EAX register.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define MULTIBOOT_VALID			0x2BADB002
 | 
			
		||||
							
								
								
									
										212
									
								
								include/x86/x86-linux.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								include/x86/x86-linux.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,212 @@
 | 
			
		||||
#ifndef X86_LINUX_H
 | 
			
		||||
#define X86_LINUX_H
 | 
			
		||||
 | 
			
		||||
#define TENATIVE 0 /* Code that is tenatively correct but hasn't yet been officially accepted */
 | 
			
		||||
 | 
			
		||||
#define E820MAP	0x2d0		/* our map */
 | 
			
		||||
#define E820MAX	32		/* number of entries in E820MAP */
 | 
			
		||||
#define E820NR	0x1e8		/* # entries in E820MAP */
 | 
			
		||||
 | 
			
		||||
#ifndef ASSEMBLY
 | 
			
		||||
 | 
			
		||||
#define PACKED __attribute__((packed))
 | 
			
		||||
 | 
			
		||||
struct e820entry {
 | 
			
		||||
	uint64_t addr;	/* start of memory segment */
 | 
			
		||||
	uint64_t size;	/* size of memory segment */
 | 
			
		||||
	uint32_t type;		/* type of memory segment */
 | 
			
		||||
#define E820_RAM	1
 | 
			
		||||
#define E820_RESERVED	2
 | 
			
		||||
#define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */
 | 
			
		||||
#define E820_NVS	4
 | 
			
		||||
} PACKED;
 | 
			
		||||
 | 
			
		||||
/* FIXME expand on drive_info_)struct... */
 | 
			
		||||
struct drive_info_struct { 
 | 
			
		||||
	uint8_t dummy[32]; 
 | 
			
		||||
}; 
 | 
			
		||||
struct sys_desc_table {
 | 
			
		||||
	uint16_t length;
 | 
			
		||||
	uint8_t  table[318];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct apm_bios_info {
 | 
			
		||||
	uint16_t version;       /* 0x40 */
 | 
			
		||||
	uint16_t cseg;		/* 0x42 */
 | 
			
		||||
	uint32_t offset;	/* 0x44 */
 | 
			
		||||
	uint16_t cseg_16;	/* 0x48 */
 | 
			
		||||
	uint16_t dseg;		/* 0x4a */
 | 
			
		||||
	uint16_t flags;		/* 0x4c */
 | 
			
		||||
	uint16_t cseg_len;	/* 0x4e */
 | 
			
		||||
	uint16_t cseg_16_len;	/* 0x50 */
 | 
			
		||||
	uint16_t dseg_len;	/* 0x52 */
 | 
			
		||||
	uint8_t  reserved[44];	/* 0x54 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct x86_linux_param_header {
 | 
			
		||||
	uint8_t  orig_x;			/* 0x00 */
 | 
			
		||||
	uint8_t  orig_y;			/* 0x01 */
 | 
			
		||||
	uint16_t ext_mem_k;			/* 0x02 -- EXT_MEM_K sits here */
 | 
			
		||||
	uint16_t orig_video_page;		/* 0x04 */
 | 
			
		||||
	uint8_t  orig_video_mode;		/* 0x06 */
 | 
			
		||||
	uint8_t  orig_video_cols;		/* 0x07 */
 | 
			
		||||
	uint16_t unused2;			/* 0x08 */
 | 
			
		||||
	uint16_t orig_video_ega_bx;		/* 0x0a */
 | 
			
		||||
	uint16_t unused3;			/* 0x0c */
 | 
			
		||||
	uint8_t	 orig_video_lines;		/* 0x0e */
 | 
			
		||||
	uint8_t	 orig_video_isVGA;		/* 0x0f */
 | 
			
		||||
	uint16_t orig_video_points;		/* 0x10 */
 | 
			
		||||
 | 
			
		||||
	/* VESA graphic mode -- linear frame buffer */
 | 
			
		||||
	uint16_t lfb_width;			/* 0x12 */
 | 
			
		||||
	uint16_t lfb_height;			/* 0x14 */
 | 
			
		||||
	uint16_t lfb_depth;			/* 0x16 */
 | 
			
		||||
	uint32_t lfb_base;			/* 0x18 */
 | 
			
		||||
	uint32_t lfb_size;			/* 0x1c */
 | 
			
		||||
	uint16_t cl_magic;			/* 0x20 */
 | 
			
		||||
#define CL_MAGIC_VALUE 0xA33F
 | 
			
		||||
	uint16_t cl_offset;			/* 0x22 */
 | 
			
		||||
	uint16_t lfb_linelength;		/* 0x24 */
 | 
			
		||||
	uint8_t	 red_size;			/* 0x26 */
 | 
			
		||||
	uint8_t	 red_pos;			/* 0x27 */
 | 
			
		||||
	uint8_t	 green_size;			/* 0x28 */
 | 
			
		||||
	uint8_t	 green_pos;			/* 0x29 */
 | 
			
		||||
	uint8_t	 blue_size;			/* 0x2a */
 | 
			
		||||
	uint8_t	 blue_pos;			/* 0x2b */
 | 
			
		||||
	uint8_t	 rsvd_size;			/* 0x2c */
 | 
			
		||||
	uint8_t	 rsvd_pos;			/* 0x2d */
 | 
			
		||||
	uint16_t vesapm_seg;			/* 0x2e */
 | 
			
		||||
	uint16_t vesapm_off;			/* 0x30 */
 | 
			
		||||
	uint16_t pages;				/* 0x32 */
 | 
			
		||||
	uint8_t  reserved4[12];			/* 0x34 -- 0x3f reserved for future expansion */
 | 
			
		||||
 | 
			
		||||
	struct apm_bios_info apm_bios_info;	/* 0x40 */
 | 
			
		||||
	struct drive_info_struct drive_info;	/* 0x80 */
 | 
			
		||||
	struct sys_desc_table sys_desc_table;	/* 0xa0 */
 | 
			
		||||
	uint32_t alt_mem_k;			/* 0x1e0 */
 | 
			
		||||
	uint8_t  reserved5[4];			/* 0x1e4 */
 | 
			
		||||
	uint8_t  e820_map_nr;			/* 0x1e8 */
 | 
			
		||||
	uint8_t  reserved6[8];			/* 0x1e9 */
 | 
			
		||||
	uint8_t  setup_sects;			/* 0x1f1 */
 | 
			
		||||
	uint16_t mount_root_rdonly;		/* 0x1f2 */
 | 
			
		||||
	uint16_t syssize;			/* 0x1f4 */
 | 
			
		||||
	uint16_t swapdev;			/* 0x1f6 */
 | 
			
		||||
	uint16_t ramdisk_flags;			/* 0x1f8 */
 | 
			
		||||
#define RAMDISK_IMAGE_START_MASK  	0x07FF
 | 
			
		||||
#define RAMDISK_PROMPT_FLAG		0x8000
 | 
			
		||||
#define RAMDISK_LOAD_FLAG		0x4000	
 | 
			
		||||
	uint16_t vid_mode;			/* 0x1fa */
 | 
			
		||||
	uint16_t root_dev;			/* 0x1fc */
 | 
			
		||||
	uint8_t  reserved9[1];			/* 0x1fe */
 | 
			
		||||
	uint8_t  aux_device_info;		/* 0x1ff */
 | 
			
		||||
	/* 2.00+ */
 | 
			
		||||
	uint8_t  reserved10[2];			/* 0x200 */
 | 
			
		||||
	uint8_t  header_magic[4];		/* 0x202 */
 | 
			
		||||
	uint16_t protocol_version;		/* 0x206 */
 | 
			
		||||
	uint16_t rmode_switch_ip;		/* 0x208 */
 | 
			
		||||
	uint16_t rmode_switch_cs;		/* 0x20a */
 | 
			
		||||
	uint8_t  reserved11[4];			/* 0x208 */
 | 
			
		||||
	uint8_t  loader_type;			/* 0x210 */
 | 
			
		||||
#define LOADER_TYPE_LOADLIN         1
 | 
			
		||||
#define LOADER_TYPE_BOOTSECT_LOADER 2
 | 
			
		||||
#define LOADER_TYPE_SYSLINUX        3
 | 
			
		||||
#define LOADER_TYPE_ETHERBOOT       4
 | 
			
		||||
#define LOADER_TYPE_UNKNOWN         0xFF
 | 
			
		||||
	uint8_t  loader_flags;			/* 0x211 */
 | 
			
		||||
	uint8_t  reserved12[2];			/* 0x212 */
 | 
			
		||||
	uint32_t kernel_start;			/* 0x214 */
 | 
			
		||||
	uint32_t initrd_start;			/* 0x218 */
 | 
			
		||||
	uint32_t initrd_size;			/* 0x21c */
 | 
			
		||||
	uint8_t  reserved13[4];			/* 0x220 */
 | 
			
		||||
	/* 2.01+ */
 | 
			
		||||
	uint16_t heap_end_ptr;			/* 0x224 */
 | 
			
		||||
	uint8_t  reserved14[2];			/* 0x226 */
 | 
			
		||||
	/* 2.02+ */
 | 
			
		||||
	uint32_t cmd_line_ptr;			/* 0x228 */
 | 
			
		||||
	/* 2.03+ */
 | 
			
		||||
	uint32_t initrd_addr_max;		/* 0x22c */
 | 
			
		||||
#if TENATIVE
 | 
			
		||||
	/* 2.04+ */
 | 
			
		||||
	uint16_t entry32_off;			/* 0x230 */
 | 
			
		||||
	uint16_t internal_cmdline_off;		/* 0x232 */
 | 
			
		||||
	uint32_t low_base;			/* 0x234 */
 | 
			
		||||
	uint32_t low_memsz;			/* 0x238 */
 | 
			
		||||
	uint32_t low_filesz;			/* 0x23c */
 | 
			
		||||
	uint32_t real_base;			/* 0x240 */
 | 
			
		||||
	uint32_t real_memsz;			/* 0x244 */
 | 
			
		||||
	uint32_t real_filesz;			/* 0x248 */
 | 
			
		||||
	uint32_t high_base;			/* 0x24C */
 | 
			
		||||
	uint32_t high_memsz;			/* 0x250 */
 | 
			
		||||
	uint32_t high_filesz;			/* 0x254 */
 | 
			
		||||
	uint8_t  reserved15[0x2d0 - 0x258];	/* 0x258 */
 | 
			
		||||
#else
 | 
			
		||||
	uint8_t  reserved15[0x2d0 - 0x230];	/* 0x230 */
 | 
			
		||||
#endif
 | 
			
		||||
	struct e820entry e820_map[E820MAX];	/* 0x2d0 */
 | 
			
		||||
						/* 0x550 */
 | 
			
		||||
#define COMMAND_LINE_SIZE 256
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct x86_linux_faked_param_header {
 | 
			
		||||
	struct x86_linux_param_header hdr;	/* 0x00 */
 | 
			
		||||
	uint8_t reserved16[688];		/* 0x550 */
 | 
			
		||||
	uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x800 */
 | 
			
		||||
	uint8_t reserved17[1792];		/* 0x900 - 0x1000 */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct x86_linux_header {
 | 
			
		||||
	uint8_t  reserved1[0x1f1];		/* 0x000 */
 | 
			
		||||
	uint8_t  setup_sects;			/* 0x1f1 */
 | 
			
		||||
	uint16_t root_flags;			/* 0x1f2 */
 | 
			
		||||
	uint16_t syssize;			/* 0x1f4 */
 | 
			
		||||
	uint16_t swapdev;			/* 0x1f6 */
 | 
			
		||||
	uint16_t ramdisk_flags;			/* 0x1f6 */
 | 
			
		||||
	uint16_t vid_mode;			/* 0x1fa */
 | 
			
		||||
	uint16_t root_dev;			/* 0x1fc */
 | 
			
		||||
	uint16_t boot_sector_magic;		/* 0x1fe */
 | 
			
		||||
	/* 2.00+ */
 | 
			
		||||
	uint8_t  reserved3[2];			/* 0x200 */
 | 
			
		||||
	uint8_t  header_magic[4];		/* 0x202 */
 | 
			
		||||
	uint16_t protocol_version;		/* 0x206 */
 | 
			
		||||
	uint32_t realmode_swtch;		/* 0x208 */
 | 
			
		||||
	uint16_t start_sys;			/* 0x20c */
 | 
			
		||||
	uint16_t kver_addr;			/* 0x20e */
 | 
			
		||||
	uint8_t  type_of_loader;		/* 0x210 */
 | 
			
		||||
	uint8_t  loadflags;			/* 0x211 */
 | 
			
		||||
	uint16_t setup_move_size;		/* 0x212 */
 | 
			
		||||
	uint32_t code32_start;			/* 0x214 */
 | 
			
		||||
	uint32_t ramdisk_image;			/* 0x218 */
 | 
			
		||||
	uint32_t ramdisk_size;			/* 0x21c */
 | 
			
		||||
	uint8_t  reserved4[4];			/* 0x220 */
 | 
			
		||||
	/* 2.01+ */
 | 
			
		||||
	uint16_t heap_end_ptr;			/* 0x224 */
 | 
			
		||||
	uint8_t  reserved5[2];			/* 0x226 */
 | 
			
		||||
	/* 2.02+ */
 | 
			
		||||
	uint32_t cmd_line_ptr;			/* 0x228 */
 | 
			
		||||
	/* 2.03+ */
 | 
			
		||||
	uint32_t initrd_addr_max;		/* 0x22c */
 | 
			
		||||
#if TENATIVE
 | 
			
		||||
	/* 2.04+ */
 | 
			
		||||
	uint16_t entry32_off;			/* 0x230 */
 | 
			
		||||
	uint16_t internal_cmdline_off;		/* 0x232 */
 | 
			
		||||
	uint32_t low_base;			/* 0x234 */
 | 
			
		||||
	uint32_t low_memsz;			/* 0x238 */
 | 
			
		||||
	uint32_t low_filesz;			/* 0x23c */
 | 
			
		||||
	uint32_t real_base;			/* 0x240 */
 | 
			
		||||
	uint32_t real_memsz;			/* 0x244 */
 | 
			
		||||
	uint32_t real_filesz;			/* 0x248 */
 | 
			
		||||
	uint32_t high_base;			/* 0x24C */
 | 
			
		||||
	uint32_t high_memsz;			/* 0x250 */
 | 
			
		||||
	uint32_t high_filesz;			/* 0x254 */
 | 
			
		||||
	uint32_t tail[32*1024 - 0x258];		/* 0x258 */
 | 
			
		||||
#else
 | 
			
		||||
	uint8_t  tail[32*1024 - 0x230];		/* 0x230 */
 | 
			
		||||
#endif
 | 
			
		||||
} PACKED;
 | 
			
		||||
 | 
			
		||||
#endif /* ASSEMBLY */
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_INITRD_ADDR_MAX 0x37FFFFFF
 | 
			
		||||
 | 
			
		||||
#endif /* X86_LINUX_H */
 | 
			
		||||
							
								
								
									
										35
									
								
								kdump/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								kdump/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
#
 | 
			
		||||
# kdump (reading a crashdump from memory)
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
KDUMP_C_SRCS:= kdump/kdump.c
 | 
			
		||||
 | 
			
		||||
KDUMP_C_OBJS:= $(patsubst %.c, $(OBJDIR)/%.o, $(KDUMP_C_SRCS))
 | 
			
		||||
KDUMP_C_DEPS:= $(patsubst %.c, $(OBJDIR)/%.d, $(KDUMP_C_SRCS))
 | 
			
		||||
KDUMP_SRCS:= $(KDUMP_C_SRCS)
 | 
			
		||||
KDUMP_OBJS:= $(KDUMP_C_OBJS)
 | 
			
		||||
KDUMP_DEPS:= $(KDUMP_C_DEPS)
 | 
			
		||||
KDUMP:= $(SBINDIR)/kdump
 | 
			
		||||
 | 
			
		||||
include $(KDUMP_DEPS)
 | 
			
		||||
 | 
			
		||||
$(KDUMP_C_DEPS): $(OBJDIR)/%.d: %.c
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(CFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
 | 
			
		||||
 | 
			
		||||
$(KDUMP_C_OBJS): $(OBJDIR)/%.o: %.c $(OBJDIR)/%.d
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(CFLAGS) -o $@ -c $<
 | 
			
		||||
 | 
			
		||||
$(KDUMP): $(KDUMP_OBJS)
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(CFLAGS) -o $@ $(KDUMP_OBJS)
 | 
			
		||||
 | 
			
		||||
echo::
 | 
			
		||||
	@echo "KDUMP_C_SRCS $(KDUMP_C_SRCS)"
 | 
			
		||||
	@echo "KDUMP_C_DEPS $(KDUMP_C_DEPS)"
 | 
			
		||||
	@echo "KDUMP_C_OBJS $(KDUMP_C_OBJS)"
 | 
			
		||||
	@echo "KDUMP_SRCS $(KDUMP_SRCS)"
 | 
			
		||||
	@echo "KDUMP_DEPS $(KDUMP_DEPS)"
 | 
			
		||||
	@echo "KDUMP_OBJS $(KDUMP_OBJS)"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										311
									
								
								kdump/kdump.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								kdump/kdump.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,311 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <endian.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
 | 
			
		||||
#if !defined(__BYTE_ORDER) || !defined(__LITTLE_ENDIAN) || !defined(__BIG_ENDIAN)
 | 
			
		||||
#error Endian defines missing
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
 | 
			
		||||
# define ELFDATALOCAL ELFDATA2LSB
 | 
			
		||||
#elif __BYTE_ORDER == __BIG_ENDIAN
 | 
			
		||||
# define ELFDATALOCAL ELFDATA2MSB
 | 
			
		||||
#else
 | 
			
		||||
# error Unknown byte order
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MAP_WINDOW_SIZE (64*1024*1024)
 | 
			
		||||
#define DEV_MEM "/dev/mem"
 | 
			
		||||
 | 
			
		||||
static void *map_addr(int fd, unsigned long size, off_t offset)
 | 
			
		||||
{
 | 
			
		||||
	void *result;
 | 
			
		||||
	result = mmap(0, size, PROT_READ, MAP_SHARED, fd, offset);
 | 
			
		||||
	if (result == MAP_FAILED) {
 | 
			
		||||
		fprintf(stderr, "Cannot mmap " DEV_MEM " offset: %llu size: %lu: %s\n",
 | 
			
		||||
			(unsigned long long)offset, size, strerror(errno));
 | 
			
		||||
		exit(5);
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void unmap_addr(void *addr, unsigned long size)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	ret = munmap(addr, size);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		fprintf(stderr, "munmap failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		exit(6);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *xmalloc(size_t size)
 | 
			
		||||
{
 | 
			
		||||
	void *result;
 | 
			
		||||
	result = malloc(size);
 | 
			
		||||
	if (result == NULL) {
 | 
			
		||||
		fprintf(stderr, "malloc of %u bytes failed: %s\n",
 | 
			
		||||
			size, strerror(errno));
 | 
			
		||||
		exit(7);
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *collect_notes(
 | 
			
		||||
	int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdr, size_t *note_bytes)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	size_t bytes, result_bytes;
 | 
			
		||||
	char *notes;
 | 
			
		||||
 | 
			
		||||
	result_bytes = 0;
 | 
			
		||||
	/* Find the worst case note memory usage */
 | 
			
		||||
	bytes = 0;
 | 
			
		||||
	for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
		if (phdr[i].p_type == PT_NOTE) {
 | 
			
		||||
			bytes += phdr[i].p_filesz;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate the worst case note array */
 | 
			
		||||
	notes = xmalloc(bytes);
 | 
			
		||||
 | 
			
		||||
	/* Walk through and capture the notes */
 | 
			
		||||
	for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
		Elf64_Nhdr *hdr, *lhdr, *nhdr;
 | 
			
		||||
		void *pnotes;
 | 
			
		||||
		if (phdr[i].p_type != PT_NOTE) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		/* First snapshot the notes */
 | 
			
		||||
		pnotes = map_addr(fd, phdr[i].p_filesz, phdr[i].p_offset);
 | 
			
		||||
		memcpy(notes + result_bytes, pnotes, phdr[i].p_filesz);
 | 
			
		||||
		unmap_addr(pnotes, phdr[i].p_filesz);
 | 
			
		||||
 | 
			
		||||
		/* Walk through the new notes and find the real length */
 | 
			
		||||
		hdr = (Elf64_Nhdr *)(notes + result_bytes);
 | 
			
		||||
		lhdr = (Elf64_Nhdr *)(notes + result_bytes + phdr[i].p_filesz);
 | 
			
		||||
		for(; hdr < lhdr; hdr = nhdr) {
 | 
			
		||||
			size_t hdr_size;
 | 
			
		||||
			/* If there is not a name this is a invalid/reserved note
 | 
			
		||||
			 * stop here.
 | 
			
		||||
			 */
 | 
			
		||||
			if (hdr->n_namesz == 0) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			hdr_size = 
 | 
			
		||||
				sizeof(*hdr) + 
 | 
			
		||||
				((hdr->n_namesz + 3) & ~3) +
 | 
			
		||||
				((hdr->n_descsz + 3) & ~3);
 | 
			
		||||
 | 
			
		||||
			nhdr = (Elf64_Nhdr *)(((char *)hdr) + hdr_size); 
 | 
			
		||||
			/* if the note does not fit in the segment stop here */
 | 
			
		||||
			if (nhdr > lhdr) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			/* Update result_bytes for after each good header */
 | 
			
		||||
			result_bytes = ((char *)hdr) - notes;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	*note_bytes = result_bytes;
 | 
			
		||||
	return notes;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *generate_new_headers(
 | 
			
		||||
	Elf64_Ehdr *ehdr, Elf64_Phdr *phdr, size_t note_bytes, size_t *header_bytes)
 | 
			
		||||
{
 | 
			
		||||
	unsigned phnum;
 | 
			
		||||
	size_t bytes;
 | 
			
		||||
	char *headers;
 | 
			
		||||
	Elf64_Ehdr *nehdr;
 | 
			
		||||
	Elf64_Phdr *nphdr;
 | 
			
		||||
	unsigned long long offset;
 | 
			
		||||
	int i;
 | 
			
		||||
	/* Count the number of program headers.
 | 
			
		||||
	 * When we are done there will be only one note header.
 | 
			
		||||
	 */
 | 
			
		||||
	phnum = 1;
 | 
			
		||||
	for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
		if (phdr[i].p_type == PT_NOTE) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		phnum++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Compute how many bytes we will need for headers */
 | 
			
		||||
	bytes = sizeof(*ehdr) + sizeof(*phdr)*phnum;
 | 
			
		||||
 | 
			
		||||
	/* Allocate memory for the headers */
 | 
			
		||||
	headers = xmalloc(bytes);
 | 
			
		||||
 | 
			
		||||
	/* Setup pointers to the new headers */
 | 
			
		||||
	nehdr = (Elf64_Ehdr *)headers;
 | 
			
		||||
	nphdr = (Elf64_Phdr *)(headers + sizeof(*nehdr));
 | 
			
		||||
	
 | 
			
		||||
	/* Copy and adjust the Elf header */
 | 
			
		||||
	memcpy(nehdr, ehdr, sizeof(*nehdr));
 | 
			
		||||
	nehdr->e_phoff = sizeof(*nehdr);
 | 
			
		||||
	nehdr->e_phnum = phnum;
 | 
			
		||||
	nehdr->e_shoff = 0;
 | 
			
		||||
	nehdr->e_shentsize = 0;
 | 
			
		||||
	nehdr->e_shnum = 0;
 | 
			
		||||
	nehdr->e_shstrndx = 0;
 | 
			
		||||
 | 
			
		||||
	/* Write the note program header */
 | 
			
		||||
	nphdr->p_type = PT_NOTE;
 | 
			
		||||
	nphdr->p_offset = bytes;
 | 
			
		||||
	nphdr->p_vaddr  = 0;
 | 
			
		||||
	nphdr->p_paddr  = 0;
 | 
			
		||||
	nphdr->p_filesz = note_bytes;
 | 
			
		||||
	nphdr->p_memsz  = note_bytes;
 | 
			
		||||
	nphdr->p_flags  = 0;
 | 
			
		||||
	nphdr->p_align  = 0;
 | 
			
		||||
	nphdr++;
 | 
			
		||||
 | 
			
		||||
	/* Write the rest of the program headers */
 | 
			
		||||
	offset = bytes + note_bytes;
 | 
			
		||||
	for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
		if (phdr[i].p_type == PT_NOTE) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		memcpy(nphdr, &phdr[i], sizeof(*nphdr));
 | 
			
		||||
		nphdr->p_offset = offset;
 | 
			
		||||
		offset += phdr[i].p_filesz;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	*header_bytes = bytes;
 | 
			
		||||
	return headers;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void write_all(int fd, const void *buf, size_t count)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t result, written;
 | 
			
		||||
	const char *ptr;
 | 
			
		||||
	size_t left;
 | 
			
		||||
	ptr = buf;
 | 
			
		||||
	left = count;
 | 
			
		||||
	do {
 | 
			
		||||
		result = write(fd, ptr, left);
 | 
			
		||||
		if (result >= 0) {
 | 
			
		||||
			written += result;
 | 
			
		||||
			ptr += result;
 | 
			
		||||
			left -= result;
 | 
			
		||||
		}
 | 
			
		||||
		else if ((errno != EAGAIN) && (errno != EINTR)) {
 | 
			
		||||
			fprintf(stderr, "write failed: %s\n",
 | 
			
		||||
				strerror(errno));
 | 
			
		||||
			exit(8);
 | 
			
		||||
		}
 | 
			
		||||
	} while(written < count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	char *start_addr_str, *end;
 | 
			
		||||
	unsigned long long start_addr;
 | 
			
		||||
	Elf64_Ehdr *ehdr;
 | 
			
		||||
	Elf64_Phdr *phdr;
 | 
			
		||||
	void *notes, *headers;
 | 
			
		||||
	size_t note_bytes, header_bytes;
 | 
			
		||||
	int fd;
 | 
			
		||||
	int i;
 | 
			
		||||
	start_addr_str = 0;
 | 
			
		||||
	if (argc > 2) {
 | 
			
		||||
		fprintf(stderr, "Invalid argument count\n");
 | 
			
		||||
		exit(9);
 | 
			
		||||
	}
 | 
			
		||||
	if (argc == 2) {
 | 
			
		||||
		start_addr_str = argv[1];
 | 
			
		||||
	}
 | 
			
		||||
	if (!start_addr_str) {
 | 
			
		||||
		start_addr_str = getenv("elfcorehdr");
 | 
			
		||||
	}
 | 
			
		||||
	if (!start_addr_str) {
 | 
			
		||||
		fprintf(stderr, "Cannot find the start of the core dump\n");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	}
 | 
			
		||||
	start_addr = strtoull(start_addr_str, &end, 0);
 | 
			
		||||
	if ((start_addr_str == end) || (*end != '\0')) {
 | 
			
		||||
		fprintf(stderr, "Bad core dump start addres: %s\n",
 | 
			
		||||
			start_addr_str);
 | 
			
		||||
		exit(2);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	fd = open(DEV_MEM, O_RDONLY);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		fprintf(stderr, "Cannot open " DEV_MEM ": %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		exit(3);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get the elf header */
 | 
			
		||||
	ehdr = map_addr(fd, sizeof(*ehdr), start_addr);
 | 
			
		||||
 | 
			
		||||
	/* Verify the ELF header */
 | 
			
		||||
	if (	(ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
 | 
			
		||||
		(ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
 | 
			
		||||
		(ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
 | 
			
		||||
		(ehdr->e_ident[EI_MAG3] != ELFMAG3) ||
 | 
			
		||||
		(ehdr->e_ident[EI_CLASS] != ELFCLASS64) ||
 | 
			
		||||
		(ehdr->e_ident[EI_DATA] != ELFDATALOCAL) ||
 | 
			
		||||
		(ehdr->e_ident[EI_VERSION] != EV_CURRENT) ||
 | 
			
		||||
		(ehdr->e_type != ET_CORE) ||
 | 
			
		||||
		(ehdr->e_version != EV_CURRENT) ||
 | 
			
		||||
		(ehdr->e_ehsize != sizeof(Elf64_Ehdr)) ||
 | 
			
		||||
		(ehdr->e_phentsize != sizeof(Elf64_Phdr)) ||
 | 
			
		||||
		(ehdr->e_phnum == 0))
 | 
			
		||||
	{
 | 
			
		||||
		fprintf(stderr, "Invalid Elf header\n");
 | 
			
		||||
		exit(4);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Get the program header */
 | 
			
		||||
	phdr = map_addr(fd, sizeof(*phdr)*(ehdr->e_phnum), ehdr->e_phoff);
 | 
			
		||||
 | 
			
		||||
	/* Collect up the notes */
 | 
			
		||||
	note_bytes = 0;
 | 
			
		||||
	notes = collect_notes(fd, ehdr, phdr, ¬e_bytes);
 | 
			
		||||
	
 | 
			
		||||
	/* Generate new headers */
 | 
			
		||||
	header_bytes = 0;
 | 
			
		||||
	headers = generate_new_headers(ehdr, phdr, note_bytes, &header_bytes);
 | 
			
		||||
 | 
			
		||||
	/* Write out everything */
 | 
			
		||||
	write_all(STDOUT_FILENO, headers, header_bytes);
 | 
			
		||||
	write_all(STDOUT_FILENO, notes, note_bytes);
 | 
			
		||||
	for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
		unsigned long long offset, size;
 | 
			
		||||
		size_t wsize;
 | 
			
		||||
		if (phdr[i].p_type != PT_NOTE) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		offset = phdr[i].p_offset;
 | 
			
		||||
		size   = phdr[i].p_filesz;
 | 
			
		||||
		wsize  = MAP_WINDOW_SIZE;
 | 
			
		||||
		if (wsize > size) {
 | 
			
		||||
			wsize = size;
 | 
			
		||||
		}
 | 
			
		||||
		for(;size > 0; size -= wsize, offset += wsize) {
 | 
			
		||||
			void *buf;
 | 
			
		||||
			wsize = MAP_WINDOW_SIZE;
 | 
			
		||||
			if (wsize > size) {
 | 
			
		||||
				wsize = size;
 | 
			
		||||
			}
 | 
			
		||||
			buf = map_addr(fd, wsize, offset);
 | 
			
		||||
			write_all(STDOUT_FILENO, buf, wsize);
 | 
			
		||||
			unmap_addr(buf, wsize);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	free(notes);
 | 
			
		||||
	close(fd);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								kexec-tools.spec.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								kexec-tools.spec.in
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
Summary: Load one kernel from another
 | 
			
		||||
Name: kexec-tools
 | 
			
		||||
Version: 
 | 
			
		||||
Release: 0
 | 
			
		||||
Copyright: GPL
 | 
			
		||||
Group: Development/Tools
 | 
			
		||||
Source0:%{name}-%{version}.tar.gz
 | 
			
		||||
Packager: Eric Biederman <ebiederman@xmission.com>
 | 
			
		||||
BuildRoot: %{_tmppath}/%{name}
 | 
			
		||||
 | 
			
		||||
%description
 | 
			
		||||
/sbin/kexec is a user space utiltity for loading another kernel
 | 
			
		||||
and asking the currently running kernel to do something with it.
 | 
			
		||||
A currently running kernel may be asked to start the loaded
 | 
			
		||||
kernel on reboot, or to start the loaded kernel after it panics.
 | 
			
		||||
 | 
			
		||||
The panic case is useful for having an intact kernel for writing
 | 
			
		||||
crash dumps.  But other uses may be imagined.
 | 
			
		||||
 | 
			
		||||
%prep
 | 
			
		||||
%setup -q -n %{name}-%{version}
 | 
			
		||||
 | 
			
		||||
%build
 | 
			
		||||
%configure
 | 
			
		||||
make
 | 
			
		||||
 | 
			
		||||
%install
 | 
			
		||||
make install DESTDIR=${RPM_BUILD_ROOT}
 | 
			
		||||
 | 
			
		||||
%files
 | 
			
		||||
%defattr(-,root,root)
 | 
			
		||||
%{_sbindir}/kexec
 | 
			
		||||
%doc News
 | 
			
		||||
%doc COPYING
 | 
			
		||||
%doc TODO
 | 
			
		||||
#%{_mandir}/man8/kexec.8.gz
 | 
			
		||||
 | 
			
		||||
%changelog
 | 
			
		||||
* Tue Dec 16 2004 Eric Biederman <ebiederman@lnxi.com>
 | 
			
		||||
- kexec-tools initialy packaged as an rpm. 
 | 
			
		||||
							
								
								
									
										63
									
								
								kexec/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								kexec/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
#
 | 
			
		||||
# kexec (linux booting linux)
 | 
			
		||||
#
 | 
			
		||||
PURGATORY_HEX_C:= $(OBJDIR)/kexec/purgatory.c
 | 
			
		||||
 | 
			
		||||
$(PURGATORY_HEX_C): $(PURGATORY) $(BIN_TO_HEX)
 | 
			
		||||
	$(MKDIR) -p $(@D)
 | 
			
		||||
	$(BIN_TO_HEX) purgatory < $(PURGATORY) > $@
 | 
			
		||||
 | 
			
		||||
KCFLAGS:= $(CFLAGS) -Ikexec/arch/$(ARCH)/include
 | 
			
		||||
 | 
			
		||||
KEXEC_C_SRCS:= kexec/kexec.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/ifdown.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/kexec-elf.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/kexec-elf-exec.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/kexec-elf-rel.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/kexec-elf-boot.c 
 | 
			
		||||
KEXEC_C_SRCS+= $(PURGATORY_HEX_C)
 | 
			
		||||
KEXEC_S_SRCS:= 
 | 
			
		||||
include kexec/arch/$(ARCH)/Makefile
 | 
			
		||||
 | 
			
		||||
KEXEC_C_OBJS:= $(patsubst %.c, $(OBJDIR)/%.o, $(KEXEC_C_SRCS))
 | 
			
		||||
KEXEC_C_DEPS:= $(patsubst %.c, $(OBJDIR)/%.d, $(KEXEC_C_SRCS))
 | 
			
		||||
KEXEC_S_OBJS:= $(patsubst %.S, $(OBJDIR)/%.o, $(KEXEC_S_SRCS))
 | 
			
		||||
KEXEC_S_DEPS:= $(patsubst %.S, $(OBJDIR)/%.d, $(KEXEC_S_SRCS))
 | 
			
		||||
KEXEC_SRCS:= $(KEXEC_C_SRCS) $(KEXEC_S_SRCS)
 | 
			
		||||
KEXEC_OBJS:= $(KEXEC_C_OBJS) $(KEXEC_S_OBJS)
 | 
			
		||||
KEXEC_DEPS:= $(KEXEC_C_DEPS) $(KEXEC_S_DEPS)
 | 
			
		||||
KEXEC:= $(SBINDIR)/kexec
 | 
			
		||||
 | 
			
		||||
include $(KEXEC_DEPS)
 | 
			
		||||
 | 
			
		||||
$(KEXEC_C_DEPS): $(OBJDIR)/%.d: %.c
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(KCFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
 | 
			
		||||
 | 
			
		||||
$(KEXEC_S_DEPS): $(OBJDIR)/%.d: %.S
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(KCFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
 | 
			
		||||
 | 
			
		||||
$(KEXEC_C_OBJS): $(OBJDIR)/%.o: %.c $(OBJDIR)/%.d
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(KCFLAGS) -o $@ -c $<
 | 
			
		||||
 | 
			
		||||
$(KEXEC_S_OBJS): $(OBJDIR)/%.o: %.S $(OBJDIR)/%.d
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(KCFLAGS) -o $@ -c $<
 | 
			
		||||
 | 
			
		||||
$(KEXEC): $(KEXEC_OBJS) $(UTIL_LIB)
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) $(KCFLAGS) -o $@ $(KEXEC_OBJS) $(UTIL_LIB) $(LIBS)
 | 
			
		||||
 | 
			
		||||
echo::
 | 
			
		||||
	@echo "KEXEC_C_SRCS $(KEXEC_C_SRCS)"
 | 
			
		||||
	@echo "KEXEC_C_DEPS $(KEXEC_C_DEPS)"
 | 
			
		||||
	@echo "KEXEC_C_OBJS $(KEXEC_C_OBJS)"
 | 
			
		||||
	@echo "KEXEC_S_SRCS $(KEXEC_S_SRCS)"
 | 
			
		||||
	@echo "KEXEC_S_DEPS $(KEXEC_S_DEPS)"
 | 
			
		||||
	@echo "KEXEC_S_OBJS $(KEXEC_S_OBJS)"
 | 
			
		||||
	@echo "KEXEC_SRCS $(KEXEC_SRCS)"
 | 
			
		||||
	@echo "KEXEC_DEPS $(KEXEC_DEPS)"
 | 
			
		||||
	@echo "KEXEC_OBJS $(KEXEC_OBJS)"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								kexec/arch/alpha/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								kexec/arch/alpha/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef KEXEC_ARCH_ALPHA_OPTIONS_H
 | 
			
		||||
#define KEXEC_ARCH_ALPHA_OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#define OPT_ARCH_MAX   (OPT_MAX+0)
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPTIONS \
 | 
			
		||||
	KEXEC_OPTIONS \
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_ARCH_ALPHA_OPTIONS_H */
 | 
			
		||||
							
								
								
									
										11
									
								
								kexec/arch/i386/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								kexec/arch/i386/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#
 | 
			
		||||
# kexec i386 (linux booting linux)
 | 
			
		||||
#
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-x86.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-elf-x86.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-elf-rel-x86.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-bzImage.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-multiboot-x86.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-beoboot-x86.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-nbi.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/x86-linux-setup.c
 | 
			
		||||
							
								
								
									
										131
									
								
								kexec/arch/i386/compat_x86_64.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								kexec/arch/i386/compat_x86_64.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004,2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define USE_LRET 0
 | 
			
		||||
	
 | 
			
		||||
.data
 | 
			
		||||
	.equ	MSR_K6_EFER,   0xC0000080
 | 
			
		||||
	.equ	EFER_LME,      0x00000100
 | 
			
		||||
	.equ	X86_CR4_PAE,   0x00000020
 | 
			
		||||
	.equ	CR0_PG,        0x80000000
 | 
			
		||||
 | 
			
		||||
	.globl compat_x86_64, compat_x86_64_size, compat_x86_64_entry32
 | 
			
		||||
	.code64
 | 
			
		||||
	.balign 16	
 | 
			
		||||
compat_x86_64:
 | 
			
		||||
	/* Compute where I am running at */
 | 
			
		||||
	leaq	compat_x86_64(%rip), %rbx
 | 
			
		||||
 | 
			
		||||
	/* Relocate the code */
 | 
			
		||||
	addq	%rbx, gdt_addr(%rip)
 | 
			
		||||
#if !USE_LRET
 | 
			
		||||
	addl	%ebx, lm_exit_addr(%rip)
 | 
			
		||||
#endif	
 | 
			
		||||
 | 
			
		||||
	/* Lookup the 32bit start address */
 | 
			
		||||
	movl	compat_x86_64_entry32(%rip), %ebx
 | 
			
		||||
	pushq	%rbx
 | 
			
		||||
 | 
			
		||||
#if USE_LRET	
 | 
			
		||||
	/* Push the 64bit start address */
 | 
			
		||||
	pushq	$0x10
 | 
			
		||||
	pushq	lm_exit(%rip)
 | 
			
		||||
#endif	
 | 
			
		||||
	
 | 
			
		||||
	/* This also acts as a serializing instruction ensuring
 | 
			
		||||
	 * my self modifying code works.
 | 
			
		||||
	 */
 | 
			
		||||
	lgdt	gdt(%rip)
 | 
			
		||||
 | 
			
		||||
#if USE_LRET
 | 
			
		||||
	lret
 | 
			
		||||
#else				
 | 
			
		||||
	/* Switch to 32bit compatiblity mode */
 | 
			
		||||
	ljmp	*lm_exit_addr(%rip)
 | 
			
		||||
#endif	
 | 
			
		||||
lm_exit:
 | 
			
		||||
	.code32
 | 
			
		||||
 | 
			
		||||
	/* Disable paging */
 | 
			
		||||
	movl	%cr0, %eax
 | 
			
		||||
	andl	$~CR0_PG, %eax
 | 
			
		||||
	movl	%eax, %cr0
 | 
			
		||||
 | 
			
		||||
	/* Disable long mode */
 | 
			
		||||
	movl	$MSR_K6_EFER, %ecx
 | 
			
		||||
	rdmsr
 | 
			
		||||
	andl	$~EFER_LME, %eax
 | 
			
		||||
	wrmsr
 | 
			
		||||
 | 
			
		||||
	/* Disable PAE */
 | 
			
		||||
	xorl	%eax, %eax
 | 
			
		||||
	movl	%eax, %cr4
 | 
			
		||||
 | 
			
		||||
	/* load the data segments */
 | 
			
		||||
	movl	$0x18, %eax	/* data segment */
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	/* Remove the 32 bits of the 64 bit start address */
 | 
			
		||||
	popl	%eax
 | 
			
		||||
 | 
			
		||||
	/* set all of the registers to known values */
 | 
			
		||||
	/* leave %esp alone */
 | 
			
		||||
 | 
			
		||||
	xorl	%eax, %eax
 | 
			
		||||
	xorl	%ebx, %ebx
 | 
			
		||||
	xorl    %ecx, %ecx
 | 
			
		||||
	xorl    %edx, %edx
 | 
			
		||||
	xorl    %esi, %esi
 | 
			
		||||
	xorl    %edi, %edi
 | 
			
		||||
	xorl    %ebp, %ebp
 | 
			
		||||
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.balign 16
 | 
			
		||||
gdt:	/* 0x00 unusable segment 
 | 
			
		||||
	 * 0x08 unused
 | 
			
		||||
	 * so use them as the gdt ptr
 | 
			
		||||
	 */
 | 
			
		||||
	.word	gdt_end - gdt - 1
 | 
			
		||||
gdt_addr:	
 | 
			
		||||
	.quad	gdt - compat_x86_64
 | 
			
		||||
	.word	0, 0, 0
 | 
			
		||||
 | 
			
		||||
	/* 0x10 4GB flat code segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x18 4GB flat data segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
gdt_end:	
 | 
			
		||||
 | 
			
		||||
#if !USE_LRET	
 | 
			
		||||
lm_exit_addr:
 | 
			
		||||
	.long lm_exit - compat_x86_64
 | 
			
		||||
	.long 0x10
 | 
			
		||||
#endif	
 | 
			
		||||
 | 
			
		||||
compat_x86_64_entry32:
 | 
			
		||||
	.long 0  
 | 
			
		||||
	     	
 | 
			
		||||
compat_x86_64_end:
 | 
			
		||||
compat_x86_64_size:
 | 
			
		||||
	.long compat_x86_64_end - compat_x86_64
 | 
			
		||||
							
								
								
									
										22
									
								
								kexec/arch/i386/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								kexec/arch/i386/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
#ifndef KEXEC_ARCH_I386_OPTIONS_H
 | 
			
		||||
#define KEXEC_ARCH_I386_OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#define OPT_RESET_VGA      (OPT_MAX+0)
 | 
			
		||||
#define OPT_SERIAL         (OPT_MAX+1)
 | 
			
		||||
#define OPT_SERIAL_BAUD    (OPT_MAX+2)
 | 
			
		||||
#define OPT_CONSOLE_VGA    (OPT_MAX+3)
 | 
			
		||||
#define OPT_CONSOLE_SERIAL (OPT_MAX+4)
 | 
			
		||||
#define OPT_ARCH_MAX       (OPT_MAX+5)
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPTIONS \
 | 
			
		||||
	KEXEC_OPTIONS \
 | 
			
		||||
	{ "reset-vga",	    0, 0, OPT_RESET_VGA }, \
 | 
			
		||||
	{ "serial",	    1, 0, OPT_SERIAL }, \
 | 
			
		||||
	{ "serial-baud",    1, 0, OPT_SERIAL_BAUD }, \
 | 
			
		||||
	{ "console-vga",    0, 0, OPT_CONSOLE_VGA }, \
 | 
			
		||||
	{ "console-serial", 0, 0, OPT_CONSOLE_SERIAL }, \
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_ARCH_I386_OPTIONS_H */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										140
									
								
								kexec/arch/i386/kexec-beoboot-x86.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								kexec/arch/i386/kexec-beoboot-x86.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
			
		||||
/*------------------------------------------------------------ -*- C -*-
 | 
			
		||||
 *  Eric Biederman <ebiederman@xmission.com>
 | 
			
		||||
 *  Erik Arjan Hendriks <hendriks@lanl.gov>
 | 
			
		||||
 *
 | 
			
		||||
 *  14 December 2004
 | 
			
		||||
 *  This file is a derivative of the beoboot image loader, modified
 | 
			
		||||
 *  to work with kexec.  
 | 
			
		||||
 *
 | 
			
		||||
 *  This version is derivative from the orignal mkbootimg.c which is
 | 
			
		||||
 *  Copyright (C) 2000 Scyld Computing Corporation
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 *  it under the terms of the GNU General Public License as published by
 | 
			
		||||
 *  the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 *  (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
 * 
 | 
			
		||||
 *--------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <x86/x86-linux.h>
 | 
			
		||||
#include <boot/beoboot.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "kexec-x86.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
int beoboot_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct beoboot_header bb_header;
 | 
			
		||||
	const char *cmdline, *kernel;
 | 
			
		||||
	int result;
 | 
			
		||||
	if (len < sizeof(bb_header)) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(&bb_header, buf, sizeof(bb_header));
 | 
			
		||||
	if (memcmp(bb_header.magic, BEOBOOT_MAGIC, 4) != 0) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (bb_header.arch != BEOBOOT_ARCH) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Make certain a bzImage is packed into there.
 | 
			
		||||
	 */
 | 
			
		||||
	cmdline = buf + sizeof(bb_header);
 | 
			
		||||
	kernel  = cmdline + bb_header.cmdline_size;
 | 
			
		||||
	result = bzImage_probe(kernel, bb_header.kernel_size);
 | 
			
		||||
	
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void beoboot_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(	"-d, --debug               Enable debugging to help spot a failure.\n"
 | 
			
		||||
		"    --real-mode           Use the kernels real mode entry point.\n"
 | 
			
		||||
		);
 | 
			
		||||
       
 | 
			
		||||
	/* No parameters are parsed */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define SETUP_BASE    0x90000
 | 
			
		||||
#define KERN32_BASE  0x100000 /* 1MB */
 | 
			
		||||
#define INITRD_BASE 0x1000000 /* 16MB */
 | 
			
		||||
 | 
			
		||||
int beoboot_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct beoboot_header bb_header;
 | 
			
		||||
	const unsigned char *command_line, *kernel, *initrd;
 | 
			
		||||
 | 
			
		||||
	int debug, real_mode_entry;
 | 
			
		||||
	int opt;
 | 
			
		||||
	int result;
 | 
			
		||||
#define OPT_REAL_MODE	(OPT_ARCH_MAX+0)
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ "debug",		0, 0, OPT_DEBUG },
 | 
			
		||||
		{ "real-mode",		0, 0, OPT_REAL_MODE },
 | 
			
		||||
		{ 0, 			0, 0, 0 },
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR "";
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Parse the command line arguments
 | 
			
		||||
	 */
 | 
			
		||||
	debug = 0;
 | 
			
		||||
	real_mode_entry = 0;
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_DEBUG:
 | 
			
		||||
			debug = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_REAL_MODE:
 | 
			
		||||
			real_mode_entry = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Parse the file
 | 
			
		||||
	 */
 | 
			
		||||
	memcpy(&bb_header, buf, sizeof(bb_header));
 | 
			
		||||
	command_line   = buf + sizeof(bb_header);
 | 
			
		||||
	kernel         = command_line + bb_header.cmdline_size;
 | 
			
		||||
	initrd         = NULL;
 | 
			
		||||
	if (bb_header.flags & BEOBOOT_INITRD_PRESENT) {
 | 
			
		||||
		initrd = kernel + bb_header.kernel_size;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	result = do_bzImage_load(info,
 | 
			
		||||
		kernel,        bb_header.kernel_size,
 | 
			
		||||
		command_line,  bb_header.cmdline_size,
 | 
			
		||||
		initrd,        bb_header.initrd_size,
 | 
			
		||||
		real_mode_entry, debug);
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										296
									
								
								kexec/arch/i386/kexec-bzImage.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								kexec/arch/i386/kexec-bzImage.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,296 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include <ip_checksum.h>
 | 
			
		||||
#include <x86/x86-linux.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "kexec-x86.h"
 | 
			
		||||
#include "x86-linux-setup.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
int bzImage_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct x86_linux_header header;
 | 
			
		||||
	if (len < sizeof(header)) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(&header, buf, sizeof(header));
 | 
			
		||||
	if (memcmp(header.header_magic, "HdrS", 4) != 0) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not a bzImage\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (header.boot_sector_magic != 0xAA55) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "No x86 boot sector present\n");
 | 
			
		||||
		}
 | 
			
		||||
		/* No x86 boot sector present */
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (header.protocol_version < 0x0200) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Must be at least protocol version 2.00\n");
 | 
			
		||||
		}
 | 
			
		||||
		/* Must be at least protocol version 2.00 */
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if ((header.loadflags & 1) == 0) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "zImage not a bzImage\n");
 | 
			
		||||
		}
 | 
			
		||||
		/* Not a bzImage */
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* I've got a bzImage */
 | 
			
		||||
	if (probe_debug) {
 | 
			
		||||
		fprintf(stderr, "It's a bzImage\n");
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void bzImage_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(	"-d, --debug               Enable debugging to help spot a failure.\n"
 | 
			
		||||
		"    --real-mode           Use the kernels real mode entry point.\n"
 | 
			
		||||
		"    --command-line=STRING Set the kernel command line to STRING.\n"
 | 
			
		||||
		"    --append=STRING       Set the kernel command line to STRING.\n"
 | 
			
		||||
		"    --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
 | 
			
		||||
		"    --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
 | 
			
		||||
		);
 | 
			
		||||
       
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int do_bzImage_load(struct kexec_info *info,
 | 
			
		||||
	const char *kernel, off_t kernel_len,
 | 
			
		||||
	const char *command_line, off_t command_line_len,
 | 
			
		||||
	const char *initrd, off_t initrd_len,
 | 
			
		||||
	int real_mode_entry, int debug)
 | 
			
		||||
{
 | 
			
		||||
	struct x86_linux_header setup_header;
 | 
			
		||||
	struct x86_linux_param_header *real_mode;
 | 
			
		||||
	int setup_sects;
 | 
			
		||||
	char *kernel_version;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	int kern16_size;
 | 
			
		||||
	unsigned long setup_base, setup_size;
 | 
			
		||||
	struct entry32_regs regs32;
 | 
			
		||||
	struct entry16_regs regs16;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Find out about the file I am about to load.
 | 
			
		||||
	 */
 | 
			
		||||
	if (kernel_len < sizeof(setup_header)) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(&setup_header, kernel, sizeof(setup_header));
 | 
			
		||||
	setup_sects = setup_header.setup_sects;
 | 
			
		||||
	if (setup_sects == 0) {
 | 
			
		||||
		setup_sects = 4;
 | 
			
		||||
	}
 | 
			
		||||
	kern16_size = (setup_sects +1) *512;
 | 
			
		||||
	kernel_version = ((unsigned char *)&setup_header) + 512 + setup_header.kver_addr;
 | 
			
		||||
	if (kernel_len < kern16_size) {
 | 
			
		||||
		fprintf(stderr, "BzImage truncated?\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load the trampoline.  This must load at a higher address
 | 
			
		||||
	 * the the argument/parameter segment or the kernel will stomp
 | 
			
		||||
	 * it's gdt.
 | 
			
		||||
	 */
 | 
			
		||||
	elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
 | 
			
		||||
		0x3000, 640*1024, -1);
 | 
			
		||||
 | 
			
		||||
	/* The argument/parameter segment */
 | 
			
		||||
	setup_size = kern16_size + command_line_len;
 | 
			
		||||
	real_mode = xmalloc(setup_size);
 | 
			
		||||
	memcpy(real_mode, kernel, kern16_size);
 | 
			
		||||
	if (real_mode->protocol_version >= 0x0200) {
 | 
			
		||||
		/* Careful setup_base must be greater than 8K */
 | 
			
		||||
		setup_base = add_buffer(info, real_mode, setup_size, setup_size,
 | 
			
		||||
			16, 0x3000, 640*1024, -1);
 | 
			
		||||
	} else {
 | 
			
		||||
		add_segment(info, real_mode, setup_size, SETUP_BASE, setup_size);
 | 
			
		||||
		setup_base = SETUP_BASE;
 | 
			
		||||
	}
 | 
			
		||||
	/* Verify purgatory loads higher than the parameters */
 | 
			
		||||
	if (info->rhdr.rel_addr < setup_base) {
 | 
			
		||||
		die("Could not put setup code above the kernel parameters\n");
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* The main kernel segment */
 | 
			
		||||
	size = kernel_len - kern16_size;
 | 
			
		||||
	add_segment(info, kernel + kern16_size, size, KERN32_BASE,  size);
 | 
			
		||||
 | 
			
		||||
		
 | 
			
		||||
	/* Tell the kernel what is going on */
 | 
			
		||||
	setup_linux_bootloader_parameters(info, real_mode, setup_base,
 | 
			
		||||
		kern16_size, command_line, command_line_len,
 | 
			
		||||
		initrd, initrd_len);
 | 
			
		||||
 | 
			
		||||
	/* Get the initial register values */
 | 
			
		||||
	elf_rel_get_symbol(&info->rhdr, "entry16_regs", ®s16, sizeof(regs16));
 | 
			
		||||
	elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s32, sizeof(regs32));
 | 
			
		||||
	/*
 | 
			
		||||
 | 
			
		||||
	 * Initialize the 32bit start information.
 | 
			
		||||
	 */
 | 
			
		||||
	regs32.eax = 0; /* unused */
 | 
			
		||||
	regs32.ebx = 0; /* 0 == boot not AP processor start */
 | 
			
		||||
	regs32.ecx = 0; /* unused */
 | 
			
		||||
	regs32.edx = 0; /* unused */
 | 
			
		||||
	regs32.esi = setup_base; /* kernel parameters */
 | 
			
		||||
	regs32.edi = 0; /* unused */
 | 
			
		||||
	regs32.esp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* stack, unused */
 | 
			
		||||
	regs32.ebp = 0; /* unused */
 | 
			
		||||
	regs32.eip = KERN32_BASE; /* kernel entry point */
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Initialize the 16bit start information.
 | 
			
		||||
	 */
 | 
			
		||||
	regs16.cs = setup_base + 0x20;
 | 
			
		||||
	regs16.ip = 0;
 | 
			
		||||
	regs16.ss = (elf_rel_get_addr(&info->rhdr, "stack_end") - 64*1024) >> 4;
 | 
			
		||||
	regs16.esp = 0xFFFC;
 | 
			
		||||
	if (real_mode_entry) {
 | 
			
		||||
		printf("Starting the kernel in real mode\n");
 | 
			
		||||
		regs32.eip = elf_rel_get_addr(&info->rhdr, "entry16");
 | 
			
		||||
	}
 | 
			
		||||
	if (real_mode && debug) {
 | 
			
		||||
		unsigned long entry16_debug, pre32, first32;
 | 
			
		||||
		uint32_t old_first32;
 | 
			
		||||
		/* Find the location of the symbols */
 | 
			
		||||
		entry16_debug = elf_rel_get_addr(&info->rhdr, "entry16_debug");
 | 
			
		||||
		pre32 = elf_rel_get_addr(&info->rhdr, "entry16_debug_pre32");
 | 
			
		||||
		first32 = elf_rel_get_addr(&info->rhdr, "entry16_debug_first32");
 | 
			
		||||
		
 | 
			
		||||
		/* Hook all of the linux kernel hooks */
 | 
			
		||||
		real_mode->rmode_switch_cs = entry16_debug >> 4;
 | 
			
		||||
		real_mode->rmode_switch_ip = pre32 - entry16_debug;
 | 
			
		||||
		old_first32 = real_mode->kernel_start;
 | 
			
		||||
		real_mode->kernel_start = first32;
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry16_debug_old_first32",
 | 
			
		||||
			&old_first32, sizeof(old_first32));
 | 
			
		||||
	
 | 
			
		||||
		regs32.eip = entry16_debug;
 | 
			
		||||
	}
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "entry16_regs", ®s16, sizeof(regs16));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "entry16_debug_regs", ®s16, sizeof(regs16));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s32, sizeof(regs32));
 | 
			
		||||
 | 
			
		||||
	/* Fill in the information BIOS calls would normally provide. */
 | 
			
		||||
	if (!real_mode_entry) {
 | 
			
		||||
		setup_linux_system_parameters(real_mode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
	
 | 
			
		||||
int bzImage_load(int argc, char **argv, const char *buf, off_t len, 
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	const char *command_line;
 | 
			
		||||
	const char *ramdisk;
 | 
			
		||||
	char *ramdisk_buf;
 | 
			
		||||
	off_t ramdisk_length;
 | 
			
		||||
	int command_line_len;
 | 
			
		||||
	int debug, real_mode_entry;
 | 
			
		||||
	int opt;
 | 
			
		||||
	int result;
 | 
			
		||||
#define OPT_APPEND	(OPT_ARCH_MAX+0)
 | 
			
		||||
#define OPT_RAMDISK	(OPT_ARCH_MAX+1)
 | 
			
		||||
#define OPT_REAL_MODE	(OPT_ARCH_MAX+2)
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ "debug",		0, 0, OPT_DEBUG },
 | 
			
		||||
		{ "command-line",	1, 0, OPT_APPEND },
 | 
			
		||||
		{ "append",		1, 0, OPT_APPEND },
 | 
			
		||||
		{ "initrd",		1, 0, OPT_RAMDISK },
 | 
			
		||||
		{ "ramdisk",		1, 0, OPT_RAMDISK },
 | 
			
		||||
		{ "real-mode",		0, 0, OPT_REAL_MODE },
 | 
			
		||||
		{ 0, 			0, 0, 0 },
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Parse the command line arguments
 | 
			
		||||
	 */
 | 
			
		||||
	debug = 0;
 | 
			
		||||
	real_mode_entry = 0;
 | 
			
		||||
	command_line = 0;
 | 
			
		||||
	ramdisk = 0;
 | 
			
		||||
	ramdisk_length = 0;
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_DEBUG:
 | 
			
		||||
			debug = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_APPEND:
 | 
			
		||||
			command_line = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_RAMDISK:
 | 
			
		||||
			ramdisk = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_REAL_MODE:
 | 
			
		||||
			real_mode_entry = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	command_line_len = 0;
 | 
			
		||||
	if (command_line) {
 | 
			
		||||
		command_line_len = strlen(command_line) +1;
 | 
			
		||||
	}
 | 
			
		||||
	ramdisk_buf = 0;
 | 
			
		||||
	if (ramdisk) {
 | 
			
		||||
		ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
 | 
			
		||||
	}
 | 
			
		||||
	result = do_bzImage_load(info,
 | 
			
		||||
		buf, len,
 | 
			
		||||
		command_line, command_line_len,
 | 
			
		||||
		ramdisk_buf, ramdisk_length,
 | 
			
		||||
		real_mode_entry, debug);
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								kexec/arch/i386/kexec-elf-rel-x86.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								kexec/arch/i386/kexec-elf-rel-x86.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
int machine_verify_elf_rel(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data != ELFDATA2LSB) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->ei_class != ELFCLASS32) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ehdr->e_machine != EM_386) && (ehdr->e_machine != EM_486)) 
 | 
			
		||||
	{
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
 | 
			
		||||
	void *location, unsigned long address, unsigned long value)
 | 
			
		||||
{
 | 
			
		||||
	switch(r_type) {
 | 
			
		||||
	case R_386_32:
 | 
			
		||||
		*((uint32_t *)location) += value;
 | 
			
		||||
		break;
 | 
			
		||||
	case R_386_PC32:
 | 
			
		||||
		*((uint32_t *)location) += value - address;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		die("Unknown rel relocation: %lu\n", r_type);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										245
									
								
								kexec/arch/i386/kexec-elf-x86.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								kexec/arch/i386/kexec-elf-x86.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,245 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <x86/x86-linux.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "../../kexec-elf-boot.h"
 | 
			
		||||
#include "x86-linux-setup.h"
 | 
			
		||||
#include "kexec-x86.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
int elf_x86_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not an ELF executable\n");
 | 
			
		||||
		}
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Verify the architecuture specific bits */
 | 
			
		||||
	if ((ehdr.e_machine != EM_386) && (ehdr.e_machine != EM_486)) {
 | 
			
		||||
		/* for a different architecture */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not x86_64 ELF executable\n");
 | 
			
		||||
		}
 | 
			
		||||
		result = -1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	result = 0;
 | 
			
		||||
 out:
 | 
			
		||||
	free_elf_info(&ehdr);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_x86_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(	"    --command-line=STRING Set the kernel command line to STRING\n"
 | 
			
		||||
		"    --append=STRING       Set the kernel command line to STRING\n"
 | 
			
		||||
		"    --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
 | 
			
		||||
		"    --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
 | 
			
		||||
		"    --args-linux          Pass linux kernel style options\n"
 | 
			
		||||
		"    --args-elf            Pass elf boot notes\n"
 | 
			
		||||
		);
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_x86_load(int argc, char **argv, const char *buf, off_t len, 
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	const char *command_line;
 | 
			
		||||
	int command_line_len;
 | 
			
		||||
	const char *ramdisk;
 | 
			
		||||
	unsigned long entry, max_addr;
 | 
			
		||||
	int arg_style;
 | 
			
		||||
#define ARG_STYLE_ELF   0
 | 
			
		||||
#define ARG_STYLE_LINUX 1
 | 
			
		||||
#define ARG_STYLE_NONE  2
 | 
			
		||||
	int opt;
 | 
			
		||||
#define OPT_APPEND	(OPT_ARCH_MAX+0)
 | 
			
		||||
#define OPT_RAMDISK	(OPT_ARCH_MAX+1)
 | 
			
		||||
#define OPT_ARGS_ELF    (OPT_ARCH_MAX+2)
 | 
			
		||||
#define OPT_ARGS_LINUX  (OPT_ARCH_MAX+3)
 | 
			
		||||
#define OPT_ARGS_NONE   (OPT_ARCH_MAX+4)
 | 
			
		||||
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ "command-line",	1, NULL, OPT_APPEND },
 | 
			
		||||
		{ "append",		1, NULL, OPT_APPEND },
 | 
			
		||||
		{ "initrd",		1, NULL, OPT_RAMDISK },
 | 
			
		||||
		{ "ramdisk",		1, NULL, OPT_RAMDISK },
 | 
			
		||||
		{ "args-elf",		0, NULL, OPT_ARGS_ELF },
 | 
			
		||||
		{ "args-linux",		0, NULL, OPT_ARGS_LINUX },
 | 
			
		||||
		{ "args-none",		0, NULL, OPT_ARGS_NONE },
 | 
			
		||||
		{ 0, 			0, NULL, 0 },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static const char short_options[] = KEXEC_OPT_STR "";
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Parse the command line arguments
 | 
			
		||||
	 */
 | 
			
		||||
	arg_style = ARG_STYLE_ELF;
 | 
			
		||||
	command_line = 0;
 | 
			
		||||
	ramdisk = 0;
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_APPEND:
 | 
			
		||||
			command_line = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_RAMDISK:
 | 
			
		||||
			ramdisk = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_ARGS_ELF: 
 | 
			
		||||
			arg_style = ARG_STYLE_ELF;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_ARGS_LINUX:
 | 
			
		||||
			arg_style = ARG_STYLE_LINUX;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_ARGS_NONE:
 | 
			
		||||
#ifdef __i386___
 | 
			
		||||
			arg_style = ARG_STYLE_NONE;
 | 
			
		||||
#else
 | 
			
		||||
			die("--args-none only works on arch i386\n");
 | 
			
		||||
#endif
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	command_line_len = 0;
 | 
			
		||||
	if (command_line) {
 | 
			
		||||
		command_line_len = strlen(command_line) +1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load the ELF executable */
 | 
			
		||||
	elf_exec_build_load(info, &ehdr, buf, len);
 | 
			
		||||
 | 
			
		||||
	entry = ehdr.e_entry;
 | 
			
		||||
	max_addr = elf_max_addr(&ehdr);
 | 
			
		||||
 | 
			
		||||
	/* Do we want arguments? */
 | 
			
		||||
	if (arg_style != ARG_STYLE_NONE) {
 | 
			
		||||
		/* Load the setup code */
 | 
			
		||||
		elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
 | 
			
		||||
			0, ULONG_MAX, 1);
 | 
			
		||||
	}
 | 
			
		||||
	if (arg_style == ARG_STYLE_NONE) {
 | 
			
		||||
		info->entry = (void *)entry;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	else if (arg_style == ARG_STYLE_ELF) {
 | 
			
		||||
		unsigned long note_base;
 | 
			
		||||
		struct entry32_regs regs;
 | 
			
		||||
		uint32_t arg1, arg2;
 | 
			
		||||
 | 
			
		||||
		/* Setup the ELF boot notes */
 | 
			
		||||
		note_base = elf_boot_notes(info, max_addr,
 | 
			
		||||
			command_line, command_line_len);
 | 
			
		||||
 | 
			
		||||
		/* Initialize the stack arguments */
 | 
			
		||||
		arg2 = 0; /* No return address */
 | 
			
		||||
		arg1 = note_base;
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "stack_arg32_1", &arg1, sizeof(arg1));
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "stack_arg32_2", &arg2, sizeof(arg2));
 | 
			
		||||
		
 | 
			
		||||
		/* Initialize the registers */
 | 
			
		||||
		elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs));
 | 
			
		||||
		regs.eip = entry;       /* The entry point */
 | 
			
		||||
		regs.esp = elf_rel_get_addr(&info->rhdr, "stack_arg32_2");
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs));
 | 
			
		||||
 | 
			
		||||
		if (ramdisk) {
 | 
			
		||||
			die("Ramdisks not supported with generic elf arguments");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (arg_style == ARG_STYLE_LINUX) {
 | 
			
		||||
		struct x86_linux_faked_param_header *hdr;
 | 
			
		||||
		unsigned long param_base;
 | 
			
		||||
		const unsigned char *ramdisk_buf;
 | 
			
		||||
		off_t ramdisk_length;
 | 
			
		||||
		struct entry32_regs regs;
 | 
			
		||||
 | 
			
		||||
		/* Get the linux parameter header */
 | 
			
		||||
		hdr = xmalloc(sizeof(*hdr));
 | 
			
		||||
		param_base = add_buffer(info, hdr, sizeof(*hdr), sizeof(*hdr),
 | 
			
		||||
			16, 0, max_addr, 1);
 | 
			
		||||
 | 
			
		||||
		/* Initialize the parameter header */
 | 
			
		||||
		memset(hdr, 0, sizeof(*hdr));
 | 
			
		||||
		init_linux_parameters(&hdr->hdr);
 | 
			
		||||
 | 
			
		||||
		/* Add a ramdisk to the current image */
 | 
			
		||||
		ramdisk_buf = NULL;
 | 
			
		||||
		ramdisk_length = 0;
 | 
			
		||||
		if (ramdisk) {
 | 
			
		||||
			unsigned char *ramdisk_buf;
 | 
			
		||||
			ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Tell the kernel what is going on */
 | 
			
		||||
		setup_linux_bootloader_parameters(info, &hdr->hdr, param_base, 
 | 
			
		||||
			offsetof(struct x86_linux_faked_param_header, command_line),
 | 
			
		||||
			command_line, command_line_len,
 | 
			
		||||
			ramdisk_buf, ramdisk_length);
 | 
			
		||||
 | 
			
		||||
		/* Fill in the information bios calls would usually provide */
 | 
			
		||||
		setup_linux_system_parameters(&hdr->hdr);
 | 
			
		||||
 | 
			
		||||
		/* Initialize the registers */
 | 
			
		||||
		elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs));
 | 
			
		||||
		regs.ebx = 0;		/* Bootstrap processor */
 | 
			
		||||
		regs.esi = param_base;	/* Pointer to the parameters */
 | 
			
		||||
		regs.eip = entry;	/* The entry point */
 | 
			
		||||
		regs.esp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs));
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Unknown argument style\n");
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										393
									
								
								kexec/arch/i386/kexec-multiboot-x86.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										393
									
								
								kexec/arch/i386/kexec-multiboot-x86.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,393 @@
 | 
			
		||||
/*
 | 
			
		||||
 *  kexec-multiboot-x86.c
 | 
			
		||||
 *
 | 
			
		||||
 *  (partial) multiboot support for kexec.  Only supports ELF32 
 | 
			
		||||
 *  kernels, and a subset of the multiboot info page options 
 | 
			
		||||
 *  (i.e. enough to boot the Xen hypervisor).
 | 
			
		||||
 * 
 | 
			
		||||
 *  TODO:  
 | 
			
		||||
 *    - smarter allocation of new segments
 | 
			
		||||
 *    - proper support for the MULTIBOOT_VIDEO_MODE bit
 | 
			
		||||
 *    - support for the MULTIBOOT_AOUT_KLUDGE bit
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 *  Copyright (C) 2003  Tim Deegan (tjd21 at cl.cam.ac.uk)
 | 
			
		||||
 * 
 | 
			
		||||
 *  Parts based on GNU GRUB, Copyright (C) 2000  Free Software Foundation, Inc
 | 
			
		||||
 *  Parts copied from kexec-elf32-x86.c, written by Eric Biederman
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is free software; you can redistribute it and/or
 | 
			
		||||
 *  modify it under the terms of the GNU General Public License as
 | 
			
		||||
 *  published by the Free Software Foundation; either version 2 of the
 | 
			
		||||
 *  License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 *  This program is distributed in the hope that it will be useful,
 | 
			
		||||
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 *  General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 *  You should have received a copy of the GNU General Public License
 | 
			
		||||
 *  along with this program; if not, write to the Free Software
 | 
			
		||||
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 | 
			
		||||
 *  02111-1307, USA.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include <asm/page.h>
 | 
			
		||||
#include <ip_checksum.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "kexec-x86.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
/* From GNU GRUB */
 | 
			
		||||
#include <x86/mb_header.h>
 | 
			
		||||
#include <x86/mb_info.h>
 | 
			
		||||
 | 
			
		||||
/* Static storage */
 | 
			
		||||
static char headerbuf[MULTIBOOT_SEARCH];
 | 
			
		||||
static struct multiboot_header *mbh = NULL;
 | 
			
		||||
 | 
			
		||||
#define BOOTLOADER "kexec"
 | 
			
		||||
#define BOOTLOADER_VERSION VERSION
 | 
			
		||||
#define MIN(_x,_y) (((_x)<=(_y))?(_x):(_y))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int multiboot_x86_probe(const char *buf, off_t buf_len)
 | 
			
		||||
/* Is it a good idea to try booting this file? */
 | 
			
		||||
{
 | 
			
		||||
	int i, len;
 | 
			
		||||
	/* First of all, check that this is an ELF file */
 | 
			
		||||
	if ((i=elf_x86_probe(buf, buf_len)) < 0) {
 | 
			
		||||
		return i;
 | 
			
		||||
	}
 | 
			
		||||
	/* Now look for a multiboot header in the first 8KB */
 | 
			
		||||
	len = MULTIBOOT_SEARCH;
 | 
			
		||||
	if (len > buf_len) {
 | 
			
		||||
		len = buf_len;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(headerbuf, buf, len);
 | 
			
		||||
	if (len < 12) {
 | 
			
		||||
		/* Short file */
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i <= (len - 12); i += 4)
 | 
			
		||||
	{
 | 
			
		||||
		/* Search for a multiboot header */
 | 
			
		||||
		mbh = (struct multiboot_header *)(headerbuf + i);
 | 
			
		||||
		if (mbh->magic != MULTIBOOT_MAGIC 
 | 
			
		||||
		    || ((mbh->magic+mbh->flags+mbh->checksum) & 0xffffffff))
 | 
			
		||||
		{
 | 
			
		||||
			/* Not a multiboot header */
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) {
 | 
			
		||||
			/* Requires options we don't support */
 | 
			
		||||
			fprintf(stderr, 
 | 
			
		||||
				"Found a multiboot header, but it uses "
 | 
			
		||||
				"a non-ELF header layout,\n"
 | 
			
		||||
				"and I can't do that (yet).  Sorry.\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		} 
 | 
			
		||||
		if (mbh->flags & MULTIBOOT_UNSUPPORTED) {
 | 
			
		||||
			/* Requires options we don't support */
 | 
			
		||||
			fprintf(stderr, 
 | 
			
		||||
				"Found a multiboot header, but it "
 | 
			
		||||
				"requires multiboot options that I\n"
 | 
			
		||||
				"don't understand.  Sorry.\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		} 
 | 
			
		||||
		if (mbh->flags & MULTIBOOT_VIDEO_MODE) { 
 | 
			
		||||
			/* Asked for screen mode information */
 | 
			
		||||
			/* XXX carry on regardless */
 | 
			
		||||
			fprintf(stderr, 
 | 
			
		||||
				"BEWARE!  Found a multiboot header which asks "
 | 
			
		||||
				"for screen mode information.\n"
 | 
			
		||||
				"BEWARE!  I am NOT supplying screen mode "
 | 
			
		||||
                                "information, but loading it regardless.\n");
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
		/* Bootable */
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	/* Not multiboot */
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void multiboot_x86_usage(void)
 | 
			
		||||
/* Multiboot-specific options */
 | 
			
		||||
{
 | 
			
		||||
	printf("    --command-line=STRING        Set the kernel command line to STRING.\n");
 | 
			
		||||
	printf("    --module=\"MOD arg1 arg2...\"  Load module MOD with command-line \"arg1...\"\n");
 | 
			
		||||
	printf("                                 (can be used multiple times).\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int multiboot_x86_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
/* Marshal up a multiboot-style kernel */
 | 
			
		||||
{
 | 
			
		||||
	struct multiboot_info *mbi;
 | 
			
		||||
	void   *mbi_buf;
 | 
			
		||||
	struct mod_list *modp;
 | 
			
		||||
	unsigned long freespace;
 | 
			
		||||
	unsigned long long mem_lower = 0, mem_upper = 0;
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	unsigned long mbi_base;
 | 
			
		||||
	struct entry32_regs regs;
 | 
			
		||||
	size_t mbi_bytes, mbi_offset;
 | 
			
		||||
	const char *command_line=NULL;
 | 
			
		||||
	char *imagename, *cp;
 | 
			
		||||
	struct memory_range *range;
 | 
			
		||||
	int ranges;
 | 
			
		||||
	struct AddrRangeDesc *mmap;
 | 
			
		||||
	int command_line_len;
 | 
			
		||||
	int i;
 | 
			
		||||
	int opt;
 | 
			
		||||
	int modules, mod_command_line_space;
 | 
			
		||||
#define OPT_CL  	(OPT_ARCH_MAX+0)
 | 
			
		||||
#define OPT_MOD 	(OPT_ARCH_MAX+1)
 | 
			
		||||
#define OPT_VGA 	(OPT_ARCH_MAX+2)
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ "command-line",		1, 0, OPT_CL },
 | 
			
		||||
		{ "append",			1, 0, OPT_CL },
 | 
			
		||||
		{ "module",			1, 0, OPT_MOD },
 | 
			
		||||
		{ 0, 				0, 0, 0 },
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR "";
 | 
			
		||||
	
 | 
			
		||||
	/* Probe for the MB header if it's not already found */
 | 
			
		||||
	if (mbh == NULL && multiboot_x86_probe(buf, len) != 1) 
 | 
			
		||||
	{
 | 
			
		||||
		fprintf(stderr, "Cannot find a loadable multiboot header.\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* Parse the command line */
 | 
			
		||||
	command_line = "";
 | 
			
		||||
	command_line_len = 0;
 | 
			
		||||
	modules = 0;
 | 
			
		||||
	mod_command_line_space = 0;
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1)
 | 
			
		||||
	{
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_CL:
 | 
			
		||||
			command_line = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_MOD:
 | 
			
		||||
			modules++;
 | 
			
		||||
			mod_command_line_space += strlen(optarg) + 1;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	imagename = argv[optind];
 | 
			
		||||
	command_line_len = strlen(command_line) + strlen(imagename) + 2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* Load the ELF executable */
 | 
			
		||||
	elf_exec_build_load(info, &ehdr, buf, len);
 | 
			
		||||
 | 
			
		||||
	/* Load the setup code */
 | 
			
		||||
	elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0, ULONG_MAX, 1);
 | 
			
		||||
	
 | 
			
		||||
	/* The first segment will contain the multiboot headers:
 | 
			
		||||
	 * =============
 | 
			
		||||
	 * multiboot information (mbi)
 | 
			
		||||
	 * -------------
 | 
			
		||||
	 * kernel command line
 | 
			
		||||
	 * -------------
 | 
			
		||||
	 * bootloader name
 | 
			
		||||
	 * -------------
 | 
			
		||||
	 * module information entries
 | 
			
		||||
	 * -------------
 | 
			
		||||
	 * module command lines
 | 
			
		||||
	 * ==============
 | 
			
		||||
	 */
 | 
			
		||||
	mbi_bytes = (sizeof(*mbi) + command_line_len 
 | 
			
		||||
		     + strlen (BOOTLOADER " " BOOTLOADER_VERSION) + 1
 | 
			
		||||
		     + 3) & ~3;
 | 
			
		||||
	mbi_buf = xmalloc(mbi_bytes);
 | 
			
		||||
	mbi = mbi_buf;
 | 
			
		||||
	memset(mbi, 0, sizeof(*mbi));
 | 
			
		||||
	sprintf(((char *)mbi) + sizeof(*mbi), "%s %s",
 | 
			
		||||
		imagename, command_line);
 | 
			
		||||
	sprintf(((char *)mbi) + sizeof(*mbi) + command_line_len, "%s",
 | 
			
		||||
		BOOTLOADER " " BOOTLOADER_VERSION);
 | 
			
		||||
	mbi->flags = MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME;
 | 
			
		||||
	/* We'll relocate these to absolute addresses later. For now,
 | 
			
		||||
	 * all addresses within the first segment are relative to the
 | 
			
		||||
	 * start of the MBI. */
 | 
			
		||||
	mbi->cmdline = sizeof(*mbi); 
 | 
			
		||||
	mbi->boot_loader_name = sizeof(*mbi) + command_line_len; 
 | 
			
		||||
 | 
			
		||||
	/* Memory map */
 | 
			
		||||
	if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) {
 | 
			
		||||
		fprintf(stderr, "Cannot get memory information\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	mmap = xmalloc(ranges * sizeof(*mmap));
 | 
			
		||||
	for (i=0; i<ranges; i++) {
 | 
			
		||||
		unsigned long long length;
 | 
			
		||||
		length = range[i].end - range[i].start;
 | 
			
		||||
		/* Translate bzImage mmap to multiboot-speak */
 | 
			
		||||
		mmap[i].size = sizeof(mmap[i]) - 4;
 | 
			
		||||
		mmap[i].base_addr_low  = range[i].start & 0xffffffff;
 | 
			
		||||
		mmap[i].base_addr_high  = range[i].start >> 32;
 | 
			
		||||
		mmap[i].length_low     = length & 0xffffffff;
 | 
			
		||||
		mmap[i].length_high    = length >> 32;
 | 
			
		||||
		if (range[i].type == RANGE_RAM) {
 | 
			
		||||
			mmap[i].Type = 1; /* RAM */
 | 
			
		||||
			/* Is this the "low" memory? */
 | 
			
		||||
			if ((range[i].start == 0)
 | 
			
		||||
			    && (range[i].end > mem_lower))
 | 
			
		||||
				mem_lower = range[i].end;
 | 
			
		||||
			/* Is this the "high" memory? */
 | 
			
		||||
			if ((range[i].start <= 0x100000)
 | 
			
		||||
			    && (range[i].end > mem_upper + 0x100000))
 | 
			
		||||
				mem_upper = range[i].end - 0x100000;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		mmap[i].Type = 0xbad;  /* Not RAM */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (mbh->flags & MULTIBOOT_MEMORY_INFO) { 
 | 
			
		||||
		/* Provide a copy of the memory map to the kernel */
 | 
			
		||||
 | 
			
		||||
		mbi->flags |= MB_INFO_MEMORY | MB_INFO_MEM_MAP;
 | 
			
		||||
		
 | 
			
		||||
		freespace = add_buffer(info,
 | 
			
		||||
			mmap, ranges * sizeof(*mmap), ranges * sizeof(*mmap),
 | 
			
		||||
			4, 0, 0xFFFFFFFFUL, 1);
 | 
			
		||||
 | 
			
		||||
		mbi->mmap_addr   = freespace;
 | 
			
		||||
		mbi->mmap_length = ranges * sizeof(*mmap);
 | 
			
		||||
 | 
			
		||||
		/* For kernels that care naught for fancy memory maps
 | 
			
		||||
		 * and just want the size of low and high memory */
 | 
			
		||||
		mbi->mem_lower = MIN(mem_lower>>10, 0xffffffff);
 | 
			
		||||
		mbi->mem_upper = MIN(mem_upper>>10, 0xffffffff);
 | 
			
		||||
			
 | 
			
		||||
		/* done */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Load modules */
 | 
			
		||||
	if (modules) {
 | 
			
		||||
		char *mod_filename, *mod_command_line, *mod_clp, *buf;
 | 
			
		||||
		off_t mod_size;
 | 
			
		||||
 | 
			
		||||
		/* We'll relocate this to an absolute address later */
 | 
			
		||||
		mbi->mods_addr = mbi_bytes;
 | 
			
		||||
		mbi->mods_count = 0;
 | 
			
		||||
		mbi->flags |= MB_INFO_MODS;
 | 
			
		||||
		
 | 
			
		||||
		/* Add room for the module descriptors to the MBI buffer */
 | 
			
		||||
		mbi_bytes += (sizeof(*modp) * modules)
 | 
			
		||||
			+ mod_command_line_space;
 | 
			
		||||
		mbi_buf = xrealloc(mbi_buf, mbi_bytes);
 | 
			
		||||
 | 
			
		||||
		/* mbi might have moved */
 | 
			
		||||
		mbi = mbi_buf;
 | 
			
		||||
		/* module descriptors go in the newly added space */
 | 
			
		||||
		modp = ((void *)mbi) + mbi->mods_addr; 
 | 
			
		||||
		/* module command lines go after the descriptors */
 | 
			
		||||
		mod_clp = ((void *)modp) + (sizeof(*modp) * modules);
 | 
			
		||||
		
 | 
			
		||||
		/* Go back and parse the module command lines */
 | 
			
		||||
		optind = opterr = 1;
 | 
			
		||||
		while((opt = getopt_long(argc, argv, 
 | 
			
		||||
					 short_options, options, 0)) != -1)
 | 
			
		||||
		{
 | 
			
		||||
			if (opt != OPT_MOD) continue;
 | 
			
		||||
 | 
			
		||||
			/* Split module filename from command line */
 | 
			
		||||
			mod_command_line = mod_filename = optarg;
 | 
			
		||||
			if ((cp = strchr(mod_filename, ' ')) != NULL) {
 | 
			
		||||
				/* See as I discard the 'const' modifier */
 | 
			
		||||
				*cp = '\0';
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* Load the module */
 | 
			
		||||
			buf = slurp_decompress_file(mod_filename, &mod_size);
 | 
			
		||||
			
 | 
			
		||||
			if (cp != NULL) *cp = ' ';
 | 
			
		||||
 | 
			
		||||
			/* Pick the next aligned spot to load it in */
 | 
			
		||||
			freespace = add_buffer(info,
 | 
			
		||||
				buf, mod_size, mod_size,
 | 
			
		||||
				PAGE_SIZE, 0, 0xffffffffUL, 1);
 | 
			
		||||
 | 
			
		||||
			/* Add the module command line */
 | 
			
		||||
			sprintf(mod_clp, "%s", mod_command_line);
 | 
			
		||||
 | 
			
		||||
			modp->mod_start = freespace;
 | 
			
		||||
			modp->mod_end   = freespace + mod_size;
 | 
			
		||||
			modp->cmdline   = (void *)mod_clp - (void *)mbi;
 | 
			
		||||
			modp->pad       = 0;
 | 
			
		||||
 | 
			
		||||
			/* Done */
 | 
			
		||||
			mbi->mods_count++;
 | 
			
		||||
			mod_clp += strlen(mod_clp) + 1;
 | 
			
		||||
			modp++;
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Find a place for the MBI to live */
 | 
			
		||||
	if (sort_segments(info) < 0) {
 | 
			
		||||
                return -1;
 | 
			
		||||
        }
 | 
			
		||||
	mbi_base = add_buffer(info,
 | 
			
		||||
		mbi_buf, mbi_bytes, mbi_bytes, 4, 0, 0xFFFFFFFFUL, 1);
 | 
			
		||||
		
 | 
			
		||||
	/* Relocate offsets in the MBI to absolute addresses */
 | 
			
		||||
	mbi_offset = mbi_base;
 | 
			
		||||
	modp = ((void *)mbi) + mbi->mods_addr;
 | 
			
		||||
	for (i=0; i<mbi->mods_count; i++) {
 | 
			
		||||
		modp[i].cmdline += mbi_offset;
 | 
			
		||||
	}
 | 
			
		||||
	mbi->mods_addr += mbi_offset;
 | 
			
		||||
	mbi->cmdline += mbi_offset;
 | 
			
		||||
	mbi->boot_loader_name += mbi_offset;
 | 
			
		||||
 | 
			
		||||
	/* Specify the initial CPU state and copy the setup code */
 | 
			
		||||
	elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs));
 | 
			
		||||
	regs.eax = 0x2BADB002;
 | 
			
		||||
	regs.ebx = mbi_offset;
 | 
			
		||||
	regs.eip = ehdr.e_entry;
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s, sizeof(regs));
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  EOF (kexec-multiboot-x86.c)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										249
									
								
								kexec/arch/i386/kexec-nbi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								kexec/arch/i386/kexec-nbi.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,249 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "../../kexec-elf-boot.h"
 | 
			
		||||
#include "kexec-x86.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
struct segheader
 | 
			
		||||
{
 | 
			
		||||
	uint8_t length;
 | 
			
		||||
	uint8_t vendortag;
 | 
			
		||||
	uint8_t reserved;
 | 
			
		||||
	uint8_t flags;
 | 
			
		||||
#define NBI_SEG 0x3
 | 
			
		||||
#define NBI_SEG_ABSOLUTE  0
 | 
			
		||||
#define NBI_SEG_APPEND    1
 | 
			
		||||
#define NBI_SEG_NEGATIVE  2
 | 
			
		||||
#define NBI_SEG_PREPEND   3
 | 
			
		||||
#define NBI_LAST_SEG      (1 << 2)
 | 
			
		||||
	uint32_t loadaddr;
 | 
			
		||||
	uint32_t imglength;
 | 
			
		||||
	uint32_t memlength;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct imgheader
 | 
			
		||||
{
 | 
			
		||||
#define NBI_MAGIC "\x36\x13\x03\x1b"
 | 
			
		||||
	uint8_t magic[4];
 | 
			
		||||
#define NBI_RETURNS (1 << 8)
 | 
			
		||||
#define NBI_ENTRY32 (1 << 31)
 | 
			
		||||
	uint32_t length;	/* and flags */
 | 
			
		||||
	struct { uint16_t bx, ds; } segoff;
 | 
			
		||||
	union {
 | 
			
		||||
		struct { uint16_t ip, cs; } segoff;
 | 
			
		||||
		uint32_t linear;
 | 
			
		||||
	} execaddr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
int nbi_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct imgheader hdr;
 | 
			
		||||
	struct segheader seg;
 | 
			
		||||
	off_t seg_off;
 | 
			
		||||
	/* If we don't have enough data give up */
 | 
			
		||||
	if ((len < sizeof(hdr)) || (len < 512)) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(&hdr, buf, sizeof(hdr));
 | 
			
		||||
	if (memcmp(hdr.magic, NBI_MAGIC, sizeof(hdr.magic)) != 0) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Ensure we have a properly sized header */
 | 
			
		||||
	if (((hdr.length & 0xf)*4) != sizeof(hdr)) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "NBI: Bad vendor header size\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Ensure the vendor header is not too large.
 | 
			
		||||
	 * This can't actually happen but....
 | 
			
		||||
	 */
 | 
			
		||||
	if ((((hdr.length & 0xf0) >> 4)*4) > (512 - sizeof(hdr))) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "NBI: vendor headr too large\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Reserved bits are set in the image... */
 | 
			
		||||
	if ((hdr.length & 0x7ffffe00)) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "NBI: Reserved header bits set\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* If the image can return refuse to load it */
 | 
			
		||||
	if (hdr.length & (1 << 8)) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			printf("NBI: image wants to return\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Now verify the segments all fit within 512 bytes */
 | 
			
		||||
	seg_off = (((hdr.length & 0xf0) >> 4) + (hdr.length & 0x0f)) << 2;
 | 
			
		||||
	do {
 | 
			
		||||
		memcpy(&seg, buf + seg_off, sizeof(seg));
 | 
			
		||||
		if ((seg.length & 0xf) != 4) {
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "NBI: Invalid segment length\n");
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		seg_off += ((seg.length & 0xf) + ((seg.length >> 4) & 0xf)) << 2;
 | 
			
		||||
		if (seg.flags & 0xf8) {
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "NBI: segment reserved flags set\n");
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		if ((seg.flags & NBI_SEG) == NBI_SEG_NEGATIVE) {
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "NBI: negative segment addresses not supported\n");
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		if (seg_off > 512) {
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "NBI: segment outside 512 header\n");
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	} while(!(seg.flags & NBI_LAST_SEG));
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nbi_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(	"\n"
 | 
			
		||||
		);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int nbi_load(int argc, char **argv, const char *buf, off_t len, 
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct imgheader hdr;
 | 
			
		||||
	struct segheader seg;
 | 
			
		||||
	off_t seg_off;
 | 
			
		||||
	off_t file_off;
 | 
			
		||||
	uint32_t last0, last1;
 | 
			
		||||
	int opt;
 | 
			
		||||
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ 0, 			0, NULL, 0 },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static const char short_options[] = KEXEC_OPT_STR "";
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Parse the command line arguments
 | 
			
		||||
	 */
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Get a copy of the header */
 | 
			
		||||
	memcpy(&hdr, buf, sizeof(hdr));
 | 
			
		||||
 | 
			
		||||
	/* Load the first 512 bytes */
 | 
			
		||||
	add_segment(info, buf + 0, 512, 
 | 
			
		||||
		(hdr.segoff.ds << 4) + hdr.segoff.bx, 512);
 | 
			
		||||
	
 | 
			
		||||
	/* Initialize variables */
 | 
			
		||||
	file_off = 512;
 | 
			
		||||
	last0 = (hdr.segoff.ds << 4) + hdr.segoff.bx;
 | 
			
		||||
	last1 = last0 + 512;
 | 
			
		||||
 | 
			
		||||
	/* Load the segments  */
 | 
			
		||||
	seg_off = (((hdr.length & 0xf0) >> 4) + (hdr.length & 0x0f)) << 2;
 | 
			
		||||
	do {
 | 
			
		||||
		uint32_t loadaddr;
 | 
			
		||||
		memcpy(&seg, buf + seg_off, sizeof(seg));
 | 
			
		||||
		seg_off += ((seg.length & 0xf) + ((seg.length >> 4) & 0xf)) << 2;
 | 
			
		||||
		if ((seg.flags & NBI_SEG) == NBI_SEG_ABSOLUTE) {
 | 
			
		||||
			loadaddr = seg.loadaddr;
 | 
			
		||||
		}
 | 
			
		||||
		else if ((seg.flags & NBI_SEG) == NBI_SEG_APPEND) {
 | 
			
		||||
			loadaddr = last1 + seg.loadaddr;
 | 
			
		||||
		}
 | 
			
		||||
#if 0
 | 
			
		||||
		else if ((seg.flags & NBI_SEG) == NBI_SEG_NEGATIVE) {
 | 
			
		||||
			loadaddr = memsize - seg.loadaddr;
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
		else if ((seg.flags & NBI_SEG) == NBI_SEG_PREPEND) {
 | 
			
		||||
			loadaddr = last0 - seg.loadaddr;
 | 
			
		||||
		}
 | 
			
		||||
		add_segment(info, buf + file_off, seg.imglength,
 | 
			
		||||
			loadaddr, seg.memlength);
 | 
			
		||||
		last0 = loadaddr;
 | 
			
		||||
		last1 = last0 + seg.memlength;
 | 
			
		||||
		file_off += seg.imglength;
 | 
			
		||||
	} while(!(seg.flags & NBI_LAST_SEG));
 | 
			
		||||
 | 
			
		||||
	if (hdr.length & NBI_ENTRY32) {
 | 
			
		||||
		struct entry32_regs regs32;
 | 
			
		||||
		/* Initialize the registers */
 | 
			
		||||
		elf_rel_get_symbol(&info->rhdr, "entry32_regs32", ®s32, sizeof(regs32));
 | 
			
		||||
		regs32.eip = hdr.execaddr.linear;
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry32_regs32", ®s32, sizeof(regs32));
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		struct entry32_regs regs32;
 | 
			
		||||
		struct entry16_regs regs16;
 | 
			
		||||
 | 
			
		||||
		/* Initialize the 16 bit registers */
 | 
			
		||||
		elf_rel_get_symbol(&info->rhdr, "entry16_regs", ®s16, sizeof(regs16));
 | 
			
		||||
		regs16.cs = hdr.execaddr.segoff.cs;
 | 
			
		||||
		regs16.ip = hdr.execaddr.segoff.ip;
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry16_regs", ®s16, sizeof(regs16));
 | 
			
		||||
 | 
			
		||||
		/* Initialize the 32 bit registers */
 | 
			
		||||
		elf_rel_get_symbol(&info->rhdr, "entry32_regs", ®s32, sizeof(regs32));
 | 
			
		||||
		regs32.eip = elf_rel_get_addr(&info->rhdr, "entry16");
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry32_regs", ®s32, sizeof(regs32));
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										262
									
								
								kexec/arch/i386/kexec-x86.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								kexec/arch/i386/kexec-x86.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,262 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "../../kexec-syscall.h"
 | 
			
		||||
#include "kexec-x86.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_MEMORY_RANGES 64
 | 
			
		||||
#define MAX_LINE 160
 | 
			
		||||
static struct memory_range memory_range[MAX_MEMORY_RANGES];
 | 
			
		||||
 | 
			
		||||
/* Return a sorted list of memory ranges. */
 | 
			
		||||
int get_memory_ranges(struct memory_range **range, int *ranges)
 | 
			
		||||
{
 | 
			
		||||
	const char iomem[]= "/proc/iomem";
 | 
			
		||||
	int memory_ranges = 0;
 | 
			
		||||
	char line[MAX_LINE];
 | 
			
		||||
	FILE *fp;
 | 
			
		||||
	fp = fopen(iomem, "r");
 | 
			
		||||
	if (!fp) {
 | 
			
		||||
		fprintf(stderr, "Cannot open %s: %s\n", 
 | 
			
		||||
			iomem, strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	while(fgets(line, sizeof(line), fp) != 0) {
 | 
			
		||||
		unsigned long long start, end;
 | 
			
		||||
		char *str;
 | 
			
		||||
		int type;
 | 
			
		||||
		int consumed;
 | 
			
		||||
		int count;
 | 
			
		||||
		if (memory_ranges >= MAX_MEMORY_RANGES)
 | 
			
		||||
			break;
 | 
			
		||||
		count = sscanf(line, "%Lx-%Lx : %n",
 | 
			
		||||
			&start, &end, &consumed);
 | 
			
		||||
		if (count != 2) 
 | 
			
		||||
			continue;
 | 
			
		||||
		str = line + consumed;
 | 
			
		||||
		end = end + 1;
 | 
			
		||||
#if 0
 | 
			
		||||
		printf("%016Lx-%016Lx : %s",
 | 
			
		||||
			start, end, str);
 | 
			
		||||
#endif
 | 
			
		||||
		if (memcmp(str, "System RAM\n", 11) == 0) {
 | 
			
		||||
			type = RANGE_RAM;
 | 
			
		||||
		} 
 | 
			
		||||
		else if (memcmp(str, "reserved\n", 9) == 0) {
 | 
			
		||||
			type = RANGE_RESERVED;
 | 
			
		||||
		}
 | 
			
		||||
		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
 | 
			
		||||
			type = RANGE_ACPI;
 | 
			
		||||
		}
 | 
			
		||||
		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
 | 
			
		||||
			type = RANGE_ACPI_NVS;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		/* Don't report the interrupt table as ram */
 | 
			
		||||
		if (type == RANGE_RAM && (start < 0x100)) {
 | 
			
		||||
			start = 0x100;
 | 
			
		||||
		}
 | 
			
		||||
		memory_range[memory_ranges].start = start;
 | 
			
		||||
		memory_range[memory_ranges].end = end;
 | 
			
		||||
		memory_range[memory_ranges].type = type;
 | 
			
		||||
#if 0
 | 
			
		||||
		printf("%016Lx-%016Lx : %x\n",
 | 
			
		||||
			start, end, type);
 | 
			
		||||
#endif
 | 
			
		||||
		memory_ranges++;
 | 
			
		||||
	}
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
	*range = memory_range;
 | 
			
		||||
	*ranges = memory_ranges;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct file_type file_type[] = {
 | 
			
		||||
	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load, 
 | 
			
		||||
	  multiboot_x86_usage },
 | 
			
		||||
	{ "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
 | 
			
		||||
	{ "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
 | 
			
		||||
	{ "beoboot-x86", beoboot_probe, beoboot_load, beoboot_usage },
 | 
			
		||||
	{ "nbi-x86", nbi_probe, nbi_load, nbi_usage },
 | 
			
		||||
};
 | 
			
		||||
int file_types = sizeof(file_type)/sizeof(file_type[0]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void arch_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(
 | 
			
		||||
		"     --reset-vga               Attempt to reset a standard vga device\n"
 | 
			
		||||
		"     --serial=<port>           Specify the serial port for debug output\n"
 | 
			
		||||
		"     --serial-baud=<buad_rate> Specify the serial port baud rate\n"
 | 
			
		||||
		"     --console-vga             Enable the vga console\n"
 | 
			
		||||
		"     --console-serial          Enable the serial console\n"
 | 
			
		||||
		);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
	uint8_t  reset_vga;
 | 
			
		||||
	uint16_t serial_base;
 | 
			
		||||
	uint32_t serial_baud;
 | 
			
		||||
	uint8_t  console_vga;
 | 
			
		||||
	uint8_t  console_serial;
 | 
			
		||||
} arch_options = {
 | 
			
		||||
	.reset_vga   = 0,
 | 
			
		||||
	.serial_base = 0x3f8,
 | 
			
		||||
	.serial_baud = 0,
 | 
			
		||||
	.console_vga = 0,
 | 
			
		||||
	.console_serial = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int arch_process_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ 0, 			0, NULL, 0 },
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR;
 | 
			
		||||
	int opt;
 | 
			
		||||
	unsigned long value;
 | 
			
		||||
	char *end;
 | 
			
		||||
 | 
			
		||||
	opterr = 0; /* Don't complain about unrecognized options here */
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_RESET_VGA:
 | 
			
		||||
			arch_options.reset_vga = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_CONSOLE_VGA:
 | 
			
		||||
			arch_options.console_vga = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_CONSOLE_SERIAL:
 | 
			
		||||
			arch_options.console_serial = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_SERIAL:
 | 
			
		||||
			value = ULONG_MAX;
 | 
			
		||||
			if (strcmp(optarg, "ttyS0") == 0) {
 | 
			
		||||
				value = 0x3f8;
 | 
			
		||||
			}
 | 
			
		||||
			else if (strcmp(optarg, "ttyS1") == 0) {
 | 
			
		||||
				value = 0x2f8;
 | 
			
		||||
			}
 | 
			
		||||
			else if (strncmp(optarg, "0x", 2) == 0) {
 | 
			
		||||
				value = strtoul(optarg +2, &end, 16);
 | 
			
		||||
				if (*end != '\0') {
 | 
			
		||||
					value = ULONG_MAX;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (value >= 65536) {
 | 
			
		||||
				fprintf(stderr, "Bad serial port base '%s'\n", 
 | 
			
		||||
					optarg);
 | 
			
		||||
				usage();
 | 
			
		||||
				return -1;
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			arch_options.serial_base = value;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_SERIAL_BAUD:
 | 
			
		||||
			value = strtoul(optarg, &end, 0);
 | 
			
		||||
			if ((value > 115200) || ((115200 %value) != 0) || 
 | 
			
		||||
				(value < 9600) || (*end)) 
 | 
			
		||||
			{
 | 
			
		||||
				fprintf(stderr, "Bad serial port baud rate '%s'\n",
 | 
			
		||||
					optarg);
 | 
			
		||||
				usage();
 | 
			
		||||
				return -1;
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			arch_options.serial_baud = value;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Reset getopt for the next pass; called in other source modules */
 | 
			
		||||
	opterr = 1;
 | 
			
		||||
	optind = 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	struct utsname utsname;
 | 
			
		||||
	result = uname(&utsname);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		fprintf(stderr, "uname failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (	(strcmp(utsname.machine, "i386") == 0) ||
 | 
			
		||||
		(strcmp(utsname.machine, "i486") == 0) ||
 | 
			
		||||
		(strcmp(utsname.machine, "i586") == 0) ||
 | 
			
		||||
		(strcmp(utsname.machine, "i686") == 0)) 
 | 
			
		||||
	{
 | 
			
		||||
		/* For compatibility with older patches 
 | 
			
		||||
		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_386 here.
 | 
			
		||||
		 */
 | 
			
		||||
		*flags |= KEXEC_ARCH_DEFAULT;
 | 
			
		||||
	}
 | 
			
		||||
	else if (strcmp(utsname.machine, "x86_64") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		*flags |= KEXEC_ARCH_X86_64;
 | 
			
		||||
		if (!info->rhdr.e_shdr) {
 | 
			
		||||
			fprintf(stderr, 
 | 
			
		||||
				"A trampoline is required for cross architecture support\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "compat_x86_64_entry32",
 | 
			
		||||
			&info->entry, sizeof(info->entry));
 | 
			
		||||
		
 | 
			
		||||
		info->entry = elf_rel_get_addr(&info->rhdr, "compat_x86_64");
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		fprintf(stderr, "Unsupported machine type: %s\n",
 | 
			
		||||
			utsname.machine);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_update_purgatory(struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "reset_vga",
 | 
			
		||||
		&arch_options.reset_vga, sizeof(arch_options.reset_vga));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "serial_base",
 | 
			
		||||
		&arch_options.serial_base, sizeof(arch_options.serial_base));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "serial_baud", 
 | 
			
		||||
		&arch_options.serial_baud, sizeof(arch_options.serial_baud));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "console_vga", 
 | 
			
		||||
		&arch_options.console_vga, sizeof(arch_options.console_vga));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "console_serial", 
 | 
			
		||||
		&arch_options.console_serial, sizeof(arch_options.console_serial));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								kexec/arch/i386/kexec-x86.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								kexec/arch/i386/kexec-x86.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
#ifndef KEXEC_X86_H
 | 
			
		||||
#define KEXEC_X86_H
 | 
			
		||||
 | 
			
		||||
extern unsigned char compat_x86_64[];
 | 
			
		||||
extern uint32_t compat_x86_64_size, compat_x86_64_entry32;
 | 
			
		||||
 | 
			
		||||
struct entry32_regs {
 | 
			
		||||
	uint32_t eax;
 | 
			
		||||
	uint32_t ebx;
 | 
			
		||||
	uint32_t ecx;
 | 
			
		||||
	uint32_t edx;
 | 
			
		||||
	uint32_t esi;
 | 
			
		||||
	uint32_t edi;
 | 
			
		||||
	uint32_t esp;
 | 
			
		||||
	uint32_t ebp;
 | 
			
		||||
	uint32_t eip;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct entry16_regs {
 | 
			
		||||
	uint32_t eax;
 | 
			
		||||
	uint32_t ebx;
 | 
			
		||||
	uint32_t ecx;
 | 
			
		||||
	uint32_t edx;
 | 
			
		||||
	uint32_t esi;
 | 
			
		||||
	uint32_t edi;
 | 
			
		||||
	uint32_t esp;
 | 
			
		||||
	uint32_t ebp;
 | 
			
		||||
	uint16_t ds;
 | 
			
		||||
	uint16_t es;
 | 
			
		||||
	uint16_t ss;
 | 
			
		||||
	uint16_t fs;
 | 
			
		||||
	uint16_t gs;
 | 
			
		||||
	uint16_t ip;
 | 
			
		||||
	uint16_t cs;
 | 
			
		||||
	uint16_t pad;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int multiboot_x86_probe(const char *buf, off_t len);
 | 
			
		||||
int multiboot_x86_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void multiboot_x86_usage(void);
 | 
			
		||||
 | 
			
		||||
int elf_x86_probe(const char *buf, off_t len);
 | 
			
		||||
int elf_x86_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void elf_x86_usage(void);
 | 
			
		||||
 | 
			
		||||
int bzImage_probe(const char *buf, off_t len);
 | 
			
		||||
int bzImage_load(int argc, char **argv, const char *buf, off_t len, 
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void bzImage_usage(void);
 | 
			
		||||
int do_bzImage_load(struct kexec_info *info,
 | 
			
		||||
	const char *kernel, off_t kernel_len,
 | 
			
		||||
	const char *command_line, off_t command_line_len,
 | 
			
		||||
	const char *initrd, off_t initrd_len,
 | 
			
		||||
	int real_mode_entry, int debug);
 | 
			
		||||
 | 
			
		||||
int beoboot_probe(const char *buf, off_t len);
 | 
			
		||||
int beoboot_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void beoboot_usage(void);
 | 
			
		||||
 | 
			
		||||
int nbi_probe(const char *buf, off_t len);
 | 
			
		||||
int nbi_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void nbi_usage(void);
 | 
			
		||||
#endif /* KEXEC_X86_H */
 | 
			
		||||
							
								
								
									
										178
									
								
								kexec/arch/i386/x86-linux-setup.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								kexec/arch/i386/x86-linux-setup.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <x86/x86-linux.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "kexec-x86.h"
 | 
			
		||||
#include "x86-linux-setup.h"
 | 
			
		||||
 | 
			
		||||
void init_linux_parameters(struct x86_linux_param_header *real_mode)
 | 
			
		||||
{
 | 
			
		||||
	/* Fill in the values that are usually provided by the kernel. */
 | 
			
		||||
 | 
			
		||||
	/* Boot block magic */
 | 
			
		||||
	memcpy(real_mode->header_magic, "HdrS", 4);
 | 
			
		||||
	real_mode->protocol_version = 0x0203;
 | 
			
		||||
	real_mode->initrd_addr_max = DEFAULT_INITRD_ADDR_MAX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setup_linux_bootloader_parameters(
 | 
			
		||||
	struct kexec_info *info, struct x86_linux_param_header *real_mode,
 | 
			
		||||
	unsigned long real_mode_base, unsigned long cmdline_offset,
 | 
			
		||||
	const char *cmdline, off_t cmdline_len,
 | 
			
		||||
	const unsigned char *initrd_buf, off_t initrd_size)
 | 
			
		||||
{
 | 
			
		||||
	char *cmdline_ptr;
 | 
			
		||||
	unsigned long initrd_base, initrd_addr_max;
 | 
			
		||||
 | 
			
		||||
	/* Say I'm a boot loader */
 | 
			
		||||
	real_mode->loader_type = LOADER_TYPE_UNKNOWN;
 | 
			
		||||
 | 
			
		||||
	/* No loader flags */
 | 
			
		||||
	real_mode->loader_flags = 0;
 | 
			
		||||
 | 
			
		||||
	/* Find the maximum initial ramdisk address */
 | 
			
		||||
	initrd_addr_max = DEFAULT_INITRD_ADDR_MAX;
 | 
			
		||||
	if (real_mode->protocol_version >= 0x0203) {
 | 
			
		||||
		initrd_addr_max = real_mode->initrd_addr_max;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load the initrd if we have one */
 | 
			
		||||
	if (initrd_buf) {
 | 
			
		||||
		initrd_base = add_buffer(info,
 | 
			
		||||
			initrd_buf, initrd_size, initrd_size,
 | 
			
		||||
			4096, INITRD_BASE, initrd_addr_max, -1);
 | 
			
		||||
	} else {
 | 
			
		||||
		initrd_base = 0;
 | 
			
		||||
		initrd_size = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Ramdisk address and size */
 | 
			
		||||
	real_mode->initrd_start = initrd_base;
 | 
			
		||||
	real_mode->initrd_size  = initrd_size;
 | 
			
		||||
 | 
			
		||||
	/* The location of the command line */
 | 
			
		||||
	/* if (real_mode_base == 0x90000) { */
 | 
			
		||||
		real_mode->cl_magic = CL_MAGIC_VALUE;
 | 
			
		||||
		real_mode->cl_offset = cmdline_offset;
 | 
			
		||||
		/* setup_move_size */
 | 
			
		||||
	/* } */
 | 
			
		||||
	if (real_mode->protocol_version >= 0x0202) {
 | 
			
		||||
		real_mode->cmd_line_ptr = real_mode_base + cmdline_offset;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Fill in the command line */
 | 
			
		||||
	if (cmdline_len > COMMAND_LINE_SIZE) {
 | 
			
		||||
		cmdline_len = COMMAND_LINE_SIZE;
 | 
			
		||||
	}
 | 
			
		||||
	cmdline_ptr = ((char *)real_mode) + cmdline_offset;
 | 
			
		||||
	memcpy(cmdline_ptr, cmdline, cmdline_len);
 | 
			
		||||
	cmdline_ptr[cmdline_len - 1] = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setup_linux_system_parameters(struct x86_linux_param_header *real_mode)
 | 
			
		||||
{
 | 
			
		||||
	/* Fill in information the BIOS would usually provide */
 | 
			
		||||
	struct memory_range *range;
 | 
			
		||||
	int i, ranges;
 | 
			
		||||
	
 | 
			
		||||
	/* Default screen size */
 | 
			
		||||
	real_mode->orig_x = 0;
 | 
			
		||||
	real_mode->orig_y = 0;
 | 
			
		||||
	real_mode->orig_video_page = 0;
 | 
			
		||||
	real_mode->orig_video_mode = 0;
 | 
			
		||||
	real_mode->orig_video_cols = 80;
 | 
			
		||||
	real_mode->orig_video_lines = 25;
 | 
			
		||||
	real_mode->orig_video_ega_bx = 0;
 | 
			
		||||
	real_mode->orig_video_isVGA = 1;
 | 
			
		||||
	real_mode->orig_video_points = 16;
 | 
			
		||||
 | 
			
		||||
	/* Fill in the memsize later */
 | 
			
		||||
	real_mode->ext_mem_k = 0;
 | 
			
		||||
	real_mode->alt_mem_k = 0;
 | 
			
		||||
	real_mode->e820_map_nr = 0;
 | 
			
		||||
 | 
			
		||||
	/* Default APM info */
 | 
			
		||||
	memset(&real_mode->apm_bios_info, 0, sizeof(real_mode->apm_bios_info));
 | 
			
		||||
	/* Default drive info */
 | 
			
		||||
	memset(&real_mode->drive_info, 0, sizeof(real_mode->drive_info));
 | 
			
		||||
	/* Default sysdesc table */
 | 
			
		||||
	real_mode->sys_desc_table.length = 0;
 | 
			
		||||
 | 
			
		||||
	/* default yes: this can be overridden on the command line */
 | 
			
		||||
	real_mode->mount_root_rdonly = 0xFFFF;
 | 
			
		||||
 | 
			
		||||
	/* default /dev/hda
 | 
			
		||||
	 * this can be overrident on the command line if necessary.
 | 
			
		||||
	 */
 | 
			
		||||
	real_mode->root_dev = (0x3 <<8)| 0;
 | 
			
		||||
 | 
			
		||||
	/* another safe default */
 | 
			
		||||
	real_mode->aux_device_info = 0;
 | 
			
		||||
 | 
			
		||||
	/* Fill in the memory info */
 | 
			
		||||
	if ((get_memory_ranges(&range, &ranges) < 0) || ranges == 0) {
 | 
			
		||||
		die("Cannot get memory information\n");
 | 
			
		||||
	}
 | 
			
		||||
	if (ranges > E820MAX) {
 | 
			
		||||
		fprintf(stderr, "Too many memory ranges, truncating...\n");
 | 
			
		||||
		ranges = E820MAX;
 | 
			
		||||
	}
 | 
			
		||||
	real_mode->e820_map_nr = ranges;
 | 
			
		||||
	for(i = 0; i < ranges; i++) {
 | 
			
		||||
		real_mode->e820_map[i].addr = range[i].start;
 | 
			
		||||
		real_mode->e820_map[i].size = range[i].end - range[i].start;
 | 
			
		||||
		switch (range[i].type) {
 | 
			
		||||
		case RANGE_RAM:
 | 
			
		||||
			real_mode->e820_map[i].type = E820_RAM; 
 | 
			
		||||
			break;
 | 
			
		||||
		case RANGE_ACPI:
 | 
			
		||||
			real_mode->e820_map[i].type = E820_ACPI; 
 | 
			
		||||
			break;
 | 
			
		||||
		case RANGE_ACPI_NVS:
 | 
			
		||||
			real_mode->e820_map[i].type = E820_NVS;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
		case RANGE_RESERVED:
 | 
			
		||||
			real_mode->e820_map[i].type = E820_RESERVED; 
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		if (range[i].type != RANGE_RAM)
 | 
			
		||||
			continue;
 | 
			
		||||
		if ((range[i].start <= 0x100000) && range[i].end > 0x100000) {
 | 
			
		||||
			unsigned long long mem_k = (range[i].end >> 10) - 0x100000;
 | 
			
		||||
			real_mode->ext_mem_k = mem_k;
 | 
			
		||||
			real_mode->alt_mem_k = mem_k;
 | 
			
		||||
			if (mem_k > 0xfc00) {
 | 
			
		||||
				real_mode->ext_mem_k = 0xfc00; /* 64M */
 | 
			
		||||
			}
 | 
			
		||||
			if (mem_k > 0xffffffff) {
 | 
			
		||||
				real_mode->alt_mem_k = 0xffffffff;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										17
									
								
								kexec/arch/i386/x86-linux-setup.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								kexec/arch/i386/x86-linux-setup.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
#ifndef X86_LINUX_SETUP_H
 | 
			
		||||
#define X86_LINUX_SETUP_H
 | 
			
		||||
 | 
			
		||||
void init_linux_parameters(struct x86_linux_param_header *real_mode);
 | 
			
		||||
void setup_linux_bootloader_parameters(
 | 
			
		||||
	struct kexec_info *info, struct x86_linux_param_header *real_mode,
 | 
			
		||||
	unsigned long real_mode_base, unsigned long cmdline_offset,
 | 
			
		||||
	const char *cmdline, off_t cmdline_len,
 | 
			
		||||
	const unsigned char *initrd_buf, off_t initrd_size);
 | 
			
		||||
void setup_linux_system_parameters(struct x86_linux_param_header *real_mode);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define SETUP_BASE    0x90000
 | 
			
		||||
#define KERN32_BASE  0x100000 /* 1MB */
 | 
			
		||||
#define INITRD_BASE 0x1000000 /* 16MB */
 | 
			
		||||
 | 
			
		||||
#endif /* X86_LINUX_SETUP_H */
 | 
			
		||||
							
								
								
									
										6
									
								
								kexec/arch/ia64/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								kexec/arch/ia64/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#
 | 
			
		||||
# kexec ia64 (linux booting linux)
 | 
			
		||||
#
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ia64/kexec-ia64.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ia64/kexec-elf-ia64.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ia64/kexec-elf-rel-ia64.c
 | 
			
		||||
							
								
								
									
										11
									
								
								kexec/arch/ia64/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								kexec/arch/ia64/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef KEXEC_ARCH_IA64_OPTIONS_H
 | 
			
		||||
#define KEXEC_ARCH_IA64_OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#define OPT_ARCH_MAX   (OPT_MAX+0)
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPTIONS \
 | 
			
		||||
	KEXEC_OPTIONS \
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_ARCH_IA64_OPTIONS_H */
 | 
			
		||||
							
								
								
									
										141
									
								
								kexec/arch/ia64/kexec-elf-ia64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								kexec/arch/ia64/kexec-elf-ia64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 * Copyright (C) 2004 Albert Herranz
 | 
			
		||||
 * Copyright (C) 2004 Silicon Graphics, Inc.
 | 
			
		||||
 *   Jesse Barnes <jbarnes@sgi.com>
 | 
			
		||||
 * Copyright (C) 2004 Khalid Aziz <khalid.aziz@hp.com> Hewlett Packard Co
 | 
			
		||||
 *
 | 
			
		||||
 * 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 (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include <ip_checksum.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * elf_ia64_probe - sanity check the elf image
 | 
			
		||||
 *
 | 
			
		||||
 * Make sure that the file image has a reasonable chance of working.
 | 
			
		||||
 */
 | 
			
		||||
int elf_ia64_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not an ELF executable\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Verify the architecuture specific bits */
 | 
			
		||||
	if (ehdr.e_machine != EM_IA_64) {
 | 
			
		||||
		/* for a different architecture */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not for this architecture.\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_ia64_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(
 | 
			
		||||
		"    --command-line=STRING Set the kernel command line to STRING.\n"
 | 
			
		||||
		"    --append=STRING       Set the kernel command line to STRING.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	const char *command_line;
 | 
			
		||||
	int command_line_len;
 | 
			
		||||
	unsigned long entry, max_addr;
 | 
			
		||||
	int result;
 | 
			
		||||
	int opt;
 | 
			
		||||
#define OPT_APPEND	(OPT_ARCH_MAX+0)
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{"command-line", 1, 0, OPT_APPEND},
 | 
			
		||||
		{"append",       1, 0, OPT_APPEND},
 | 
			
		||||
		{0, 0, 0, 0},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR "";
 | 
			
		||||
 | 
			
		||||
	command_line = 0;
 | 
			
		||||
	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch (opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_APPEND:
 | 
			
		||||
			command_line = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	command_line_len = 0;
 | 
			
		||||
	if (command_line) {
 | 
			
		||||
		command_line_len = strlen(command_line) + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Parse the Elf file */
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		fprintf(stderr, "ELF parse failed\n");
 | 
			
		||||
		free_elf_info(&ehdr);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	entry = ehdr.e_entry;
 | 
			
		||||
	max_addr = elf_max_addr(&ehdr);
 | 
			
		||||
 | 
			
		||||
	/* Load the Elf data */
 | 
			
		||||
	result = elf_exec_load(&ehdr, info);
 | 
			
		||||
	free_elf_info(&ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		fprintf(stderr, "ELF load failed\n");
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* For now we don't have arguments to pass :( */
 | 
			
		||||
	info->entry = (void *)entry;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								kexec/arch/ia64/kexec-elf-rel-ia64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								kexec/arch/ia64/kexec-elf-rel-ia64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
int machine_verify_elf_rel(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data != ELFDATA2LSB) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->ei_class != ELFCLASS64) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->e_machine != EM_IA_64) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
 | 
			
		||||
	void *location, unsigned long address, unsigned long value)
 | 
			
		||||
{
 | 
			
		||||
	switch(r_type) {
 | 
			
		||||
	case R_IA64_NONE:
 | 
			
		||||
		break;
 | 
			
		||||
	case R_IA64_DIR64LSB:
 | 
			
		||||
		*((uint64_t *)location) = value;
 | 
			
		||||
		break;
 | 
			
		||||
	case R_IA64_DIR32LSB:
 | 
			
		||||
		*((uint32_t *)location) = value;
 | 
			
		||||
		if (value != *((uint32_t *)location))
 | 
			
		||||
			goto overflow;
 | 
			
		||||
		break;
 | 
			
		||||
	case R_IA64_PCREL21B:
 | 
			
		||||
	case R_IA64_LTOFF22:
 | 
			
		||||
	case R_IA64_SEGREL64LSB:
 | 
			
		||||
	default:
 | 
			
		||||
		die("Unknown rela relocation: %lu\n", r_type);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return;
 | 
			
		||||
 overflow:
 | 
			
		||||
	die("overflow in relocation type %lu val %Lx\n", 
 | 
			
		||||
		r_type, value);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										156
									
								
								kexec/arch/ia64/kexec-ia64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								kexec/arch/ia64/kexec-ia64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 * Copyright (C) 2004 Albert Herranz
 | 
			
		||||
 * Copyright (C) 2004 Silicon Graphics, Inc.
 | 
			
		||||
 *   Jesse Barnes <jbarnes@sgi.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-syscall.h"
 | 
			
		||||
#include "kexec-ia64.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_MEMORY_RANGES 64
 | 
			
		||||
#define MAX_LINE 160
 | 
			
		||||
static struct memory_range memory_range[MAX_MEMORY_RANGES];
 | 
			
		||||
 | 
			
		||||
/* Return a sorted list of available memory ranges. */
 | 
			
		||||
int get_memory_ranges(struct memory_range **range, int *ranges)
 | 
			
		||||
{
 | 
			
		||||
	int memory_ranges;
 | 
			
		||||
	/*
 | 
			
		||||
	 * /proc/iomem on ia64 does not show where all memory is. If
 | 
			
		||||
	 * that is fixed up, we can make use of that to validate
 | 
			
		||||
	 * the memory range kernel will be loade din. Until then.....
 | 
			
		||||
	 * -- Khalid Aziz
 | 
			
		||||
	 */
 | 
			
		||||
	
 | 
			
		||||
	/* Note that the ia64 architecture mandates all systems will
 | 
			
		||||
	 * have at least 64MB at 0-64M.  The SGI altix does not follow
 | 
			
		||||
	 * that restriction, but a reasonable guess is better than nothing
 | 
			
		||||
	 * at all.
 | 
			
		||||
	 * -- Eric Biederman
 | 
			
		||||
	 */
 | 
			
		||||
	fprintf(stderr, "Warning assuming memory at 0-64MB is present\n");
 | 
			
		||||
	memory_ranges = 0;
 | 
			
		||||
	memory_range[memory_ranges].start = 0x00010000;
 | 
			
		||||
	memory_range[memory_ranges].end   = 0x10000000;
 | 
			
		||||
	memory_range[memory_ranges].type  = RANGE_RAM;
 | 
			
		||||
	memory_ranges++;
 | 
			
		||||
	*range = memory_range;
 | 
			
		||||
	*ranges = memory_ranges;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Supported file types and callbacks */
 | 
			
		||||
struct file_type file_type[] = {
 | 
			
		||||
       {"elf-ia64", elf_ia64_probe, elf_ia64_load, elf_ia64_usage},
 | 
			
		||||
};
 | 
			
		||||
int file_types = sizeof(file_type) / sizeof(file_type[0]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void arch_usage(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
} arch_options = {
 | 
			
		||||
};
 | 
			
		||||
int arch_process_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ 0, 			0, NULL, 0 },
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR;
 | 
			
		||||
	int opt;
 | 
			
		||||
	unsigned long value;
 | 
			
		||||
	char *end;
 | 
			
		||||
 | 
			
		||||
	opterr = 0; /* Don't complain about unrecognized options here */
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Reset getopt for the next pass; called in other source modules */
 | 
			
		||||
	opterr = 1;
 | 
			
		||||
	optind = 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	struct utsname utsname;
 | 
			
		||||
	result = uname(&utsname);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		fprintf(stderr, "uname failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(utsname.machine, "ia64") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		*flags |= KEXEC_ARCH_X86_64;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		fprintf(stderr, "Unsupported machine type: %s\n",
 | 
			
		||||
			utsname.machine);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	struct utsname utsname;
 | 
			
		||||
	result = uname(&utsname);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		fprintf(stderr, "uname failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(utsname.machine, "ia64") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* For compatibility with older patches 
 | 
			
		||||
		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_IA64 here.
 | 
			
		||||
		 */
 | 
			
		||||
		*flags |= KEXEC_ARCH_DEFAULT;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		fprintf(stderr, "Unsupported machine type: %s\n",
 | 
			
		||||
			utsname.machine);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_update_purgatory(struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								kexec/arch/ia64/kexec-ia64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								kexec/arch/ia64/kexec-ia64.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
#ifndef KEXEC_IA64_H
 | 
			
		||||
#define KEXEC_IA64_H
 | 
			
		||||
 | 
			
		||||
int elf_ia64_probe(const char *buf, off_t len);
 | 
			
		||||
int elf_ia64_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void elf_ia64_usage(void);
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_IA64_H */
 | 
			
		||||
							
								
								
									
										9
									
								
								kexec/arch/ppc/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								kexec/arch/ppc/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
#
 | 
			
		||||
# kexec ppc (linux booting linux)
 | 
			
		||||
#
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ppc/kexec-ppc.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ppc/kexec-elf-ppc.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ppc/kexec-elf-rel-ppc.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ppc/kexec-dol-ppc.c
 | 
			
		||||
KEXEC_S_SRCS+= kexec/arch/ppc/ppc-setup-simple.S
 | 
			
		||||
KEXEC_S_SRCS+= kexec/arch/ppc/ppc-setup-dol.S
 | 
			
		||||
							
								
								
									
										11
									
								
								kexec/arch/ppc/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								kexec/arch/ppc/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef KEXEC_ARCH_PPC_OPTIONS_H
 | 
			
		||||
#define KEXEC_ARCH_PPC_OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#define OPT_ARCH_MAX   (OPT_MAX+0)
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPTIONS \
 | 
			
		||||
	KEXEC_OPTIONS \
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_ARCH_PPC_OPTIONS_H */
 | 
			
		||||
							
								
								
									
										479
									
								
								kexec/arch/ppc/kexec-dol-ppc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										479
									
								
								kexec/arch/ppc/kexec-dol-ppc.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,479 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec-dol-ppc.c - kexec DOL executable loader for the PowerPC
 | 
			
		||||
 * Copyright (C) 2004 Albert Herranz
 | 
			
		||||
 *
 | 
			
		||||
 * This source code is licensed under the GNU General Public License,
 | 
			
		||||
 * Version 2.  See the file COPYING for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include <ip_checksum.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "kexec-ppc.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
static int debug = 0;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * I've found out there DOLs with unaligned and/or overlapping sections.
 | 
			
		||||
 * I assume that sizes of sections can be wrong on these DOLs so I trust
 | 
			
		||||
 * better start of sections.
 | 
			
		||||
 * In order to load DOLs, I first extend sections to page aligned boundaries
 | 
			
		||||
 * and then merge overlapping sections starting from lower addresses.
 | 
			
		||||
 * -- Albert Herranz
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* DOL related stuff */
 | 
			
		||||
 | 
			
		||||
#define DOL_HEADER_SIZE    0x100
 | 
			
		||||
 | 
			
		||||
#define DOL_SECT_MAX_TEXT      7	/* text sections */
 | 
			
		||||
#define DOL_SECT_MAX_DATA     11	/* data sections */
 | 
			
		||||
#define DOL_MAX_SECT	   (DOL_SECT_MAX_TEXT+DOL_SECT_MAX_DATA)
 | 
			
		||||
 | 
			
		||||
/* this is the DOL executable header */
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint32_t offset_text[DOL_SECT_MAX_TEXT];	/* in the file */
 | 
			
		||||
	uint32_t offset_data[DOL_SECT_MAX_DATA];
 | 
			
		||||
	uint32_t address_text[DOL_SECT_MAX_TEXT];	/* in memory */
 | 
			
		||||
	uint32_t address_data[DOL_SECT_MAX_DATA];
 | 
			
		||||
	uint32_t size_text[DOL_SECT_MAX_TEXT];
 | 
			
		||||
	uint32_t size_data[DOL_SECT_MAX_DATA];
 | 
			
		||||
	uint32_t address_bss;
 | 
			
		||||
	uint32_t size_bss;
 | 
			
		||||
	uint32_t entry_point;
 | 
			
		||||
} dol_header;
 | 
			
		||||
 | 
			
		||||
#define dol_sect_offset(hptr, index) \
 | 
			
		||||
		((index >= DOL_SECT_MAX_TEXT)? \
 | 
			
		||||
			hptr->offset_data[index - DOL_SECT_MAX_TEXT] \
 | 
			
		||||
			:hptr->offset_text[index])
 | 
			
		||||
#define dol_sect_address(hptr, index) \
 | 
			
		||||
		((index >= DOL_SECT_MAX_TEXT)? \
 | 
			
		||||
			hptr->address_data[index - DOL_SECT_MAX_TEXT] \
 | 
			
		||||
			:hptr->address_text[index])
 | 
			
		||||
#define dol_sect_size(hptr, index) \
 | 
			
		||||
		((index >= DOL_SECT_MAX_TEXT)? \
 | 
			
		||||
			hptr->size_data[index - DOL_SECT_MAX_TEXT] \
 | 
			
		||||
			:hptr->size_text[index])
 | 
			
		||||
#define dol_sect_type(index) \
 | 
			
		||||
		((index >= DOL_SECT_MAX_TEXT) ? "data" : "text")
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	uint32_t sects_bitmap;
 | 
			
		||||
	uint32_t start;
 | 
			
		||||
	uint32_t size;
 | 
			
		||||
} dol_segment;
 | 
			
		||||
 | 
			
		||||
#define dol_seg_end(s1) \
 | 
			
		||||
		(s1->start + s1->size)
 | 
			
		||||
#define dol_seg_after_sect(s1, s2) \
 | 
			
		||||
		(s1->start >= dol_seg_end(s2))
 | 
			
		||||
#define dol_seg_overlaps(s1, s2) \
 | 
			
		||||
		(!(dol_seg_after_sect(s1,s2) || dol_seg_after_sect(s2,s1)))
 | 
			
		||||
 | 
			
		||||
/* same as in asm/page.h */
 | 
			
		||||
#define PAGE_SHIFT		12
 | 
			
		||||
#define PAGE_SIZE		(1UL << PAGE_SHIFT)
 | 
			
		||||
#define PAGE_MASK		(~((1 << PAGE_SHIFT) - 1))
 | 
			
		||||
#define PAGE_ALIGN(addr)	(((addr) + PAGE_SIZE - 1) & PAGE_MASK)
 | 
			
		||||
 | 
			
		||||
#define BOOTLOADER         "kexec"
 | 
			
		||||
#define BOOTLOADER_VERSION VERSION
 | 
			
		||||
#define MAX_COMMAND_LINE   256
 | 
			
		||||
 | 
			
		||||
#define UPSZ(X) ((sizeof(X) + 3) & ~3)
 | 
			
		||||
static struct boot_notes {
 | 
			
		||||
	Elf_Bhdr hdr;
 | 
			
		||||
	Elf_Nhdr bl_hdr;
 | 
			
		||||
	unsigned char bl_desc[UPSZ(BOOTLOADER)];
 | 
			
		||||
	Elf_Nhdr blv_hdr;
 | 
			
		||||
	unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
 | 
			
		||||
	Elf_Nhdr cmd_hdr;
 | 
			
		||||
	unsigned char command_line[0];
 | 
			
		||||
} elf_boot_notes = {
 | 
			
		||||
        .hdr = {
 | 
			
		||||
                .b_signature = 0x0E1FB007,
 | 
			
		||||
                .b_size = sizeof(elf_boot_notes),
 | 
			
		||||
                .b_checksum = 0,
 | 
			
		||||
                .b_records = 3,
 | 
			
		||||
        },
 | 
			
		||||
        .bl_hdr = {
 | 
			
		||||
                .n_namesz = 0,
 | 
			
		||||
                .n_descsz = sizeof(BOOTLOADER),
 | 
			
		||||
                .n_type = EBN_BOOTLOADER_NAME,
 | 
			
		||||
        },
 | 
			
		||||
        .bl_desc = BOOTLOADER,
 | 
			
		||||
        .blv_hdr = {
 | 
			
		||||
                .n_namesz = 0,
 | 
			
		||||
                .n_descsz = sizeof(BOOTLOADER_VERSION),
 | 
			
		||||
                .n_type = EBN_BOOTLOADER_VERSION,
 | 
			
		||||
        },
 | 
			
		||||
        .blv_desc = BOOTLOADER_VERSION,
 | 
			
		||||
        .cmd_hdr = {
 | 
			
		||||
                .n_namesz = 0,
 | 
			
		||||
                .n_descsz = 0,
 | 
			
		||||
                .n_type = EBN_COMMAND_LINE,
 | 
			
		||||
        },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void print_sects_bitmap(dol_segment * seg)
 | 
			
		||||
{
 | 
			
		||||
	int i, first_seen;
 | 
			
		||||
 | 
			
		||||
	printf("\t" "sects_bitmap");
 | 
			
		||||
	first_seen = 0;
 | 
			
		||||
	for (i = 0; i < DOL_MAX_SECT; i++) {
 | 
			
		||||
		if ((seg->sects_bitmap & (1 << i)) == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		printf("%c%d", (first_seen ? ',' : '='), i);
 | 
			
		||||
		first_seen = 1;
 | 
			
		||||
	}
 | 
			
		||||
	printf("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_dol_segment(dol_segment * seg)
 | 
			
		||||
{
 | 
			
		||||
	printf("dol segment:\n");
 | 
			
		||||
	printf("\t" "start=%08lx, size=%ld (%08lx)\n",
 | 
			
		||||
	       (unsigned long)seg->start, (unsigned long)seg->size,
 | 
			
		||||
	       (unsigned long)seg->size);
 | 
			
		||||
	printf("\t" "end=%08lx\n", (unsigned long)dol_seg_end(seg));
 | 
			
		||||
	print_sects_bitmap(seg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int load_dol_segments(dol_segment * seg, int max_segs, dol_header * h)
 | 
			
		||||
{
 | 
			
		||||
	int i, n, remaining;
 | 
			
		||||
	unsigned int start, size;
 | 
			
		||||
	unsigned long adj1, adj2, end1;
 | 
			
		||||
 | 
			
		||||
	n = 0;
 | 
			
		||||
	remaining = max_segs;
 | 
			
		||||
	for (i = 0; i < DOL_MAX_SECT && remaining > 0; i++) {
 | 
			
		||||
		/* zero here means the section is not in use */
 | 
			
		||||
		if (dol_sect_size(h, i) == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* we initially map 1 seg to 1 sect */
 | 
			
		||||
		seg->sects_bitmap = (1 << i);
 | 
			
		||||
 | 
			
		||||
		start = dol_sect_address(h, i);
 | 
			
		||||
		size = dol_sect_size(h, i);
 | 
			
		||||
 | 
			
		||||
		/* page align the segment */
 | 
			
		||||
		seg->start = start & PAGE_MASK;
 | 
			
		||||
		end1 = start + size;
 | 
			
		||||
		adj1 = start - seg->start;
 | 
			
		||||
		adj2 = PAGE_ALIGN(end1) - end1;
 | 
			
		||||
		seg->size = adj1 + size + adj2;
 | 
			
		||||
 | 
			
		||||
		//print_dol_segment(seg);
 | 
			
		||||
 | 
			
		||||
		seg++;
 | 
			
		||||
		remaining--;
 | 
			
		||||
		n++;
 | 
			
		||||
	}
 | 
			
		||||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void fix_dol_segments_overlaps(dol_segment * seg, int max_segs)
 | 
			
		||||
{
 | 
			
		||||
	int i, j;
 | 
			
		||||
	dol_segment *p, *pp;
 | 
			
		||||
	long extra_length;
 | 
			
		||||
 | 
			
		||||
	/* look for overlapping segments and fix them */
 | 
			
		||||
	for (i = 0; i < max_segs; i++) {
 | 
			
		||||
		p = seg + i;	/* segment p */
 | 
			
		||||
 | 
			
		||||
		/* not really a segment */
 | 
			
		||||
		if (p->size == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* check if overlaps any previous segments */
 | 
			
		||||
		for (j = 0; j < i; j++) {
 | 
			
		||||
			pp = seg + j;	/* segment pp */
 | 
			
		||||
 | 
			
		||||
			/* not a segment or no overlap */
 | 
			
		||||
			if (pp->size == 0 || !dol_seg_overlaps(p, pp))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			/* merge the two segments */
 | 
			
		||||
			if (pp->start < p->start) {
 | 
			
		||||
				/* extend pp to include p and delete p */
 | 
			
		||||
				extra_length = dol_seg_end(p) - dol_seg_end(pp);
 | 
			
		||||
				if (extra_length > 0) {
 | 
			
		||||
					pp->size += extra_length;
 | 
			
		||||
				}
 | 
			
		||||
				pp->sects_bitmap |= p->sects_bitmap;
 | 
			
		||||
				p->size = p->start = p->sects_bitmap = 0;
 | 
			
		||||
 | 
			
		||||
				/* restart the loop because p was deleted */
 | 
			
		||||
				i = 0;
 | 
			
		||||
				break;
 | 
			
		||||
			} else {
 | 
			
		||||
				/* extend p to include pp and delete pp */
 | 
			
		||||
				extra_length = dol_seg_end(pp) - dol_seg_end(p);
 | 
			
		||||
				if (extra_length > 0) {
 | 
			
		||||
					p->size += extra_length;
 | 
			
		||||
				}
 | 
			
		||||
				p->sects_bitmap |= pp->sects_bitmap;
 | 
			
		||||
				pp->size = pp->start = pp->sects_bitmap = 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dol_ppc_probe(const char *buf, off_t dol_length)
 | 
			
		||||
{
 | 
			
		||||
	dol_header header, *h;
 | 
			
		||||
	int i, valid = 0;
 | 
			
		||||
 | 
			
		||||
	/* the DOL file should be at least as long as the DOL header */
 | 
			
		||||
	if (dol_length < DOL_HEADER_SIZE) {
 | 
			
		||||
		if (debug) {
 | 
			
		||||
			fprintf(stderr, "Not a DOL file, too short.\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* read the DOL header */
 | 
			
		||||
	memcpy(&header, buf, sizeof(header));
 | 
			
		||||
	h = &header;
 | 
			
		||||
 | 
			
		||||
	/* now perform some sanity checks */
 | 
			
		||||
	for (i = 0; i < DOL_MAX_SECT; i++) {
 | 
			
		||||
		/* DOL segment MAY NOT be physically stored in the header */
 | 
			
		||||
		if ((dol_sect_offset(h, i) != 0)
 | 
			
		||||
		    && (dol_sect_offset(h, i) < DOL_HEADER_SIZE)) {
 | 
			
		||||
			if (debug) {
 | 
			
		||||
				fprintf(stderr,
 | 
			
		||||
					"%s segment offset within DOL header\n",
 | 
			
		||||
					dol_sect_type(i));
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* end of physical storage must be within file */
 | 
			
		||||
		if (dol_sect_offset(h, i) + dol_sect_size(h, i) > dol_length) {
 | 
			
		||||
			if (debug) {
 | 
			
		||||
				fprintf(stderr,
 | 
			
		||||
					"%s segment past DOL file size\n",
 | 
			
		||||
					dol_sect_type(i));
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* we only should accept DOLs with segments above 2GB */
 | 
			
		||||
		if (dol_sect_address(h, i) != 0
 | 
			
		||||
		    && !(dol_sect_address(h, i) & 0x80000000)) {
 | 
			
		||||
			fprintf(stderr, "warning, %s segment below 2GB\n",
 | 
			
		||||
				dol_sect_type(i));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (i < DOL_SECT_MAX_TEXT) {
 | 
			
		||||
			/* remember that entrypoint was in a code segment */
 | 
			
		||||
			if (h->entry_point >= dol_sect_address(h, i)
 | 
			
		||||
			    && h->entry_point < dol_sect_address(h, i) +
 | 
			
		||||
			    dol_sect_size(h, i))
 | 
			
		||||
				valid = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* if there is a BSS segment it must^H^H^H^Hshould be above 2GB, too */
 | 
			
		||||
	if (h->address_bss != 0 && !(h->address_bss & 0x80000000)) {
 | 
			
		||||
		fprintf(stderr, "warning, BSS segment below 2GB\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* if entrypoint is not within a code segment reject this file */
 | 
			
		||||
	if (!valid) {
 | 
			
		||||
		if (debug) {
 | 
			
		||||
			fprintf(stderr, "Entry point out of text segment\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* I've got a dol */
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dol_ppc_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf
 | 
			
		||||
	    ("-d, --debug               Enable debugging to help spot a failure.\n"
 | 
			
		||||
	     "    --command-line=STRING Set the kernel command line to STRING.\n"
 | 
			
		||||
	     "    --append=STRING       Set the kernel command line to STRING.\n");
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int dol_ppc_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	dol_header header, *h;
 | 
			
		||||
	unsigned long entry;
 | 
			
		||||
	char *arg_buf;
 | 
			
		||||
	size_t arg_bytes;
 | 
			
		||||
	unsigned long arg_base;
 | 
			
		||||
	struct boot_notes *notes;
 | 
			
		||||
	size_t note_bytes;
 | 
			
		||||
	const char *command_line;
 | 
			
		||||
	int command_line_len;
 | 
			
		||||
	unsigned long mstart;
 | 
			
		||||
	dol_segment dol_segs[DOL_MAX_SECT];
 | 
			
		||||
	unsigned int sects_bitmap;
 | 
			
		||||
	unsigned long lowest_start;
 | 
			
		||||
	int i, j, k;
 | 
			
		||||
	int opt;
 | 
			
		||||
#define OPT_APPEND      (OPT_ARCH_MAX+0)
 | 
			
		||||
 | 
			
		||||
        static const struct option options[] = {
 | 
			
		||||
                KEXEC_ARCH_OPTIONS
 | 
			
		||||
                {"debug",        0, 0, OPT_DEBUG},
 | 
			
		||||
                {"command-line", 1, 0, OPT_APPEND},
 | 
			
		||||
                {"append",       1, 0, OPT_APPEND},
 | 
			
		||||
                {0, 0, 0, 0},
 | 
			
		||||
        };
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Parse the command line arguments
 | 
			
		||||
	 */
 | 
			
		||||
	debug = 0;
 | 
			
		||||
	command_line = 0;
 | 
			
		||||
	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch (opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_DEBUG:
 | 
			
		||||
			debug = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_APPEND:
 | 
			
		||||
			command_line = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	command_line_len = 0;
 | 
			
		||||
	if (command_line) {
 | 
			
		||||
		command_line_len = strlen(command_line) + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* read the DOL header */
 | 
			
		||||
	memcpy(&header, buf, sizeof(header));
 | 
			
		||||
	h = &header;
 | 
			
		||||
 | 
			
		||||
	/* set entry point */
 | 
			
		||||
	entry = h->entry_point;
 | 
			
		||||
 | 
			
		||||
	/* convert the DOL sections into suitable page aligned segments */
 | 
			
		||||
	memset(dol_segs, 0, sizeof(dol_segs));
 | 
			
		||||
 | 
			
		||||
	load_dol_segments(dol_segs, DOL_MAX_SECT, h);
 | 
			
		||||
	fix_dol_segments_overlaps(dol_segs, DOL_MAX_SECT);
 | 
			
		||||
 | 
			
		||||
	/* load rest of segments */
 | 
			
		||||
	for (i = 0; i < DOL_MAX_SECT; i++) {
 | 
			
		||||
		unsigned char *seg_buf;
 | 
			
		||||
		/* not a segment */
 | 
			
		||||
		if (dol_segs[i].size == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		//print_dol_segment(&dol_segs[i]);
 | 
			
		||||
 | 
			
		||||
		/* prepare segment */
 | 
			
		||||
		seg_buf = xmalloc(dol_segs[i].size);
 | 
			
		||||
		mstart = dol_segs[i].start;
 | 
			
		||||
		if (mstart & 0xf0000000) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * GameCube DOLs expect memory mapped this way:
 | 
			
		||||
			 *
 | 
			
		||||
			 * 80000000 - 817fffff 24MB RAM, cached
 | 
			
		||||
			 * c0000000 - c17fffff 24MB RAM, not cached
 | 
			
		||||
			 *
 | 
			
		||||
			 * kexec, instead, needs physical memory layout, so
 | 
			
		||||
			 * we clear the upper bits of the address.
 | 
			
		||||
			 * (2 bits should be enough, indeed)
 | 
			
		||||
			 */
 | 
			
		||||
			mstart &= ~0xf0000000;	/* clear bits 0-3, ibm syntax */
 | 
			
		||||
		}
 | 
			
		||||
		add_segment(info,
 | 
			
		||||
			seg_buf, dol_segs[i].size, 
 | 
			
		||||
			mstart, dol_segs[i].size);
 | 
			
		||||
			
 | 
			
		||||
			
 | 
			
		||||
		/* load sections into segment memory, according to bitmap */
 | 
			
		||||
		sects_bitmap = 0;
 | 
			
		||||
		while (sects_bitmap != dol_segs[i].sects_bitmap) {
 | 
			
		||||
			unsigned char *sec_buf;
 | 
			
		||||
			/* find lowest start address for section */
 | 
			
		||||
			lowest_start = 0xffffffff;
 | 
			
		||||
			for (j = -1, k = 0; k < DOL_MAX_SECT; k++) {
 | 
			
		||||
				/* continue if section is already done */
 | 
			
		||||
				if ((sects_bitmap & (1 << k)) != 0)
 | 
			
		||||
					continue;
 | 
			
		||||
				/* do nothing for non sections */
 | 
			
		||||
				if ((dol_segs[i].sects_bitmap & (1 << k)) == 0)
 | 
			
		||||
					continue;
 | 
			
		||||
				/* found new candidate */
 | 
			
		||||
				if (dol_sect_address(h, k) < lowest_start) {
 | 
			
		||||
					lowest_start = dol_sect_address(h, k);
 | 
			
		||||
					j = k;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			/* mark section as being loaded */
 | 
			
		||||
			sects_bitmap |= (1 << j);
 | 
			
		||||
 | 
			
		||||
			/* read it from file to the right place */
 | 
			
		||||
			sec_buf = seg_buf + 
 | 
			
		||||
			    (dol_sect_address(h, j) - dol_segs[i].start);
 | 
			
		||||
			memcpy(sec_buf, buf + dol_sect_offset(h, j), 
 | 
			
		||||
				dol_sect_size(h, j));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* build the setup glue and argument segment (segment 0) */
 | 
			
		||||
	note_bytes = sizeof(elf_boot_notes) + ((command_line_len + 3) & ~3);
 | 
			
		||||
	arg_bytes = note_bytes + ((setup_dol_size + 3) & ~3);
 | 
			
		||||
 | 
			
		||||
	arg_buf = xmalloc(arg_bytes);
 | 
			
		||||
	arg_base = add_buffer(info,
 | 
			
		||||
		arg_buf, arg_bytes, arg_bytes, 4, 0, 0xFFFFFFFFUL, 1);
 | 
			
		||||
 | 
			
		||||
	notes = (struct boot_notes *)(arg_buf + ((setup_dol_size + 3) & ~3));
 | 
			
		||||
 | 
			
		||||
	notes->hdr.b_size = note_bytes;
 | 
			
		||||
	notes->cmd_hdr.n_descsz = command_line_len;
 | 
			
		||||
	notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
 | 
			
		||||
 | 
			
		||||
	setup_dol_regs.spr8 = entry;	/* Link Register */
 | 
			
		||||
 | 
			
		||||
	memcpy(arg_buf, setup_dol_start, setup_dol_size);
 | 
			
		||||
	memcpy(notes, &elf_boot_notes, sizeof(elf_boot_notes));
 | 
			
		||||
	memcpy(notes->command_line, command_line, command_line_len);
 | 
			
		||||
 | 
			
		||||
	if (debug) {
 | 
			
		||||
		fprintf(stdout, "entry       = %p\n", (void *)arg_base);
 | 
			
		||||
		print_segments(stdout, info);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->entry = (void *)arg_base;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										225
									
								
								kexec/arch/ppc/kexec-elf-ppc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								kexec/arch/ppc/kexec-elf-ppc.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,225 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec-elf-ppc.c - kexec Elf loader for the PowerPC
 | 
			
		||||
 * Copyright (C) 2004 Albert Herranz
 | 
			
		||||
 *
 | 
			
		||||
 * This source code is licensed under the GNU General Public License,
 | 
			
		||||
 * Version 2.  See the file COPYING for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include <ip_checksum.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "kexec-ppc.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
#define BOOTLOADER         "kexec"
 | 
			
		||||
#define BOOTLOADER_VERSION VERSION
 | 
			
		||||
#define MAX_COMMAND_LINE   256
 | 
			
		||||
 | 
			
		||||
#define UPSZ(X) ((sizeof(X) + 3) & ~3)
 | 
			
		||||
static struct boot_notes {
 | 
			
		||||
	Elf_Bhdr hdr;
 | 
			
		||||
	Elf_Nhdr bl_hdr;
 | 
			
		||||
	unsigned char bl_desc[UPSZ(BOOTLOADER)];
 | 
			
		||||
	Elf_Nhdr blv_hdr;
 | 
			
		||||
	unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
 | 
			
		||||
	Elf_Nhdr cmd_hdr;
 | 
			
		||||
	unsigned char command_line[0];
 | 
			
		||||
} elf_boot_notes = {
 | 
			
		||||
	.hdr = {
 | 
			
		||||
		.b_signature = 0x0E1FB007,
 | 
			
		||||
		.b_size = sizeof(elf_boot_notes),
 | 
			
		||||
		.b_checksum = 0,
 | 
			
		||||
		.b_records = 3,
 | 
			
		||||
	},
 | 
			
		||||
	.bl_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = sizeof(BOOTLOADER),
 | 
			
		||||
		.n_type = EBN_BOOTLOADER_NAME,
 | 
			
		||||
	},
 | 
			
		||||
	.bl_desc = BOOTLOADER,
 | 
			
		||||
	.blv_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = sizeof(BOOTLOADER_VERSION),
 | 
			
		||||
		.n_type = EBN_BOOTLOADER_VERSION,
 | 
			
		||||
	},
 | 
			
		||||
	.blv_desc = BOOTLOADER_VERSION,
 | 
			
		||||
	.cmd_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = 0,
 | 
			
		||||
		.n_type = EBN_COMMAND_LINE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int elf_ppc_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Verify the architecuture specific bits */
 | 
			
		||||
	if (ehdr.e_machine != EM_PPC) {
 | 
			
		||||
		/* for a different architecture */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not for this architecture.\n");
 | 
			
		||||
		}
 | 
			
		||||
		result = -1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	result = 0;
 | 
			
		||||
 out:
 | 
			
		||||
	free_elf_info(&ehdr);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_ppc_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf
 | 
			
		||||
	    (
 | 
			
		||||
	     "    --command-line=STRING Set the kernel command line to STRING.\n"
 | 
			
		||||
	     "    --append=STRING       Set the kernel command line to STRING.\n"
 | 
			
		||||
	     "    --gamecube=1|0        Enable/disable support for ELFs with changed\n"
 | 
			
		||||
	     "                          addresses suitable for the GameCube.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gamecube_hack_addresses(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_phdr *phdr, *phdr_end;
 | 
			
		||||
	phdr_end = ehdr->e_phdr + ehdr->e_phnum;
 | 
			
		||||
	for(phdr = ehdr->e_phdr; phdr != phdr_end; phdr++) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * GameCube ELF kernel is linked with memory mapped
 | 
			
		||||
		 * this way (to easily transform it into a DOL
 | 
			
		||||
		 * suitable for being loaded with psoload):
 | 
			
		||||
		 *
 | 
			
		||||
		 * 80000000 - 817fffff 24MB RAM, cached
 | 
			
		||||
		 * c0000000 - c17fffff 24MB RAM, not cached
 | 
			
		||||
		 *
 | 
			
		||||
		 * kexec, instead, needs physical memory layout, so
 | 
			
		||||
		 * we clear the upper bits of the address.
 | 
			
		||||
		 * (2 bits should be enough, indeed)
 | 
			
		||||
		 */
 | 
			
		||||
		phdr->p_paddr &= ~0xf0000000;	/* clear bits 0-3, ibm syntax */
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_ppc_load(int argc, char **argv,	const char *buf, off_t len, 
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	char *arg_buf;
 | 
			
		||||
	size_t arg_bytes;
 | 
			
		||||
	unsigned long arg_base;
 | 
			
		||||
	struct boot_notes *notes;
 | 
			
		||||
	size_t note_bytes;
 | 
			
		||||
	const char *command_line;
 | 
			
		||||
	int command_line_len;
 | 
			
		||||
	unsigned char *setup_start;
 | 
			
		||||
	uint32_t setup_size;
 | 
			
		||||
	int result;
 | 
			
		||||
#ifdef CONFIG_GAMECUBE
 | 
			
		||||
	int target_is_gamecube = 1;
 | 
			
		||||
#else
 | 
			
		||||
	int target_is_gamecube = 0;
 | 
			
		||||
#endif
 | 
			
		||||
	int opt;
 | 
			
		||||
#define OPT_APPEND	(OPT_ARCH_MAX+0)
 | 
			
		||||
#define OPT_GAMECUBE	(OPT_ARCH_MAX+1)
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{"command-line", 1, 0, OPT_APPEND},
 | 
			
		||||
		{"append",       1, 0, OPT_APPEND},
 | 
			
		||||
		{"gamecube",     1, 0, OPT_GAMECUBE},
 | 
			
		||||
		{0, 0, 0, 0},
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR "d";
 | 
			
		||||
 | 
			
		||||
	command_line = 0;
 | 
			
		||||
	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch (opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_APPEND:
 | 
			
		||||
			command_line = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_GAMECUBE:
 | 
			
		||||
			target_is_gamecube = atoi(optarg);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	command_line_len = 0;
 | 
			
		||||
	if (command_line) {
 | 
			
		||||
		command_line_len = strlen(command_line) + 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Parse the Elf file */
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		free_elf_info(&ehdr);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	if (target_is_gamecube) {
 | 
			
		||||
		gamecube_hack_addresses(&ehdr);
 | 
			
		||||
	}
 | 
			
		||||
	/* Load the Elf data */
 | 
			
		||||
	result = elf_exec_load(&ehdr, info);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		free_elf_info(&ehdr);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (target_is_gamecube) {
 | 
			
		||||
		setup_start = setup_dol_start;
 | 
			
		||||
		setup_size = setup_dol_size;
 | 
			
		||||
		setup_dol_regs.spr8 = ehdr.e_entry;	/* Link Register */
 | 
			
		||||
	} else {
 | 
			
		||||
		setup_start = setup_simple_start;
 | 
			
		||||
		setup_size = setup_simple_size;
 | 
			
		||||
		setup_simple_regs.spr8 = ehdr.e_entry;	/* Link Register */
 | 
			
		||||
	}
 | 
			
		||||
	note_bytes = sizeof(elf_boot_notes) + ((command_line_len + 3) & ~3);
 | 
			
		||||
	arg_bytes = note_bytes + ((setup_size + 3) & ~3);
 | 
			
		||||
 | 
			
		||||
	arg_buf = xmalloc(arg_bytes);
 | 
			
		||||
	arg_base = add_buffer(info, 
 | 
			
		||||
		arg_buf, arg_bytes, arg_bytes, 4, 0, elf_max_addr(&ehdr), 1);
 | 
			
		||||
 | 
			
		||||
	notes = (struct boot_notes *)(arg_buf + ((setup_size + 3) & ~3));
 | 
			
		||||
 | 
			
		||||
	memcpy(arg_buf, setup_start, setup_size);
 | 
			
		||||
	memcpy(notes, &elf_boot_notes, sizeof(elf_boot_notes));
 | 
			
		||||
	memcpy(notes->command_line, command_line, command_line_len);
 | 
			
		||||
	notes->hdr.b_size = note_bytes;
 | 
			
		||||
	notes->cmd_hdr.n_descsz = command_line_len;
 | 
			
		||||
	notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
 | 
			
		||||
 | 
			
		||||
	info->entry = (void *)arg_base;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								kexec/arch/ppc/kexec-elf-rel-ppc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								kexec/arch/ppc/kexec-elf-rel-ppc.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
int machine_verify_elf_rel(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data != ELFDATA2MSB) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->ei_class != ELFCLASS32) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->e_machine != EM_PPC) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
 | 
			
		||||
	void *location, unsigned long address, unsigned long value)
 | 
			
		||||
{
 | 
			
		||||
	switch(r_type) {
 | 
			
		||||
	case R_PPC_ADDR32:
 | 
			
		||||
		/* Simply set it */
 | 
			
		||||
		*(uint32_t *)location = value;
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	case R_PPC_ADDR16_LO:
 | 
			
		||||
		/* Low half of the symbol */
 | 
			
		||||
		*(uint16_t *)location = value;
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	case R_PPC_ADDR16_HA:
 | 
			
		||||
		/* Sign-adjusted lower 16 bits: PPC ELF ABI says:
 | 
			
		||||
		   (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
 | 
			
		||||
		   This is the same, only sane.
 | 
			
		||||
		*/
 | 
			
		||||
		*(uint16_t *)location = (value + 0x8000) >> 16;
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	case R_PPC_REL24:
 | 
			
		||||
		if ((int)(value - address) < -0x02000000
 | 
			
		||||
			|| (int)(value - address) >= 0x02000000)
 | 
			
		||||
		{
 | 
			
		||||
			die("Symbol more than 16MiB away");
 | 
			
		||||
		}
 | 
			
		||||
		/* Only replace bits 2 through 26 */
 | 
			
		||||
		*(uint32_t *)location
 | 
			
		||||
			= (*(uint32_t *)location & ~0x03fffffc)
 | 
			
		||||
			| ((value - address)
 | 
			
		||||
				& 0x03fffffc);
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	case R_PPC_REL32:
 | 
			
		||||
		/* 32-bit relative jump. */
 | 
			
		||||
		*(uint32_t *)location = value - address;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		die("Unknown rela relocation: %lu\n", r_type);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										151
									
								
								kexec/arch/ppc/kexec-ppc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								kexec/arch/ppc/kexec-ppc.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec-ppc.c - kexec for the PowerPC
 | 
			
		||||
 * Copyright (C) 2004, 2005 Albert Herranz
 | 
			
		||||
 *
 | 
			
		||||
 * This source code is licensed under the GNU General Public License,
 | 
			
		||||
 * Version 2.  See the file COPYING for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-syscall.h"
 | 
			
		||||
#include "kexec-ppc.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_MEMORY_RANGES  64
 | 
			
		||||
#define MAX_LINE          160
 | 
			
		||||
static struct memory_range memory_range[MAX_MEMORY_RANGES];
 | 
			
		||||
 | 
			
		||||
/* Return a sorted list of memory ranges. */
 | 
			
		||||
int get_memory_ranges(struct memory_range **range, int *ranges)
 | 
			
		||||
{
 | 
			
		||||
	int memory_ranges = 0;
 | 
			
		||||
#ifdef CONFIG_GAMECUBE
 | 
			
		||||
	/* RAM - lowmem used by DOLs - framebuffer */
 | 
			
		||||
	memory_range[memory_ranges].start = 0x00003000;
 | 
			
		||||
	memory_range[memory_ranges].end = 0x0174bfff;
 | 
			
		||||
	memory_range[memory_ranges].type = RANGE_RAM;
 | 
			
		||||
	memory_ranges++;
 | 
			
		||||
#else
 | 
			
		||||
#error Please, fix this for your platform
 | 
			
		||||
	const char iomem[] = "/proc/iomem";
 | 
			
		||||
	char line[MAX_LINE];
 | 
			
		||||
	FILE *fp;
 | 
			
		||||
	unsigned long long start, end;
 | 
			
		||||
	char *str;
 | 
			
		||||
	int type, consumed, count;
 | 
			
		||||
 | 
			
		||||
	fp = fopen(iomem, "r");
 | 
			
		||||
	if (!fp) {
 | 
			
		||||
		fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	while (fgets(line, sizeof(line), fp) != 0) {
 | 
			
		||||
		if (memory_ranges >= MAX_MEMORY_RANGES)
 | 
			
		||||
			break;
 | 
			
		||||
		count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed);
 | 
			
		||||
		if (count != 2)
 | 
			
		||||
			continue;
 | 
			
		||||
		str = line + consumed;
 | 
			
		||||
		end = end + 1;
 | 
			
		||||
#if 0
 | 
			
		||||
		printf("%016Lx-%016Lx : %s\n", start, end, str);
 | 
			
		||||
#endif
 | 
			
		||||
		if (memcmp(str, "System RAM\n", 11) == 0) {
 | 
			
		||||
			type = RANGE_RAM;
 | 
			
		||||
		} else if (memcmp(str, "reserved\n", 9) == 0) {
 | 
			
		||||
			type = RANGE_RESERVED;
 | 
			
		||||
		} else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
 | 
			
		||||
			type = RANGE_ACPI;
 | 
			
		||||
		} else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
 | 
			
		||||
			type = RANGE_ACPI_NVS;
 | 
			
		||||
		} else {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		memory_range[memory_ranges].start = start;
 | 
			
		||||
		memory_range[memory_ranges].end = end;
 | 
			
		||||
		memory_range[memory_ranges].type = type;
 | 
			
		||||
#if 0
 | 
			
		||||
		printf("%016Lx-%016Lx : %x\n", start, end, type);
 | 
			
		||||
#endif
 | 
			
		||||
		memory_ranges++;
 | 
			
		||||
	}
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
#endif
 | 
			
		||||
	*range = memory_range;
 | 
			
		||||
	*ranges = memory_ranges;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct file_type file_type[] = {
 | 
			
		||||
	{"elf-ppc", elf_ppc_probe, elf_ppc_load, elf_ppc_usage},
 | 
			
		||||
	{"dol-ppc", dol_ppc_probe, dol_ppc_load, dol_ppc_usage},
 | 
			
		||||
};
 | 
			
		||||
int file_types = sizeof(file_type) / sizeof(file_type[0]);
 | 
			
		||||
 | 
			
		||||
void arch_usage(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
} arch_options = {
 | 
			
		||||
};
 | 
			
		||||
int arch_process_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ 0, 			0, NULL, 0 },
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR;
 | 
			
		||||
	int opt;
 | 
			
		||||
	unsigned long value;
 | 
			
		||||
	char *end;
 | 
			
		||||
 | 
			
		||||
	opterr = 0; /* Don't complain about unrecognized options here */
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Reset getopt for the next pass; called in other source modules */
 | 
			
		||||
	opterr = 1;
 | 
			
		||||
	optind = 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	struct utsname utsname;
 | 
			
		||||
	result = uname(&utsname);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		fprintf(stderr, "uname failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(utsname.machine, "ppc") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* For compatibility with older patches 
 | 
			
		||||
		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_PPC here.
 | 
			
		||||
		 */
 | 
			
		||||
		*flags |= KEXEC_ARCH_DEFAULT;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		fprintf(stderr, "Unsupported machine type: %s\n",
 | 
			
		||||
			utsname.machine);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_update_purgatory(struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								kexec/arch/ppc/kexec-ppc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								kexec/arch/ppc/kexec-ppc.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
#ifndef KEXEC_PPC_H
 | 
			
		||||
#define KEXEC_PPC_H
 | 
			
		||||
 | 
			
		||||
extern unsigned char setup_simple_start[];
 | 
			
		||||
extern uint32_t setup_simple_size;
 | 
			
		||||
 | 
			
		||||
extern struct {
 | 
			
		||||
	uint32_t spr8;
 | 
			
		||||
} setup_simple_regs;
 | 
			
		||||
 | 
			
		||||
extern unsigned char setup_dol_start[];
 | 
			
		||||
extern uint32_t setup_dol_size;
 | 
			
		||||
 | 
			
		||||
extern struct {
 | 
			
		||||
	uint32_t spr8;
 | 
			
		||||
} setup_dol_regs;
 | 
			
		||||
 | 
			
		||||
int elf_ppc_probe(const char *buf, off_t len);
 | 
			
		||||
int elf_ppc_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void elf_ppc_usage(void);
 | 
			
		||||
 | 
			
		||||
int dol_ppc_probe(const char *buf, off_t len);
 | 
			
		||||
int dol_ppc_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void dol_ppc_usage(void);
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_PPC_H */
 | 
			
		||||
							
								
								
									
										174
									
								
								kexec/arch/ppc/ppc-setup-dol.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								kexec/arch/ppc/ppc-setup-dol.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,174 @@
 | 
			
		||||
/*
 | 
			
		||||
 * ppc-setup-dol.S - setup glue for Nintendo's GameCube
 | 
			
		||||
 * Copyright (C) 2004 Albert Herranz
 | 
			
		||||
 *
 | 
			
		||||
 * This source code is licensed under the GNU General Public License,
 | 
			
		||||
 * Version 2.  See the file COPYING for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ppc_asm.h"
 | 
			
		||||
 | 
			
		||||
	.data
 | 
			
		||||
	.globl setup_dol_start
 | 
			
		||||
setup_dol_start:
 | 
			
		||||
 | 
			
		||||
	/* Try to reproduce the GameCube "native" environment */
 | 
			
		||||
 | 
			
		||||
        /* Setup BATs */
 | 
			
		||||
	isync
 | 
			
		||||
	li	r8, 0
 | 
			
		||||
	mtspr	DBAT0U, r8
 | 
			
		||||
	mtspr	DBAT0L, r8
 | 
			
		||||
	mtspr	DBAT1U, r8
 | 
			
		||||
	mtspr	DBAT1L, r8
 | 
			
		||||
	mtspr	DBAT2U, r8
 | 
			
		||||
	mtspr	DBAT2L, r8
 | 
			
		||||
	mtspr	DBAT3U, r8
 | 
			
		||||
	mtspr	DBAT3L, r8
 | 
			
		||||
	mtspr	IBAT0U, r8
 | 
			
		||||
	mtspr	IBAT0L, r8
 | 
			
		||||
	mtspr	IBAT1U, r8
 | 
			
		||||
	mtspr	IBAT1L, r8
 | 
			
		||||
	mtspr	IBAT2U, r8
 | 
			
		||||
	mtspr	IBAT2L, r8
 | 
			
		||||
	mtspr	IBAT3U, r8
 | 
			
		||||
	mtspr	IBAT3L, r8
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Memory Map
 | 
			
		||||
         * start       end         size  description
 | 
			
		||||
	 * 0x80000000  0x817fffff  24MB  RAM, uncached
 | 
			
		||||
	 * 0xc0000000  0xc17fffff  24MB  RAM, cached
 | 
			
		||||
	 * 0xc8000000  0xc81fffff   2MB  Embedded Framebuffer
 | 
			
		||||
	 * 0xcc000000                    Hardware registers
 | 
			
		||||
	 * 0xe0000000                    Layer 2 transfer cache ??? 256KB
 | 
			
		||||
         *
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	isync
 | 
			
		||||
	lis	r8,     0x8000 /* IBAT0,DBAT0 for first 16Mbytes */
 | 
			
		||||
	ori	r8, r8, 0x01ff /* 16MB */
 | 
			
		||||
	mtspr	IBAT0U, r8
 | 
			
		||||
	mtspr	DBAT0U, r8
 | 
			
		||||
	li	r8,     0x0002 /* rw */
 | 
			
		||||
	mtspr	IBAT0L, r8
 | 
			
		||||
	mtspr	DBAT0L, r8
 | 
			
		||||
 | 
			
		||||
	lis	r8,     0xc000	/* DBAT1 for IO mem */
 | 
			
		||||
	ori	r8, r8, 0x1fff  /* 256MB */
 | 
			
		||||
	mtspr	DBAT1U, r8
 | 
			
		||||
	li	r8,     0x002a  /* uncached, guarded ,rw */
 | 
			
		||||
	mtspr	DBAT1L, r8
 | 
			
		||||
 | 
			
		||||
	lis	r8,     0x8100	/* IBAT2,DBAT2 for next 8Mbytes */
 | 
			
		||||
	ori	r8, r8, 0x00ff  /* 8MB */
 | 
			
		||||
	mtspr	IBAT2U, r8
 | 
			
		||||
	mtspr	DBAT2U, r8
 | 
			
		||||
	lis	r8,     0x0100
 | 
			
		||||
	ori	r8, r8, 0x0002  /* rw */
 | 
			
		||||
	mtspr	IBAT2L, r8
 | 
			
		||||
	mtspr	DBAT2L, r8
 | 
			
		||||
 | 
			
		||||
	lis	r8,     0xe000	/* DBAT3 for layer 2 transfer cache ??? */
 | 
			
		||||
	ori	r8, r8, 0x01fe  /* 16MB ??? */
 | 
			
		||||
	mtspr	DBAT3U, r8
 | 
			
		||||
	lis	r8,     0xe000
 | 
			
		||||
	ori	r8, r8, 0x0002  /* rw */
 | 
			
		||||
	mtspr	DBAT3L, r8
 | 
			
		||||
 | 
			
		||||
	sync
 | 
			
		||||
	isync
 | 
			
		||||
 | 
			
		||||
/* AFAIK, this is not strictly needed, although seems sane */
 | 
			
		||||
#if 1
 | 
			
		||||
	li      r9, 0
 | 
			
		||||
 | 
			
		||||
	/* page table pointer */
 | 
			
		||||
	sync
 | 
			
		||||
	mtspr	SDR1, r9
 | 
			
		||||
 | 
			
		||||
	/* segment registers */
 | 
			
		||||
	li	r8, 16
 | 
			
		||||
	mtctr	r8
 | 
			
		||||
	li	r8, 0
 | 
			
		||||
1:	mtsrin	r9, r8		/* zero */
 | 
			
		||||
	sync
 | 
			
		||||
	addis   r8,r8,0x1000	/* next register */
 | 
			
		||||
	bdnz	1b
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* switch MMU on and continue */
 | 
			
		||||
	RELOC_SYM(1f)
 | 
			
		||||
	mfmsr   r0
 | 
			
		||||
	ori     r0, r0, MSR_RI|MSR_ME|MSR_DR|MSR_IR
 | 
			
		||||
	mtspr   SRR1, r0
 | 
			
		||||
	oris    r3, r3, 0x8000		/* adjust text address */
 | 
			
		||||
	mtspr   SRR0, r3
 | 
			
		||||
	oris	r1, r1, 0x8000		/* adjust stack */
 | 
			
		||||
	sync
 | 
			
		||||
	rfi
 | 
			
		||||
 | 
			
		||||
1:
 | 
			
		||||
	/* from now on we run in a DOL-like environment */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* first, sanitize the hardware a little bit */
 | 
			
		||||
	/* although seems to be not needed in the general case */
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
	/* audio */
 | 
			
		||||
	lis	r8, 0xcc00	/* io mem */
 | 
			
		||||
	li	r9, 0
 | 
			
		||||
	sth     r9, 0x5036(r8)	/* stop audio sample */
 | 
			
		||||
	stw     r9, 0x6c00(r8)	/* stop streaming */
 | 
			
		||||
	stw     r9, 0x6c04(r8)	/* mute */
 | 
			
		||||
 | 
			
		||||
	/* video */
 | 
			
		||||
	mfspr	r8, 920		/* spr920 = HID2 */
 | 
			
		||||
	rlwinm	r8, r8, 0, 4, 2 /* stop GX FIFO, and more */
 | 
			
		||||
	mtspr	920, r8
 | 
			
		||||
 | 
			
		||||
	/* exi */
 | 
			
		||||
	lis	r8, 0xcc00	/* io mem */
 | 
			
		||||
1:      lwz     r9,0x680c(r8)   /* wait for dma transfer to complete */
 | 
			
		||||
	andi.   r9,r9,1
 | 
			
		||||
	bne+    1b
 | 
			
		||||
	stw     r9,0x6800(r8)   /* disable exi interrupts */
 | 
			
		||||
	addi    r8,r8,0x14	/* next channel */
 | 
			
		||||
	andi.   r9,r8,0x40	/* XXX 4 channels? */
 | 
			
		||||
	beq+    1b
 | 
			
		||||
 | 
			
		||||
	/* pic */
 | 
			
		||||
	lis	r8, 0xcc00	/* io mem */
 | 
			
		||||
	li	r9, 0
 | 
			
		||||
	stw	r9, 0x3004(r8)	/* mask all interrupts */
 | 
			
		||||
	stw	r9, 0x3000(r8)	/* clear interrupt cause */
 | 
			
		||||
 | 
			
		||||
	/* invalidate L1 data and instructions caches */
 | 
			
		||||
	mfspr	r8, HID0
 | 
			
		||||
	ori	r8, r8, HID0_ICFI|HID0_DCI
 | 
			
		||||
	mtspr	HID0, r8
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* jump to our entry point */
 | 
			
		||||
	RELOC_SYM(setup_dol_regs)
 | 
			
		||||
	mr      r9, r3
 | 
			
		||||
	lwz     r5, spr8 - setup_dol_regs(r9)
 | 
			
		||||
 | 
			
		||||
	mtlr    r5
 | 
			
		||||
	blr
 | 
			
		||||
 | 
			
		||||
	.balign 4
 | 
			
		||||
	.globl setup_dol_regs
 | 
			
		||||
setup_dol_regs:
 | 
			
		||||
spr8:	.long 0x00000000
 | 
			
		||||
 | 
			
		||||
        .balign 4
 | 
			
		||||
//#include "isobel_reloc_debug_console.s"
 | 
			
		||||
 | 
			
		||||
setup_dol_end:
 | 
			
		||||
 | 
			
		||||
	.globl setup_dol_size
 | 
			
		||||
setup_dol_size:	
 | 
			
		||||
	.long setup_dol_end - setup_dol_start
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										39
									
								
								kexec/arch/ppc/ppc-setup-simple.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								kexec/arch/ppc/ppc-setup-simple.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
/*
 | 
			
		||||
 * ppc-setup-simple.S - (hopefully) setup for simple embedded platforms
 | 
			
		||||
 * Copyright (C) 2004 Albert Herranz
 | 
			
		||||
 *
 | 
			
		||||
 * This source code is licensed under the GNU General Public License,
 | 
			
		||||
 * Version 2.  See the file COPYING for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Only suitable for platforms booting with MMU turned off.
 | 
			
		||||
 * -- Albert Herranz
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "ppc_asm.h"
 | 
			
		||||
 | 
			
		||||
	.data
 | 
			
		||||
	.globl setup_simple_start
 | 
			
		||||
setup_simple_start:
 | 
			
		||||
 | 
			
		||||
	/* should perform here any required setup */
 | 
			
		||||
 | 
			
		||||
	RELOC_SYM(setup_simple_regs)
 | 
			
		||||
	mr      r9, r3
 | 
			
		||||
	lwz     r5, spr8 - setup_simple_regs(r9)
 | 
			
		||||
 | 
			
		||||
	mtlr    r5
 | 
			
		||||
	blr
 | 
			
		||||
 | 
			
		||||
	.balign 4
 | 
			
		||||
	.globl setup_simple_regs
 | 
			
		||||
setup_simple_regs:
 | 
			
		||||
spr8:	.long 0x00000000
 | 
			
		||||
 | 
			
		||||
setup_simple_end:
 | 
			
		||||
 | 
			
		||||
	.globl setup_simple_size
 | 
			
		||||
setup_simple_size:	
 | 
			
		||||
	.long setup_simple_end - setup_simple_start
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										506
									
								
								kexec/arch/ppc/ppc_asm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										506
									
								
								kexec/arch/ppc/ppc_asm.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,506 @@
 | 
			
		||||
/*
 | 
			
		||||
 * ppc_asm.h - mainly bits stolen from Linux kernel asm/reg.h and asm/ppc_asm.h
 | 
			
		||||
 *
 | 
			
		||||
 * This source code is licensed under the GNU General Public License,
 | 
			
		||||
 * Version 2.  See the file COPYING for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Condition Register Bit Fields */
 | 
			
		||||
 | 
			
		||||
#define	cr0	0
 | 
			
		||||
#define	cr1	1
 | 
			
		||||
#define	cr2	2
 | 
			
		||||
#define	cr3	3
 | 
			
		||||
#define	cr4	4
 | 
			
		||||
#define	cr5	5
 | 
			
		||||
#define	cr6	6
 | 
			
		||||
#define	cr7	7
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* General Purpose Registers (GPRs) */
 | 
			
		||||
 | 
			
		||||
#define	r0	0
 | 
			
		||||
#define	r1	1
 | 
			
		||||
#define	r2	2
 | 
			
		||||
#define	r3	3
 | 
			
		||||
#define	r4	4
 | 
			
		||||
#define	r5	5
 | 
			
		||||
#define	r6	6
 | 
			
		||||
#define	r7	7
 | 
			
		||||
#define	r8	8
 | 
			
		||||
#define	r9	9
 | 
			
		||||
#define	r10	10
 | 
			
		||||
#define	r11	11
 | 
			
		||||
#define	r12	12
 | 
			
		||||
#define	r13	13
 | 
			
		||||
#define	r14	14
 | 
			
		||||
#define	r15	15
 | 
			
		||||
#define	r16	16
 | 
			
		||||
#define	r17	17
 | 
			
		||||
#define	r18	18
 | 
			
		||||
#define	r19	19
 | 
			
		||||
#define	r20	20
 | 
			
		||||
#define	r21	21
 | 
			
		||||
#define	r22	22
 | 
			
		||||
#define	r23	23
 | 
			
		||||
#define	r24	24
 | 
			
		||||
#define	r25	25
 | 
			
		||||
#define	r26	26
 | 
			
		||||
#define	r27	27
 | 
			
		||||
#define	r28	28
 | 
			
		||||
#define	r29	29
 | 
			
		||||
#define	r30	30
 | 
			
		||||
#define	r31	31
 | 
			
		||||
 | 
			
		||||
/* Machine State Register (MSR) Fields */
 | 
			
		||||
#define MSR_SF		(1<<63)
 | 
			
		||||
#define MSR_ISF		(1<<61)
 | 
			
		||||
#define MSR_VEC		(1<<25)		/* Enable AltiVec */
 | 
			
		||||
#define MSR_POW		(1<<18)		/* Enable Power Management */
 | 
			
		||||
#define MSR_WE		(1<<18)		/* Wait State Enable */
 | 
			
		||||
#define MSR_TGPR	(1<<17)		/* TLB Update registers in use */
 | 
			
		||||
#define MSR_CE		(1<<17)		/* Critical Interrupt Enable */
 | 
			
		||||
#define MSR_ILE		(1<<16)		/* Interrupt Little Endian */
 | 
			
		||||
#define MSR_EE		(1<<15)		/* External Interrupt Enable */
 | 
			
		||||
#define MSR_PR		(1<<14)		/* Problem State / Privilege Level */
 | 
			
		||||
#define MSR_FP		(1<<13)		/* Floating Point enable */
 | 
			
		||||
#define MSR_ME		(1<<12)		/* Machine Check Enable */
 | 
			
		||||
#define MSR_FE0		(1<<11)		/* Floating Exception mode 0 */
 | 
			
		||||
#define MSR_SE		(1<<10)		/* Single Step */
 | 
			
		||||
#define MSR_BE		(1<<9)		/* Branch Trace */
 | 
			
		||||
#define MSR_DE		(1<<9)		/* Debug Exception Enable */
 | 
			
		||||
#define MSR_FE1		(1<<8)		/* Floating Exception mode 1 */
 | 
			
		||||
#define MSR_IP		(1<<6)		/* Exception prefix 0x000/0xFFF */
 | 
			
		||||
#define MSR_IR		(1<<5)		/* Instruction Relocate */
 | 
			
		||||
#define MSR_DR		(1<<4)		/* Data Relocate */
 | 
			
		||||
#define MSR_PE		(1<<3)		/* Protection Enable */
 | 
			
		||||
#define MSR_PX		(1<<2)		/* Protection Exclusive Mode */
 | 
			
		||||
#define MSR_RI		(1<<1)		/* Recoverable Exception */
 | 
			
		||||
#define MSR_LE		(1<<0)		/* Little Endian */
 | 
			
		||||
 | 
			
		||||
/* Special Purpose Registers (SPRNs)*/
 | 
			
		||||
#define SPRN_CTR	0x009	/* Count Register */
 | 
			
		||||
#define SPRN_DABR	0x3F5	/* Data Address Breakpoint Register */
 | 
			
		||||
#define SPRN_DAR	0x013	/* Data Address Register */
 | 
			
		||||
#define SPRN_TBRL	0x10C	/* Time Base Read Lower Register (user, R/O) */
 | 
			
		||||
#define SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
 | 
			
		||||
#define SPRN_TBWL	0x11C	/* Time Base Lower Register (super, R/W) */
 | 
			
		||||
#define SPRN_TBWU	0x11D	/* Time Base Upper Register (super, R/W) */
 | 
			
		||||
#define SPRN_HIOR	0x137	/* 970 Hypervisor interrupt offset */
 | 
			
		||||
#define SPRN_DBAT0L	0x219	/* Data BAT 0 Lower Register */
 | 
			
		||||
#define SPRN_DBAT0U	0x218	/* Data BAT 0 Upper Register */
 | 
			
		||||
#define SPRN_DBAT1L	0x21B	/* Data BAT 1 Lower Register */
 | 
			
		||||
#define SPRN_DBAT1U	0x21A	/* Data BAT 1 Upper Register */
 | 
			
		||||
#define SPRN_DBAT2L	0x21D	/* Data BAT 2 Lower Register */
 | 
			
		||||
#define SPRN_DBAT2U	0x21C	/* Data BAT 2 Upper Register */
 | 
			
		||||
#define SPRN_DBAT3L	0x21F	/* Data BAT 3 Lower Register */
 | 
			
		||||
#define SPRN_DBAT3U	0x21E	/* Data BAT 3 Upper Register */
 | 
			
		||||
#define SPRN_DBAT4L	0x239	/* Data BAT 4 Lower Register */
 | 
			
		||||
#define SPRN_DBAT4U	0x238	/* Data BAT 4 Upper Register */
 | 
			
		||||
#define SPRN_DBAT5L	0x23B	/* Data BAT 5 Lower Register */
 | 
			
		||||
#define SPRN_DBAT5U	0x23A	/* Data BAT 5 Upper Register */
 | 
			
		||||
#define SPRN_DBAT6L	0x23D	/* Data BAT 6 Lower Register */
 | 
			
		||||
#define SPRN_DBAT6U	0x23C	/* Data BAT 6 Upper Register */
 | 
			
		||||
#define SPRN_DBAT7L	0x23F	/* Data BAT 7 Lower Register */
 | 
			
		||||
#define SPRN_DBAT7U	0x23E	/* Data BAT 7 Upper Register */
 | 
			
		||||
 | 
			
		||||
#define SPRN_DEC	0x016		/* Decrement Register */
 | 
			
		||||
#define SPRN_DER	0x095		/* Debug Enable Regsiter */
 | 
			
		||||
#define DER_RSTE	0x40000000	/* Reset Interrupt */
 | 
			
		||||
#define DER_CHSTPE	0x20000000	/* Check Stop */
 | 
			
		||||
#define DER_MCIE	0x10000000	/* Machine Check Interrupt */
 | 
			
		||||
#define DER_EXTIE	0x02000000	/* External Interrupt */
 | 
			
		||||
#define DER_ALIE	0x01000000	/* Alignment Interrupt */
 | 
			
		||||
#define DER_PRIE	0x00800000	/* Program Interrupt */
 | 
			
		||||
#define DER_FPUVIE	0x00400000	/* FP Unavailable Interrupt */
 | 
			
		||||
#define DER_DECIE	0x00200000	/* Decrementer Interrupt */
 | 
			
		||||
#define DER_SYSIE	0x00040000	/* System Call Interrupt */
 | 
			
		||||
#define DER_TRE		0x00020000	/* Trace Interrupt */
 | 
			
		||||
#define DER_SEIE	0x00004000	/* FP SW Emulation Interrupt */
 | 
			
		||||
#define DER_ITLBMSE	0x00002000	/* Imp. Spec. Instruction TLB Miss */
 | 
			
		||||
#define DER_ITLBERE	0x00001000	/* Imp. Spec. Instruction TLB Error */
 | 
			
		||||
#define DER_DTLBMSE	0x00000800	/* Imp. Spec. Data TLB Miss */
 | 
			
		||||
#define DER_DTLBERE	0x00000400	/* Imp. Spec. Data TLB Error */
 | 
			
		||||
#define DER_LBRKE	0x00000008	/* Load/Store Breakpoint Interrupt */
 | 
			
		||||
#define DER_IBRKE	0x00000004	/* Instruction Breakpoint Interrupt */
 | 
			
		||||
#define DER_EBRKE	0x00000002	/* External Breakpoint Interrupt */
 | 
			
		||||
#define DER_DPIE	0x00000001	/* Dev. Port Nonmaskable Request */
 | 
			
		||||
#define SPRN_DMISS	0x3D0		/* Data TLB Miss Register */
 | 
			
		||||
#define SPRN_DSISR	0x012	/* Data Storage Interrupt Status Register */
 | 
			
		||||
#define SPRN_EAR	0x11A		/* External Address Register */
 | 
			
		||||
#define SPRN_HASH1	0x3D2		/* Primary Hash Address Register */
 | 
			
		||||
#define SPRN_HASH2	0x3D3		/* Secondary Hash Address Resgister */
 | 
			
		||||
#define SPRN_HID0	0x3F0		/* Hardware Implementation Register 0 */
 | 
			
		||||
#define HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
 | 
			
		||||
#define HID0_EBA	(1<<29)		/* Enable Bus Address Parity */
 | 
			
		||||
#define HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
 | 
			
		||||
#define HID0_SBCLK	(1<<27)
 | 
			
		||||
#define HID0_EICE	(1<<26)
 | 
			
		||||
#define HID0_TBEN	(1<<26)		/* Timebase enable - 745x */
 | 
			
		||||
#define HID0_ECLK	(1<<25)
 | 
			
		||||
#define HID0_PAR	(1<<24)
 | 
			
		||||
#define HID0_STEN	(1<<24)		/* Software table search enable - 745x */
 | 
			
		||||
#define HID0_HIGH_BAT	(1<<23)		/* Enable high BATs - 7455 */
 | 
			
		||||
#define HID0_DOZE	(1<<23)
 | 
			
		||||
#define HID0_NAP	(1<<22)
 | 
			
		||||
#define HID0_SLEEP	(1<<21)
 | 
			
		||||
#define HID0_DPM	(1<<20)
 | 
			
		||||
#define HID0_BHTCLR	(1<<18)		/* Clear branch history table - 7450 */
 | 
			
		||||
#define HID0_XAEN	(1<<17)		/* Extended addressing enable - 7450 */
 | 
			
		||||
#define HID0_NHR	(1<<16)		/* Not hard reset (software bit-7450)*/
 | 
			
		||||
#define HID0_ICE	(1<<15)		/* Instruction Cache Enable */
 | 
			
		||||
#define HID0_DCE	(1<<14)		/* Data Cache Enable */
 | 
			
		||||
#define HID0_ILOCK	(1<<13)		/* Instruction Cache Lock */
 | 
			
		||||
#define HID0_DLOCK	(1<<12)		/* Data Cache Lock */
 | 
			
		||||
#define HID0_ICFI	(1<<11)		/* Instr. Cache Flash Invalidate */
 | 
			
		||||
#define HID0_DCI	(1<<10)		/* Data Cache Invalidate */
 | 
			
		||||
#define HID0_SPD	(1<<9)		/* Speculative disable */
 | 
			
		||||
#define HID0_SGE	(1<<7)		/* Store Gathering Enable */
 | 
			
		||||
#define HID0_SIED	(1<<7)		/* Serial Instr. Execution [Disable] */
 | 
			
		||||
#define HID0_DFCA	(1<<6)		/* Data Cache Flush Assist */
 | 
			
		||||
#define HID0_LRSTK	(1<<4)		/* Link register stack - 745x */
 | 
			
		||||
#define HID0_BTIC	(1<<5)		/* Branch Target Instr Cache Enable */
 | 
			
		||||
#define HID0_ABE	(1<<3)		/* Address Broadcast Enable */
 | 
			
		||||
#define HID0_FOLD	(1<<3)		/* Branch Folding enable - 745x */
 | 
			
		||||
#define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
 | 
			
		||||
#define HID0_BTCD	(1<<1)		/* Branch target cache disable */
 | 
			
		||||
#define HID0_NOPDST	(1<<1)		/* No-op dst, dstt, etc. instr. */
 | 
			
		||||
#define HID0_NOPTI	(1<<0)		/* No-op dcbt and dcbst instr. */
 | 
			
		||||
 | 
			
		||||
#define SPRN_HID1	0x3F1		/* Hardware Implementation Register 1 */
 | 
			
		||||
#define HID1_EMCP	(1<<31)		/* 7450 Machine Check Pin Enable */
 | 
			
		||||
#define HID1_PC0	(1<<16)		/* 7450 PLL_CFG[0] */
 | 
			
		||||
#define HID1_PC1	(1<<15)		/* 7450 PLL_CFG[1] */
 | 
			
		||||
#define HID1_PC2	(1<<14)		/* 7450 PLL_CFG[2] */
 | 
			
		||||
#define HID1_PC3	(1<<13)		/* 7450 PLL_CFG[3] */
 | 
			
		||||
#define HID1_SYNCBE	(1<<11)		/* 7450 ABE for sync, eieio */
 | 
			
		||||
#define HID1_ABE	(1<<10)		/* 7450 Address Broadcast Enable */
 | 
			
		||||
#define SPRN_HID2	0x3F8		/* Hardware Implementation Register 2 */
 | 
			
		||||
#define SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
 | 
			
		||||
#define SPRN_HID4	0x3F4		/* 970 HID4 */
 | 
			
		||||
#define SPRN_HID5	0x3F6		/* 970 HID5 */
 | 
			
		||||
#if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
 | 
			
		||||
#define SPRN_IAC1	0x3F4		/* Instruction Address Compare 1 */
 | 
			
		||||
#define SPRN_IAC2	0x3F5		/* Instruction Address Compare 2 */
 | 
			
		||||
#endif
 | 
			
		||||
#define SPRN_IBAT0L	0x211		/* Instruction BAT 0 Lower Register */
 | 
			
		||||
#define SPRN_IBAT0U	0x210		/* Instruction BAT 0 Upper Register */
 | 
			
		||||
#define SPRN_IBAT1L	0x213		/* Instruction BAT 1 Lower Register */
 | 
			
		||||
#define SPRN_IBAT1U	0x212		/* Instruction BAT 1 Upper Register */
 | 
			
		||||
#define SPRN_IBAT2L	0x215		/* Instruction BAT 2 Lower Register */
 | 
			
		||||
#define SPRN_IBAT2U	0x214		/* Instruction BAT 2 Upper Register */
 | 
			
		||||
#define SPRN_IBAT3L	0x217		/* Instruction BAT 3 Lower Register */
 | 
			
		||||
#define SPRN_IBAT3U	0x216		/* Instruction BAT 3 Upper Register */
 | 
			
		||||
#define SPRN_IBAT4L	0x231		/* Instruction BAT 4 Lower Register */
 | 
			
		||||
#define SPRN_IBAT4U	0x230		/* Instruction BAT 4 Upper Register */
 | 
			
		||||
#define SPRN_IBAT5L	0x233		/* Instruction BAT 5 Lower Register */
 | 
			
		||||
#define SPRN_IBAT5U	0x232		/* Instruction BAT 5 Upper Register */
 | 
			
		||||
#define SPRN_IBAT6L	0x235		/* Instruction BAT 6 Lower Register */
 | 
			
		||||
#define SPRN_IBAT6U	0x234		/* Instruction BAT 6 Upper Register */
 | 
			
		||||
#define SPRN_IBAT7L	0x237		/* Instruction BAT 7 Lower Register */
 | 
			
		||||
#define SPRN_IBAT7U	0x236		/* Instruction BAT 7 Upper Register */
 | 
			
		||||
#define SPRN_ICMP	0x3D5		/* Instruction TLB Compare Register */
 | 
			
		||||
#define SPRN_ICTC	0x3FB	/* Instruction Cache Throttling Control Reg */
 | 
			
		||||
#define SPRN_ICTRL	0x3F3	/* 1011 7450 icache and interrupt ctrl */
 | 
			
		||||
#define ICTRL_EICE	0x08000000	/* enable icache parity errs */
 | 
			
		||||
#define ICTRL_EDC	0x04000000	/* enable dcache parity errs */
 | 
			
		||||
#define ICTRL_EICP	0x00000100	/* enable icache par. check */
 | 
			
		||||
#define SPRN_IMISS	0x3D4		/* Instruction TLB Miss Register */
 | 
			
		||||
#define SPRN_IMMR	0x27E		/* Internal Memory Map Register */
 | 
			
		||||
#define SPRN_L2CR	0x3F9		/* Level 2 Cache Control Regsiter */
 | 
			
		||||
#define SPRN_L2CR2	0x3f8
 | 
			
		||||
#define L2CR_L2E		0x80000000	/* L2 enable */
 | 
			
		||||
#define L2CR_L2PE		0x40000000	/* L2 parity enable */
 | 
			
		||||
#define L2CR_L2SIZ_MASK		0x30000000	/* L2 size mask */
 | 
			
		||||
#define L2CR_L2SIZ_256KB	0x10000000	/* L2 size 256KB */
 | 
			
		||||
#define L2CR_L2SIZ_512KB	0x20000000	/* L2 size 512KB */
 | 
			
		||||
#define L2CR_L2SIZ_1MB		0x30000000	/* L2 size 1MB */
 | 
			
		||||
#define L2CR_L2CLK_MASK		0x0e000000	/* L2 clock mask */
 | 
			
		||||
#define L2CR_L2CLK_DISABLED	0x00000000	/* L2 clock disabled */
 | 
			
		||||
#define L2CR_L2CLK_DIV1		0x02000000	/* L2 clock / 1 */
 | 
			
		||||
#define L2CR_L2CLK_DIV1_5	0x04000000	/* L2 clock / 1.5 */
 | 
			
		||||
#define L2CR_L2CLK_DIV2		0x08000000	/* L2 clock / 2 */
 | 
			
		||||
#define L2CR_L2CLK_DIV2_5	0x0a000000	/* L2 clock / 2.5 */
 | 
			
		||||
#define L2CR_L2CLK_DIV3		0x0c000000	/* L2 clock / 3 */
 | 
			
		||||
#define L2CR_L2RAM_MASK		0x01800000	/* L2 RAM type mask */
 | 
			
		||||
#define L2CR_L2RAM_FLOW		0x00000000	/* L2 RAM flow through */
 | 
			
		||||
#define L2CR_L2RAM_PIPE		0x01000000	/* L2 RAM pipelined */
 | 
			
		||||
#define L2CR_L2RAM_PIPE_LW	0x01800000	/* L2 RAM pipelined latewr */
 | 
			
		||||
#define L2CR_L2DO		0x00400000	/* L2 data only */
 | 
			
		||||
#define L2CR_L2I		0x00200000	/* L2 global invalidate */
 | 
			
		||||
#define L2CR_L2CTL		0x00100000	/* L2 RAM control */
 | 
			
		||||
#define L2CR_L2WT		0x00080000	/* L2 write-through */
 | 
			
		||||
#define L2CR_L2TS		0x00040000	/* L2 test support */
 | 
			
		||||
#define L2CR_L2OH_MASK		0x00030000	/* L2 output hold mask */
 | 
			
		||||
#define L2CR_L2OH_0_5		0x00000000	/* L2 output hold 0.5 ns */
 | 
			
		||||
#define L2CR_L2OH_1_0		0x00010000	/* L2 output hold 1.0 ns */
 | 
			
		||||
#define L2CR_L2SL		0x00008000	/* L2 DLL slow */
 | 
			
		||||
#define L2CR_L2DF		0x00004000	/* L2 differential clock */
 | 
			
		||||
#define L2CR_L2BYP		0x00002000	/* L2 DLL bypass */
 | 
			
		||||
#define L2CR_L2IP		0x00000001	/* L2 GI in progress */
 | 
			
		||||
#define SPRN_L3CR		0x3FA	/* Level 3 Cache Control Regsiter */
 | 
			
		||||
#define L3CR_L3E		0x80000000	/* L3 enable */
 | 
			
		||||
#define L3CR_L3PE		0x40000000	/* L3 data parity enable */
 | 
			
		||||
#define L3CR_L3APE		0x20000000	/* L3 addr parity enable */
 | 
			
		||||
#define L3CR_L3SIZ		0x10000000	/* L3 size */
 | 
			
		||||
#define L3CR_L3CLKEN		0x08000000	/* L3 clock enable */
 | 
			
		||||
#define L3CR_L3RES		0x04000000	/* L3 special reserved bit */
 | 
			
		||||
#define L3CR_L3CLKDIV		0x03800000	/* L3 clock divisor */
 | 
			
		||||
#define L3CR_L3IO		0x00400000	/* L3 instruction only */
 | 
			
		||||
#define L3CR_L3SPO		0x00040000	/* L3 sample point override */
 | 
			
		||||
#define L3CR_L3CKSP		0x00030000	/* L3 clock sample point */
 | 
			
		||||
#define L3CR_L3PSP		0x0000e000	/* L3 P-clock sample point */
 | 
			
		||||
#define L3CR_L3REP		0x00001000	/* L3 replacement algorithm */
 | 
			
		||||
#define L3CR_L3HWF		0x00000800	/* L3 hardware flush */
 | 
			
		||||
#define L3CR_L3I		0x00000400	/* L3 global invalidate */
 | 
			
		||||
#define L3CR_L3RT		0x00000300	/* L3 SRAM type */
 | 
			
		||||
#define L3CR_L3NIRCA		0x00000080	/* L3 non-integer ratio clock adj. */
 | 
			
		||||
#define L3CR_L3DO		0x00000040	/* L3 data only mode */
 | 
			
		||||
#define L3CR_PMEN		0x00000004	/* L3 private memory enable */
 | 
			
		||||
#define L3CR_PMSIZ		0x00000001	/* L3 private memory size */
 | 
			
		||||
#define SPRN_MSSCR0	0x3f6	/* Memory Subsystem Control Register 0 */
 | 
			
		||||
#define SPRN_MSSSR0	0x3f7	/* Memory Subsystem Status Register 1 */
 | 
			
		||||
#define SPRN_LDSTCR	0x3f8	/* Load/Store control register */
 | 
			
		||||
#define SPRN_LDSTDB	0x3f4	/* */
 | 
			
		||||
#define SPRN_LR		0x008	/* Link Register */
 | 
			
		||||
#define SPRN_MMCR0	0x3B8	/* Monitor Mode Control Register 0 */
 | 
			
		||||
#define SPRN_MMCR1	0x3BC	/* Monitor Mode Control Register 1 */
 | 
			
		||||
#ifndef SPRN_PIR
 | 
			
		||||
#define SPRN_PIR	0x3FF	/* Processor Identification Register */
 | 
			
		||||
#endif
 | 
			
		||||
#define SPRN_PMC1	0x3B9	/* Performance Counter Register 1 */
 | 
			
		||||
#define SPRN_PMC2	0x3BA	/* Performance Counter Register 2 */
 | 
			
		||||
#define SPRN_PMC3	0x3BD	/* Performance Counter Register 3 */
 | 
			
		||||
#define SPRN_PMC4	0x3BE	/* Performance Counter Register 4 */
 | 
			
		||||
#define SPRN_PTEHI	0x3D5	/* 981 7450 PTE HI word (S/W TLB load) */
 | 
			
		||||
#define SPRN_PTELO	0x3D6	/* 982 7450 PTE LO word (S/W TLB load) */
 | 
			
		||||
#define SPRN_PVR	0x11F	/* Processor Version Register */
 | 
			
		||||
#define SPRN_RPA	0x3D6	/* Required Physical Address Register */
 | 
			
		||||
#define SPRN_SDA	0x3BF	/* Sampled Data Address Register */
 | 
			
		||||
#define SPRN_SDR1	0x019	/* MMU Hash Base Register */
 | 
			
		||||
#define SPRN_SIA	0x3BB	/* Sampled Instruction Address Register */
 | 
			
		||||
#define SPRN_SPRG0	0x110	/* Special Purpose Register General 0 */
 | 
			
		||||
#define SPRN_SPRG1	0x111	/* Special Purpose Register General 1 */
 | 
			
		||||
#define SPRN_SPRG2	0x112	/* Special Purpose Register General 2 */
 | 
			
		||||
#define SPRN_SPRG3	0x113	/* Special Purpose Register General 3 */
 | 
			
		||||
#define SPRN_SPRG4	0x114	/* Special Purpose Register General 4 */
 | 
			
		||||
#define SPRN_SPRG5	0x115	/* Special Purpose Register General 5 */
 | 
			
		||||
#define SPRN_SPRG6	0x116	/* Special Purpose Register General 6 */
 | 
			
		||||
#define SPRN_SPRG7	0x117	/* Special Purpose Register General 7 */
 | 
			
		||||
#define SPRN_SRR0	0x01A	/* Save/Restore Register 0 */
 | 
			
		||||
#define SPRN_SRR1	0x01B	/* Save/Restore Register 1 */
 | 
			
		||||
#define SPRN_THRM1	0x3FC		/* Thermal Management Register 1 */
 | 
			
		||||
/* these bits were defined in inverted endian sense originally, ugh, confusing */
 | 
			
		||||
#define THRM1_TIN	(1 << 31)
 | 
			
		||||
#define THRM1_TIV	(1 << 30)
 | 
			
		||||
#define THRM1_THRES(x)	((x&0x7f)<<23)
 | 
			
		||||
#define THRM3_SITV(x)	((x&0x3fff)<<1)
 | 
			
		||||
#define THRM1_TID	(1<<2)
 | 
			
		||||
#define THRM1_TIE	(1<<1)
 | 
			
		||||
#define THRM1_V		(1<<0)
 | 
			
		||||
#define SPRN_THRM2	0x3FD		/* Thermal Management Register 2 */
 | 
			
		||||
#define SPRN_THRM3	0x3FE		/* Thermal Management Register 3 */
 | 
			
		||||
#define THRM3_E		(1<<0)
 | 
			
		||||
#define SPRN_TLBMISS	0x3D4		/* 980 7450 TLB Miss Register */
 | 
			
		||||
#define SPRN_UMMCR0	0x3A8	/* User Monitor Mode Control Register 0 */
 | 
			
		||||
#define SPRN_UMMCR1	0x3AC	/* User Monitor Mode Control Register 0 */
 | 
			
		||||
#define SPRN_UPMC1	0x3A9	/* User Performance Counter Register 1 */
 | 
			
		||||
#define SPRN_UPMC2	0x3AA	/* User Performance Counter Register 2 */
 | 
			
		||||
#define SPRN_UPMC3	0x3AD	/* User Performance Counter Register 3 */
 | 
			
		||||
#define SPRN_UPMC4	0x3AE	/* User Performance Counter Register 4 */
 | 
			
		||||
#define SPRN_USIA	0x3AB	/* User Sampled Instruction Address Register */
 | 
			
		||||
#define SPRN_VRSAVE	0x100	/* Vector Register Save Register */
 | 
			
		||||
#define SPRN_XER	0x001	/* Fixed Point Exception Register */
 | 
			
		||||
 | 
			
		||||
/* Bit definitions for MMCR0 and PMC1 / PMC2. */
 | 
			
		||||
#define MMCR0_PMC1_CYCLES	(1 << 7)
 | 
			
		||||
#define MMCR0_PMC1_ICACHEMISS	(5 << 7)
 | 
			
		||||
#define MMCR0_PMC1_DTLB		(6 << 7)
 | 
			
		||||
#define MMCR0_PMC2_DCACHEMISS	0x6
 | 
			
		||||
#define MMCR0_PMC2_CYCLES	0x1
 | 
			
		||||
#define MMCR0_PMC2_ITLB		0x7
 | 
			
		||||
#define MMCR0_PMC2_LOADMISSTIME	0x5
 | 
			
		||||
 | 
			
		||||
/* Short-hand versions for a number of the above SPRNs */
 | 
			
		||||
#define CTR	SPRN_CTR	/* Counter Register */
 | 
			
		||||
#define DAR	SPRN_DAR	/* Data Address Register */
 | 
			
		||||
#define DABR	SPRN_DABR	/* Data Address Breakpoint Register */
 | 
			
		||||
#define DBAT0L	SPRN_DBAT0L	/* Data BAT 0 Lower Register */
 | 
			
		||||
#define DBAT0U	SPRN_DBAT0U	/* Data BAT 0 Upper Register */
 | 
			
		||||
#define DBAT1L	SPRN_DBAT1L	/* Data BAT 1 Lower Register */
 | 
			
		||||
#define DBAT1U	SPRN_DBAT1U	/* Data BAT 1 Upper Register */
 | 
			
		||||
#define DBAT2L	SPRN_DBAT2L	/* Data BAT 2 Lower Register */
 | 
			
		||||
#define DBAT2U	SPRN_DBAT2U	/* Data BAT 2 Upper Register */
 | 
			
		||||
#define DBAT3L	SPRN_DBAT3L	/* Data BAT 3 Lower Register */
 | 
			
		||||
#define DBAT3U	SPRN_DBAT3U	/* Data BAT 3 Upper Register */
 | 
			
		||||
#define DBAT4L	SPRN_DBAT4L	/* Data BAT 4 Lower Register */
 | 
			
		||||
#define DBAT4U	SPRN_DBAT4U	/* Data BAT 4 Upper Register */
 | 
			
		||||
#define DBAT5L	SPRN_DBAT5L	/* Data BAT 5 Lower Register */
 | 
			
		||||
#define DBAT5U	SPRN_DBAT5U	/* Data BAT 5 Upper Register */
 | 
			
		||||
#define DBAT6L	SPRN_DBAT6L	/* Data BAT 6 Lower Register */
 | 
			
		||||
#define DBAT6U	SPRN_DBAT6U	/* Data BAT 6 Upper Register */
 | 
			
		||||
#define DBAT7L	SPRN_DBAT7L	/* Data BAT 7 Lower Register */
 | 
			
		||||
#define DBAT7U	SPRN_DBAT7U	/* Data BAT 7 Upper Register */
 | 
			
		||||
#define DEC	SPRN_DEC	/* Decrement Register */
 | 
			
		||||
#define DMISS	SPRN_DMISS	/* Data TLB Miss Register */
 | 
			
		||||
#define DSISR	SPRN_DSISR	/* Data Storage Interrupt Status Register */
 | 
			
		||||
#define EAR	SPRN_EAR	/* External Address Register */
 | 
			
		||||
#define HASH1	SPRN_HASH1	/* Primary Hash Address Register */
 | 
			
		||||
#define HASH2	SPRN_HASH2	/* Secondary Hash Address Register */
 | 
			
		||||
#define HID0	SPRN_HID0	/* Hardware Implementation Register 0 */
 | 
			
		||||
#define HID1	SPRN_HID1	/* Hardware Implementation Register 1 */
 | 
			
		||||
#define IABR	SPRN_IABR	/* Instruction Address Breakpoint Register */
 | 
			
		||||
#define IBAT0L	SPRN_IBAT0L	/* Instruction BAT 0 Lower Register */
 | 
			
		||||
#define IBAT0U	SPRN_IBAT0U	/* Instruction BAT 0 Upper Register */
 | 
			
		||||
#define IBAT1L	SPRN_IBAT1L	/* Instruction BAT 1 Lower Register */
 | 
			
		||||
#define IBAT1U	SPRN_IBAT1U	/* Instruction BAT 1 Upper Register */
 | 
			
		||||
#define IBAT2L	SPRN_IBAT2L	/* Instruction BAT 2 Lower Register */
 | 
			
		||||
#define IBAT2U	SPRN_IBAT2U	/* Instruction BAT 2 Upper Register */
 | 
			
		||||
#define IBAT3L	SPRN_IBAT3L	/* Instruction BAT 3 Lower Register */
 | 
			
		||||
#define IBAT3U	SPRN_IBAT3U	/* Instruction BAT 3 Upper Register */
 | 
			
		||||
#define IBAT4L	SPRN_IBAT4L	/* Instruction BAT 4 Lower Register */
 | 
			
		||||
#define IBAT4U	SPRN_IBAT4U	/* Instruction BAT 4 Upper Register */
 | 
			
		||||
#define IBAT5L	SPRN_IBAT5L	/* Instruction BAT 5 Lower Register */
 | 
			
		||||
#define IBAT5U	SPRN_IBAT5U	/* Instruction BAT 5 Upper Register */
 | 
			
		||||
#define IBAT6L	SPRN_IBAT6L	/* Instruction BAT 6 Lower Register */
 | 
			
		||||
#define IBAT6U	SPRN_IBAT6U	/* Instruction BAT 6 Upper Register */
 | 
			
		||||
#define IBAT7L	SPRN_IBAT7L	/* Instruction BAT 7 Lower Register */
 | 
			
		||||
#define IBAT7U	SPRN_IBAT7U	/* Instruction BAT 7 Upper Register */
 | 
			
		||||
#define ICMP	SPRN_ICMP	/* Instruction TLB Compare Register */
 | 
			
		||||
#define IMISS	SPRN_IMISS	/* Instruction TLB Miss Register */
 | 
			
		||||
#define IMMR	SPRN_IMMR	/* PPC 860/821 Internal Memory Map Register */
 | 
			
		||||
#define L2CR	SPRN_L2CR	/* Classic PPC L2 cache control register */
 | 
			
		||||
#define L3CR	SPRN_L3CR	/* PPC 745x L3 cache control register */
 | 
			
		||||
#define LR	SPRN_LR
 | 
			
		||||
#define PVR	SPRN_PVR	/* Processor Version */
 | 
			
		||||
#define RPA	SPRN_RPA	/* Required Physical Address Register */
 | 
			
		||||
#define SDR1	SPRN_SDR1	/* MMU hash base register */
 | 
			
		||||
#define SPR0	SPRN_SPRG0	/* Supervisor Private Registers */
 | 
			
		||||
#define SPR1	SPRN_SPRG1
 | 
			
		||||
#define SPR2	SPRN_SPRG2
 | 
			
		||||
#define SPR3	SPRN_SPRG3
 | 
			
		||||
#define SPR4	SPRN_SPRG4
 | 
			
		||||
#define SPR5	SPRN_SPRG5
 | 
			
		||||
#define SPR6	SPRN_SPRG6
 | 
			
		||||
#define SPR7	SPRN_SPRG7
 | 
			
		||||
#define SPRG0	SPRN_SPRG0
 | 
			
		||||
#define SPRG1	SPRN_SPRG1
 | 
			
		||||
#define SPRG2	SPRN_SPRG2
 | 
			
		||||
#define SPRG3	SPRN_SPRG3
 | 
			
		||||
#define SPRG4	SPRN_SPRG4
 | 
			
		||||
#define SPRG5	SPRN_SPRG5
 | 
			
		||||
#define SPRG6	SPRN_SPRG6
 | 
			
		||||
#define SPRG7	SPRN_SPRG7
 | 
			
		||||
#define SRR0	SPRN_SRR0	/* Save and Restore Register 0 */
 | 
			
		||||
#define SRR1	SPRN_SRR1	/* Save and Restore Register 1 */
 | 
			
		||||
#define SRR2	SPRN_SRR2	/* Save and Restore Register 2 */
 | 
			
		||||
#define SRR3	SPRN_SRR3	/* Save and Restore Register 3 */
 | 
			
		||||
#define ICTC	SPRN_ICTC	/* Instruction Cache Throttling Control Reg */
 | 
			
		||||
#define THRM1	SPRN_THRM1	/* Thermal Management Register 1 */
 | 
			
		||||
#define THRM2	SPRN_THRM2	/* Thermal Management Register 2 */
 | 
			
		||||
#define THRM3	SPRN_THRM3	/* Thermal Management Register 3 */
 | 
			
		||||
#define XER	SPRN_XER
 | 
			
		||||
#define TBRL	SPRN_TBRL	/* Time Base Read Lower Register */
 | 
			
		||||
#define TBRU	SPRN_TBRU	/* Time Base Read Upper Register */
 | 
			
		||||
#define TBWL	SPRN_TBWL	/* Time Base Write Lower Register */
 | 
			
		||||
#define TBWU	SPRN_TBWU	/* Time Base Write Upper Register */
 | 
			
		||||
 | 
			
		||||
/* Processor Version Register */
 | 
			
		||||
 | 
			
		||||
/* Processor Version Register (PVR) field extraction */
 | 
			
		||||
 | 
			
		||||
#define PVR_VER(pvr)	(((pvr) >>  16) & 0xFFFF)	/* Version field */
 | 
			
		||||
#define PVR_REV(pvr)	(((pvr) >>   0) & 0xFFFF)	/* Revison field */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * IBM has further subdivided the standard PowerPC 16-bit version and
 | 
			
		||||
 * revision subfields of the PVR for the PowerPC 403s into the following:
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define PVR_FAM(pvr)	(((pvr) >> 20) & 0xFFF)	/* Family field */
 | 
			
		||||
#define PVR_MEM(pvr)	(((pvr) >> 16) & 0xF)	/* Member field */
 | 
			
		||||
#define PVR_CORE(pvr)	(((pvr) >> 12) & 0xF)	/* Core field */
 | 
			
		||||
#define PVR_CFG(pvr)	(((pvr) >>  8) & 0xF)	/* Configuration field */
 | 
			
		||||
#define PVR_MAJ(pvr)	(((pvr) >>  4) & 0xF)	/* Major revision field */
 | 
			
		||||
#define PVR_MIN(pvr)	(((pvr) >>  0) & 0xF)	/* Minor revision field */
 | 
			
		||||
 | 
			
		||||
/* Processor Version Numbers */
 | 
			
		||||
 | 
			
		||||
#define PVR_403GA	0x00200000
 | 
			
		||||
#define PVR_403GB	0x00200100
 | 
			
		||||
#define PVR_403GC	0x00200200
 | 
			
		||||
#define PVR_403GCX	0x00201400
 | 
			
		||||
#define PVR_405GP	0x40110000
 | 
			
		||||
#define PVR_STB03XXX	0x40310000
 | 
			
		||||
#define PVR_NP405H	0x41410000
 | 
			
		||||
#define PVR_NP405L	0x41610000
 | 
			
		||||
#define PVR_440GP_RB	0x40120440
 | 
			
		||||
#define PVR_440GP_RC1	0x40120481
 | 
			
		||||
#define PVR_440GP_RC2	0x40200481
 | 
			
		||||
#define PVR_440GX_RA	0x51b21850
 | 
			
		||||
#define PVR_440GX_RB	0x51b21851
 | 
			
		||||
#define PVR_440GX_RB1	0x51b21852
 | 
			
		||||
#define PVR_601		0x00010000
 | 
			
		||||
#define PVR_602		0x00050000
 | 
			
		||||
#define PVR_603		0x00030000
 | 
			
		||||
#define PVR_603e	0x00060000
 | 
			
		||||
#define PVR_603ev	0x00070000
 | 
			
		||||
#define PVR_603r	0x00071000
 | 
			
		||||
#define PVR_604		0x00040000
 | 
			
		||||
#define PVR_604e	0x00090000
 | 
			
		||||
#define PVR_604r	0x000A0000
 | 
			
		||||
#define PVR_620		0x00140000
 | 
			
		||||
#define PVR_740		0x00080000
 | 
			
		||||
#define PVR_750		PVR_740
 | 
			
		||||
#define PVR_740P	0x10080000
 | 
			
		||||
#define PVR_750P	PVR_740P
 | 
			
		||||
#define PVR_7400	0x000C0000
 | 
			
		||||
#define PVR_7410	0x800C0000
 | 
			
		||||
#define PVR_7450	0x80000000
 | 
			
		||||
/*
 | 
			
		||||
 * For the 8xx processors, all of them report the same PVR family for
 | 
			
		||||
 * the PowerPC core. The various versions of these processors must be
 | 
			
		||||
 * differentiated by the version number in the Communication Processor
 | 
			
		||||
 * Module (CPM).
 | 
			
		||||
 */
 | 
			
		||||
#define PVR_821		0x00500000
 | 
			
		||||
#define PVR_823		PVR_821
 | 
			
		||||
#define PVR_850		PVR_821
 | 
			
		||||
#define PVR_860		PVR_821
 | 
			
		||||
#define PVR_8240	0x00810100
 | 
			
		||||
#define PVR_8245	0x80811014
 | 
			
		||||
#define PVR_8260	PVR_8240
 | 
			
		||||
 | 
			
		||||
/* Segment Registers */
 | 
			
		||||
#define SR0	0
 | 
			
		||||
#define SR1	1
 | 
			
		||||
#define SR2	2
 | 
			
		||||
#define SR3	3
 | 
			
		||||
#define SR4	4
 | 
			
		||||
#define SR5	5
 | 
			
		||||
#define SR6	6
 | 
			
		||||
#define SR7	7
 | 
			
		||||
#define SR8	8
 | 
			
		||||
#define SR9	9
 | 
			
		||||
#define SR10	10
 | 
			
		||||
#define SR11	11
 | 
			
		||||
#define SR12	12
 | 
			
		||||
#define SR13	13
 | 
			
		||||
#define SR14	14
 | 
			
		||||
#define SR15	15
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* returns  r3 = relocated address of sym */
 | 
			
		||||
/* modifies r0 */
 | 
			
		||||
#define RELOC_SYM(sym) \
 | 
			
		||||
        mflr    r3; \
 | 
			
		||||
        bl      1f; \
 | 
			
		||||
1:      mflr    r0; \
 | 
			
		||||
        mtlr    r3; \
 | 
			
		||||
        lis     r3, 1b@ha; \
 | 
			
		||||
        ori     r3, r3, 1b@l; \
 | 
			
		||||
        subf    r0, r3, r0; \
 | 
			
		||||
        lis     r3, sym@ha; \
 | 
			
		||||
        ori     r3, r3, sym@l; \
 | 
			
		||||
        add     r3, r3, r0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								kexec/arch/ppc64/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								kexec/arch/ppc64/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#
 | 
			
		||||
# kexec ppc64 (linux booting linux)
 | 
			
		||||
#
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-elf-rel-ppc64.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/ppc64/kexec-zImage-ppc64.c 
 | 
			
		||||
 | 
			
		||||
KEXEC_S_SRCS+=
 | 
			
		||||
							
								
								
									
										11
									
								
								kexec/arch/ppc64/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								kexec/arch/ppc64/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef KEXEC_ARCH_PPC64_OPTIONS_H
 | 
			
		||||
#define KEXEC_ARCH_PPC64_OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#define OPT_ARCH_MAX   (OPT_MAX+0)
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPTIONS \
 | 
			
		||||
	KEXEC_OPTIONS \
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_ARCH_PPC64_OPTIONS_H */
 | 
			
		||||
							
								
								
									
										123
									
								
								kexec/arch/ppc64/kexec-elf-ppc64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								kexec/arch/ppc64/kexec-elf-ppc64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2004  Adam Litke (agl@us.ibm.com)
 | 
			
		||||
 * Copyright (C) 2004  IBM Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <linux/elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "kexec-ppc64.h"
 | 
			
		||||
 | 
			
		||||
#define BOOTLOADER         "kexec"
 | 
			
		||||
#define BOOTLOADER_VERSION VERSION
 | 
			
		||||
#define MAX_COMMAND_LINE   256
 | 
			
		||||
 | 
			
		||||
#define UPSZ(X) ((sizeof(X) + 3) & ~3)
 | 
			
		||||
static struct boot_notes {
 | 
			
		||||
	Elf_Bhdr hdr;
 | 
			
		||||
	Elf_Nhdr bl_hdr;
 | 
			
		||||
	unsigned char bl_desc[UPSZ(BOOTLOADER)];
 | 
			
		||||
	Elf_Nhdr blv_hdr;
 | 
			
		||||
	unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
 | 
			
		||||
	Elf_Nhdr cmd_hdr;
 | 
			
		||||
	unsigned char command_line[0];
 | 
			
		||||
} elf_boot_notes = {
 | 
			
		||||
	.hdr = {
 | 
			
		||||
		.b_signature = 0x0E1FB007,
 | 
			
		||||
		.b_size = sizeof(elf_boot_notes),
 | 
			
		||||
		.b_checksum = 0,
 | 
			
		||||
		.b_records = 3,
 | 
			
		||||
	},
 | 
			
		||||
	.bl_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = sizeof(BOOTLOADER),
 | 
			
		||||
		.n_type = EBN_BOOTLOADER_NAME,
 | 
			
		||||
	},
 | 
			
		||||
	.bl_desc = BOOTLOADER,
 | 
			
		||||
	.blv_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = sizeof(BOOTLOADER_VERSION),
 | 
			
		||||
		.n_type = EBN_BOOTLOADER_VERSION,
 | 
			
		||||
	},
 | 
			
		||||
	.blv_desc = BOOTLOADER_VERSION,
 | 
			
		||||
	.cmd_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = 0,
 | 
			
		||||
		.n_type = EBN_COMMAND_LINE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int elf_ppc64_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Verify the architecuture specific bits */
 | 
			
		||||
	if ((ehdr.e_machine != EM_PPC64) && (ehdr.e_machine != EM_PPC)) {
 | 
			
		||||
		/* for a different architecture */
 | 
			
		||||
		result = -1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	result = 0;
 | 
			
		||||
 out:
 | 
			
		||||
	free_elf_info(&ehdr);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len, 
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
 | 
			
		||||
	/* Parse command line arguments */
 | 
			
		||||
 | 
			
		||||
	/* Parse the Elf file */
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		free_elf_info(&ehdr);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load the Elf data */
 | 
			
		||||
	result = elf_exec_load(&ehdr, info);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		free_elf_info(&ehdr);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_ppc64_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "elf support is still broken\n");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								kexec/arch/ppc64/kexec-elf-rel-ppc64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								kexec/arch/ppc64/kexec-elf-rel-ppc64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
int machine_verify_elf_rel(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data != ELFDATA2MSB) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->ei_class != ELFCLASS64) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->e_machine != EM_PPC64) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct mem_shdr *toc_section(const struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_shdr *shdr, *shdr_end;
 | 
			
		||||
	unsigned char *strtab;
 | 
			
		||||
	strtab = ehdr->e_shdr[ehdr->e_shstrndx].sh_data;
 | 
			
		||||
	shdr_end = &ehdr->e_shdr[ehdr->shnum];
 | 
			
		||||
	for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
 | 
			
		||||
		if (strcmp(shdr->sh_name, ".toc") == 0) {
 | 
			
		||||
			return shdr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
 | 
			
		||||
   gives the value maximum span in an instruction which uses a signed
 | 
			
		||||
   offset) */
 | 
			
		||||
static unsigned long my_r2(const struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_shdr *shdr;
 | 
			
		||||
	shdr = toc_section(ehdr);
 | 
			
		||||
	if (!shdr) {
 | 
			
		||||
		die("TOC reloc without a toc section?");
 | 
			
		||||
	}
 | 
			
		||||
	return shdr->sh_addr + 0x8000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type,
 | 
			
		||||
	void *location, unsigned long address, unsigned long value)
 | 
			
		||||
{
 | 
			
		||||
	switch(r_type) {
 | 
			
		||||
	case R_PPC64_ADDR32:
 | 
			
		||||
		/* Simply set it */
 | 
			
		||||
		*(uint32_t *)location = value;
 | 
			
		||||
		break;
 | 
			
		||||
		
 | 
			
		||||
	case R_PPC64_ADDR64:
 | 
			
		||||
		/* Simply set it */
 | 
			
		||||
		*(uint64_t *)location = value;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case R_PPC64_TOC:
 | 
			
		||||
		*(uint64_t *)location = my_r2(ehdr);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case R_PPC64_TOC16_DS:
 | 
			
		||||
		/* Subtact TOC pointer */
 | 
			
		||||
		value -= my_r2(ehdr);
 | 
			
		||||
		if ((value & 3) != 0 || value + 0x8000 > 0xffff) {
 | 
			
		||||
			die("bad TOC16_DS relocation (%lu)\n", value);
 | 
			
		||||
		}
 | 
			
		||||
		*((uint16_t *) location)
 | 
			
		||||
			= (*((uint16_t *) location) & ~0xfffc)
 | 
			
		||||
			| (value & 0xfffc);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case R_PPC64_REL24:
 | 
			
		||||
		/* Convert value to relative */
 | 
			
		||||
		value -= address;
 | 
			
		||||
		if (value + 0x2000000 > 0x3ffffff || (value & 3) != 0){
 | 
			
		||||
			die("REL24 %li out of range!\n", 
 | 
			
		||||
				(long int)value);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Only replace bits 2 through 26 */
 | 
			
		||||
		*(uint32_t *)location 
 | 
			
		||||
			= (*(uint32_t *)location & ~0x03fffffc)
 | 
			
		||||
			| (value & 0x03fffffc);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		die("Unknown rela relocation: %lu\n", r_type);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								kexec/arch/ppc64/kexec-ppc64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								kexec/arch/ppc64/kexec-ppc64.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
#ifndef KEXEC_PPC64_H
 | 
			
		||||
#define KEXEC_PPC64_H
 | 
			
		||||
 | 
			
		||||
int elf_ppc64_probe(const char *buf, off_t len);
 | 
			
		||||
int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void elf_ppc64_usage(void);
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_PPC_H */
 | 
			
		||||
							
								
								
									
										173
									
								
								kexec/arch/ppc64/kexec-zImage-ppc64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								kexec/arch/ppc64/kexec-zImage-ppc64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,173 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2004  Adam Litke (agl@us.ibm.com)
 | 
			
		||||
 * Copyright (C) 2004  IBM Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <linux/elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_HEADERS 32
 | 
			
		||||
 | 
			
		||||
int zImage_ppc64_probe(FILE *file)
 | 
			
		||||
{
 | 
			
		||||
	Elf32_Ehdr elf;
 | 
			
		||||
 | 
			
		||||
	if (fseek(file, 0, SEEK_SET) < 0) {
 | 
			
		||||
		fprintf(stderr, "seek error: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (fread(&elf, sizeof(Elf32_Ehdr), 1, file) != 1) {
 | 
			
		||||
		fprintf(stderr, "read error: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (elf.e_machine == EM_PPC64) {
 | 
			
		||||
		fprintf(stderr, "Elf64 not supported\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (elf.e_ident[EI_MAG0]  == ELFMAG0        &&
 | 
			
		||||
		elf.e_ident[EI_MAG1]  == ELFMAG1        &&
 | 
			
		||||
		elf.e_ident[EI_MAG2]  == ELFMAG2        &&
 | 
			
		||||
		elf.e_ident[EI_MAG3]  == ELFMAG3        &&
 | 
			
		||||
		elf.e_ident[EI_CLASS] == ELFCLASS32  &&
 | 
			
		||||
		elf.e_ident[EI_DATA]  == ELFDATA2MSB &&
 | 
			
		||||
		elf.e_type            == ET_EXEC        &&
 | 
			
		||||
		elf.e_machine         == EM_PPC);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int zImage_ppc64_load(FILE *file, int argc, char **argv, void **ret_entry,
 | 
			
		||||
	struct kexec_segment **ret_segments, int *ret_nr_segments)
 | 
			
		||||
{
 | 
			
		||||
	Elf32_Ehdr elf;
 | 
			
		||||
	Elf32_Phdr *p, *ph;
 | 
			
		||||
	struct kexec_segment *segment;
 | 
			
		||||
	int i;
 | 
			
		||||
	unsigned long memsize, filesize, offset, load_loc;
 | 
			
		||||
 | 
			
		||||
	/* Parse command line arguments */
 | 
			
		||||
 | 
			
		||||
	/* Read in the Elf32 header */
 | 
			
		||||
        if (fseek(file, 0, SEEK_SET) < 0) {
 | 
			
		||||
		perror("seek error:");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
        if (fread(&elf, sizeof(Elf32_Ehdr), 1, file) != 1) {
 | 
			
		||||
		perror("read error: ");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (elf.e_phnum > MAX_HEADERS) {
 | 
			
		||||
		fprintf(stderr,
 | 
			
		||||
			"Only kernels with %i program headers are supported\n",
 | 
			
		||||
			MAX_HEADERS);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Read the section header */
 | 
			
		||||
	ph = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr) * elf.e_phnum);
 | 
			
		||||
	if (ph == 0) {
 | 
			
		||||
		perror("malloc failed: ");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (fseek(file, elf.e_phoff, SEEK_SET) < 0) {
 | 
			
		||||
		perror("seek failed: ");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (fread(ph, sizeof(Elf32_Phdr) * elf.e_phnum, 1, file) != 1) {
 | 
			
		||||
		perror("read error: ");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*ret_segments = malloc(elf.e_phnum * sizeof(struct kexec_segment));
 | 
			
		||||
	if (*ret_segments == 0) {
 | 
			
		||||
		fprintf(stderr, "malloc failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	segment = ret_segments[0];
 | 
			
		||||
 | 
			
		||||
	/* Scan through the program header */
 | 
			
		||||
	memsize = filesize = offset = 0;
 | 
			
		||||
	p = ph;
 | 
			
		||||
	for (i = 0; i < elf.e_phnum; ++i, ++p) {
 | 
			
		||||
		if (p->p_type != PT_LOAD || p->p_offset == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (memsize == 0) {
 | 
			
		||||
			offset = p->p_offset;
 | 
			
		||||
			memsize = p->p_memsz;
 | 
			
		||||
			filesize = p->p_filesz;
 | 
			
		||||
			load_loc = p->p_vaddr;
 | 
			
		||||
		} else {
 | 
			
		||||
			memsize = p->p_offset + p->p_memsz - offset;
 | 
			
		||||
			filesize = p->p_offset + p->p_filesz - offset;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (memsize == 0) {
 | 
			
		||||
		fprintf(stderr, "Can't find a loadable segment.\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load program segments */
 | 
			
		||||
	p = ph;
 | 
			
		||||
	segment->buf = malloc(filesize);
 | 
			
		||||
	if (segment->buf == 0) {
 | 
			
		||||
		perror("malloc failed: ");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < elf.e_phnum; ++i, ++p) {
 | 
			
		||||
		unsigned long mem_offset;
 | 
			
		||||
		if (p->p_type != PT_LOAD || p->p_offset == 0)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/* skip to the actual image */
 | 
			
		||||
		if (fseek(file, p->p_offset, SEEK_SET) < 0) {
 | 
			
		||||
			perror("seek error: ");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		mem_offset = p->p_vaddr - load_loc;
 | 
			
		||||
		if (fread(segment->buf+mem_offset, p->p_filesz, 1, file) != 1) {
 | 
			
		||||
			perror("read error: ");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	segment->mem = (void *) load_loc;
 | 
			
		||||
	segment->memsz = memsize;
 | 
			
		||||
	segment->bufsz = filesize;
 | 
			
		||||
	*ret_entry = elf.e_entry;
 | 
			
		||||
	*ret_nr_segments = i - 1;
 | 
			
		||||
	free(ph);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void zImage_ppc64_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	fprintf(stderr, "zImage support is still broken\n");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								kexec/arch/x86_64/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								kexec/arch/x86_64/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
#
 | 
			
		||||
# kexec x86_64 (linux booting linux)
 | 
			
		||||
#
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-elf-x86.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-bzImage.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-multiboot-x86.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-beoboot-x86.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/kexec-nbi.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/i386/x86-linux-setup.c
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/x86_64/kexec-x86_64.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/x86_64/kexec-elf-x86_64.c 
 | 
			
		||||
KEXEC_C_SRCS+= kexec/arch/x86_64/kexec-elf-rel-x86_64.c
 | 
			
		||||
							
								
								
									
										22
									
								
								kexec/arch/x86_64/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								kexec/arch/x86_64/include/arch/options.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
#ifndef KEXEC_ARCH_X86_64_OPTIONS_H
 | 
			
		||||
#define KEXEC_ARCH_X86_64_OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#define OPT_RESET_VGA      (OPT_MAX+0)
 | 
			
		||||
#define OPT_SERIAL         (OPT_MAX+1)
 | 
			
		||||
#define OPT_SERIAL_BAUD    (OPT_MAX+2)
 | 
			
		||||
#define OPT_CONSOLE_VGA    (OPT_MAX+3)
 | 
			
		||||
#define OPT_CONSOLE_SERIAL (OPT_MAX+4)
 | 
			
		||||
#define OPT_ARCH_MAX       (OPT_MAX+5)
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPTIONS \
 | 
			
		||||
	KEXEC_OPTIONS \
 | 
			
		||||
	{ "reset-vga",	    0, 0, OPT_RESET_VGA }, \
 | 
			
		||||
	{ "serial",	    1, 0, OPT_SERIAL }, \
 | 
			
		||||
	{ "serial-baud",    1, 0, OPT_SERIAL_BAUD }, \
 | 
			
		||||
	{ "console-vga",    0, 0, OPT_CONSOLE_VGA }, \
 | 
			
		||||
	{ "console-serial", 0, 0, OPT_CONSOLE_SERIAL }, \
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR ""
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_ARCH_X86_64_OPTIONS_H */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										93
									
								
								kexec/arch/x86_64/kexec-elf-rel-x86_64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								kexec/arch/x86_64/kexec-elf-rel-x86_64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
int machine_verify_elf_rel(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data != ELFDATA2LSB) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->ei_class != ELFCLASS64) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->e_machine != EM_X86_64) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *reloc_name(unsigned long r_type)
 | 
			
		||||
{
 | 
			
		||||
	static const char *r_name[] = {
 | 
			
		||||
	"R_X86_64_NONE",
 | 
			
		||||
	"R_X86_64_64",
 | 
			
		||||
	"R_X86_64_PC32",
 | 
			
		||||
	"R_X86_64_GOT32",
 | 
			
		||||
	"R_X86_64_PLT32",
 | 
			
		||||
	"R_X86_64_COPY",
 | 
			
		||||
	"R_X86_64_GLOB_DAT",
 | 
			
		||||
	"R_X86_64_JUMP_SLOT",
 | 
			
		||||
	"R_X86_64_RELATIVE",
 | 
			
		||||
	"R_X86_64_GOTPCREL",
 | 
			
		||||
	"R_X86_64_32",
 | 
			
		||||
	"R_X86_64_32S",
 | 
			
		||||
	"R_X86_64_16",
 | 
			
		||||
	"R_X86_64_PC16",
 | 
			
		||||
	"R_X86_64_8",
 | 
			
		||||
	"R_X86_64_PC8",
 | 
			
		||||
	"R_X86_64_DTPMOD64",
 | 
			
		||||
	"R_X86_64_DTPOFF64",
 | 
			
		||||
	"R_X86_64_TPOFF64",
 | 
			
		||||
	"R_X86_64_TLSGD",
 | 
			
		||||
	"R_X86_64_TLSLD",
 | 
			
		||||
	"R_X86_64_DTPOFF32",
 | 
			
		||||
	"R_X86_64_GOTTPOFF",
 | 
			
		||||
	"R_X86_64_TPOFF32",
 | 
			
		||||
	};
 | 
			
		||||
	static char buf[100];
 | 
			
		||||
	const char *name;
 | 
			
		||||
	if (r_type < (sizeof(reloc_name)/sizeof(r_name[0]))){
 | 
			
		||||
		name = r_name[r_type];
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		sprintf(buf, "R_X86_64_%lu", r_type);
 | 
			
		||||
		name = buf;
 | 
			
		||||
	}
 | 
			
		||||
	return name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, 
 | 
			
		||||
	void *location, unsigned long address, unsigned long value)
 | 
			
		||||
{
 | 
			
		||||
#if 0
 | 
			
		||||
	fprintf(stderr, "%s\n", reloc_name(r_type));
 | 
			
		||||
#endif
 | 
			
		||||
	switch(r_type) {
 | 
			
		||||
	case R_X86_64_NONE:
 | 
			
		||||
		break;
 | 
			
		||||
	case R_X86_64_64:
 | 
			
		||||
		*(uint64_t *)location = value;
 | 
			
		||||
		break;
 | 
			
		||||
	case R_X86_64_32:
 | 
			
		||||
		*(uint32_t *)location = value;
 | 
			
		||||
		if (value != *(uint32_t *)location)
 | 
			
		||||
			goto overflow;
 | 
			
		||||
		break;
 | 
			
		||||
	case R_X86_64_32S:
 | 
			
		||||
		*(uint32_t *)location = value;
 | 
			
		||||
		if ((int64_t)value != *(int32_t *)location)
 | 
			
		||||
			goto overflow;
 | 
			
		||||
		break;
 | 
			
		||||
	case R_X86_64_PC32: 
 | 
			
		||||
		*(uint32_t *)location = value - address;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		die("Unhandled rela relocation: %lu\n", reloc_name(r_type));
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	return;
 | 
			
		||||
 overflow:
 | 
			
		||||
	die("overflow in relocation type %s val %Lx\n", 
 | 
			
		||||
		reloc_name(r_type), value);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										239
									
								
								kexec/arch/x86_64/kexec-elf-x86_64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								kexec/arch/x86_64/kexec-elf-x86_64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <x86/x86-linux.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "../../kexec-elf-boot.h"
 | 
			
		||||
#include "../i386/x86-linux-setup.h"
 | 
			
		||||
#include "kexec-x86_64.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
int elf_x86_64_probe(const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_elf_exec_info(buf, len, &ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not an ELF executable\n");
 | 
			
		||||
		}
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Verify the architecuture specific bits */
 | 
			
		||||
	if (ehdr.e_machine != EM_X86_64) {
 | 
			
		||||
		/* for a different architecture */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not x86_64 ELF executable\n");
 | 
			
		||||
		}
 | 
			
		||||
		result = -1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	result = 0;
 | 
			
		||||
 out:
 | 
			
		||||
	free_elf_info(&ehdr);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_x86_64_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(	"    --command-line=STRING Set the kernel command line to STRING\n"
 | 
			
		||||
		"    --append=STRING       Set the kernel command line to STRING\n"
 | 
			
		||||
		"    --initrd=FILE         Use FILE as the kernel's initial ramdisk.\n"
 | 
			
		||||
		"    --ramdisk=FILE        Use FILE as the kernel's initial ramdisk.\n"
 | 
			
		||||
		"    --args-linux          Pass linux kernel style options\n"
 | 
			
		||||
		"    --args-elf            Pass elf boot notes\n"
 | 
			
		||||
		"    --args-none           Jump directly from the kernel\n"
 | 
			
		||||
		);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_x86_64_load(int argc, char **argv, const char *buf, off_t len, 
 | 
			
		||||
	struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_ehdr ehdr;
 | 
			
		||||
	const char *command_line;
 | 
			
		||||
	int command_line_len;
 | 
			
		||||
	const char *ramdisk;
 | 
			
		||||
	unsigned long entry, max_addr;
 | 
			
		||||
	int arg_style;
 | 
			
		||||
#define ARG_STYLE_ELF   0
 | 
			
		||||
#define ARG_STYLE_LINUX 1
 | 
			
		||||
#define ARG_STYLE_NONE  2
 | 
			
		||||
	int opt;
 | 
			
		||||
#define OPT_APPEND	(OPT_ARCH_MAX+0)
 | 
			
		||||
#define OPT_RAMDISK	(OPT_ARCH_MAX+1)
 | 
			
		||||
#define OPT_ARGS_ELF    (OPT_ARCH_MAX+2)
 | 
			
		||||
#define OPT_ARGS_LINUX  (OPT_ARCH_MAX+3)
 | 
			
		||||
#define OPT_ARGS_NONE   (OPT_ARCH_MAX+4)
 | 
			
		||||
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ "command-line",	1, NULL, OPT_APPEND },
 | 
			
		||||
		{ "append",		1, NULL, OPT_APPEND },
 | 
			
		||||
		{ "initrd",		1, NULL, OPT_RAMDISK },
 | 
			
		||||
		{ "ramdisk",		1, NULL, OPT_RAMDISK },
 | 
			
		||||
		{ "args-elf",		0, NULL, OPT_ARGS_ELF },
 | 
			
		||||
		{ "args-linux",		0, NULL, OPT_ARGS_LINUX },
 | 
			
		||||
		{ "args-none",		0, NULL, OPT_ARGS_NONE },
 | 
			
		||||
		{ 0, 			0, NULL, 0 },
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR "";
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Parse the command line arguments
 | 
			
		||||
	 */
 | 
			
		||||
	arg_style = ARG_STYLE_ELF;
 | 
			
		||||
	command_line = 0;
 | 
			
		||||
	ramdisk = 0;
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			/* Ignore core options */
 | 
			
		||||
			if (opt < OPT_ARCH_MAX) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			fprintf(stderr, "Unknown option: opt: %d\n", opt);
 | 
			
		||||
		case '?':
 | 
			
		||||
			usage();
 | 
			
		||||
			return -1;
 | 
			
		||||
		case OPT_APPEND:
 | 
			
		||||
			command_line = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_RAMDISK:
 | 
			
		||||
			ramdisk = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_ARGS_ELF: 
 | 
			
		||||
			arg_style = ARG_STYLE_ELF;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_ARGS_LINUX:
 | 
			
		||||
			arg_style = ARG_STYLE_LINUX;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_ARGS_NONE:
 | 
			
		||||
#ifdef __x86_64___
 | 
			
		||||
			arg_style = ARG_STYLE_NONE;
 | 
			
		||||
#else
 | 
			
		||||
			die("--args-none only works on arch x86_64\n");
 | 
			
		||||
#endif
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	command_line_len = 0;
 | 
			
		||||
	if (command_line) {
 | 
			
		||||
		command_line_len = strlen(command_line) +1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load the ELF executable */
 | 
			
		||||
	elf_exec_build_load(info, &ehdr, buf, len);
 | 
			
		||||
 | 
			
		||||
	entry = ehdr.e_entry;
 | 
			
		||||
	max_addr = elf_max_addr(&ehdr);
 | 
			
		||||
 | 
			
		||||
	/* Do we want arguments? */
 | 
			
		||||
	if (arg_style != ARG_STYLE_NONE) {
 | 
			
		||||
		/* Load the setup code */
 | 
			
		||||
		elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size,
 | 
			
		||||
			0, ULONG_MAX, 1);
 | 
			
		||||
	}
 | 
			
		||||
	if (arg_style == ARG_STYLE_NONE) {
 | 
			
		||||
		info->entry = (void *)entry;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	else if (arg_style == ARG_STYLE_ELF) {
 | 
			
		||||
		unsigned long note_base;
 | 
			
		||||
		struct entry64_regs regs;
 | 
			
		||||
 | 
			
		||||
		/* Setup the ELF boot notes */
 | 
			
		||||
		note_base = elf_boot_notes(info, max_addr,
 | 
			
		||||
			command_line, command_line_len);
 | 
			
		||||
 | 
			
		||||
		/* Initialize the registers */
 | 
			
		||||
		elf_rel_get_symbol(&info->rhdr, "entry64_regs", ®s, sizeof(regs));
 | 
			
		||||
		regs.rdi = note_base;   /* The notes (arg1) */
 | 
			
		||||
		regs.rip = entry;       /* The entry point */
 | 
			
		||||
		regs.rsp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry64_regs", ®s, sizeof(regs));
 | 
			
		||||
 | 
			
		||||
		if (ramdisk) {
 | 
			
		||||
			die("Ramdisks not supported with generic elf arguments");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (arg_style == ARG_STYLE_LINUX) {
 | 
			
		||||
		struct x86_linux_faked_param_header *hdr;
 | 
			
		||||
		unsigned long param_base;
 | 
			
		||||
		const unsigned char *ramdisk_buf;
 | 
			
		||||
		off_t ramdisk_length;
 | 
			
		||||
		struct entry64_regs regs;
 | 
			
		||||
 | 
			
		||||
		/* Get the linux parameter header */
 | 
			
		||||
		hdr = xmalloc(sizeof(*hdr));
 | 
			
		||||
		param_base = add_buffer(info, hdr, sizeof(*hdr), sizeof(*hdr),
 | 
			
		||||
			16, 0, max_addr, 1);
 | 
			
		||||
 | 
			
		||||
		/* Initialize the parameter header */
 | 
			
		||||
		memset(hdr, 0, sizeof(*hdr));
 | 
			
		||||
		init_linux_parameters(&hdr->hdr);
 | 
			
		||||
 | 
			
		||||
		/* Add a ramdisk to the current image */
 | 
			
		||||
		ramdisk_buf = 0;
 | 
			
		||||
		ramdisk_length = 0;
 | 
			
		||||
		if (ramdisk) {
 | 
			
		||||
			unsigned char *ramdisk_buf;
 | 
			
		||||
			ramdisk_buf = slurp_file(ramdisk, &ramdisk_length);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Tell the kernel what is going on */
 | 
			
		||||
		setup_linux_bootloader_parameters(info, &hdr->hdr, param_base, 
 | 
			
		||||
			offsetof(struct x86_linux_faked_param_header, command_line),
 | 
			
		||||
			command_line, command_line_len,
 | 
			
		||||
			ramdisk_buf, ramdisk_length);
 | 
			
		||||
 | 
			
		||||
		/* Fill in the information bios calls would usually provide */
 | 
			
		||||
		setup_linux_system_parameters(&hdr->hdr);
 | 
			
		||||
 | 
			
		||||
		/* Initialize the registers */
 | 
			
		||||
		elf_rel_get_symbol(&info->rhdr, "entry64_regs", ®s, sizeof(regs));
 | 
			
		||||
		regs.rbx = 0;		/* Bootstrap processor */
 | 
			
		||||
		regs.rsi = param_base;	/* Pointer to the parameters */
 | 
			
		||||
		regs.rip = entry;	/* the entry point */
 | 
			
		||||
		regs.rsp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */
 | 
			
		||||
		elf_rel_set_symbol(&info->rhdr, "entry64_regs", ®s, sizeof(regs));
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Unknown argument style\n");
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										247
									
								
								kexec/arch/x86_64/kexec-x86_64.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										247
									
								
								kexec/arch/x86_64/kexec-x86_64.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,247 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#include <sys/utsname.h>
 | 
			
		||||
#include "../../kexec.h"
 | 
			
		||||
#include "../../kexec-elf.h"
 | 
			
		||||
#include "../../kexec-syscall.h"
 | 
			
		||||
#include "kexec-x86_64.h"
 | 
			
		||||
#include <arch/options.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_MEMORY_RANGES 64
 | 
			
		||||
#define MAX_LINE 160
 | 
			
		||||
static struct memory_range memory_range[MAX_MEMORY_RANGES];
 | 
			
		||||
 | 
			
		||||
/* Return a sorted list of memory ranges. */
 | 
			
		||||
int get_memory_ranges(struct memory_range **range, int *ranges)
 | 
			
		||||
{
 | 
			
		||||
	const char iomem[]= "/proc/iomem";
 | 
			
		||||
	int memory_ranges = 0;
 | 
			
		||||
	char line[MAX_LINE];
 | 
			
		||||
	FILE *fp;
 | 
			
		||||
	fp = fopen(iomem, "r");
 | 
			
		||||
	if (!fp) {
 | 
			
		||||
		fprintf(stderr, "Cannot open %s: %s\n", 
 | 
			
		||||
			iomem, strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	while(fgets(line, sizeof(line), fp) != 0) {
 | 
			
		||||
		unsigned long long start, end;
 | 
			
		||||
		char *str;
 | 
			
		||||
		int type;
 | 
			
		||||
		int consumed;
 | 
			
		||||
		int count;
 | 
			
		||||
		if (memory_ranges >= MAX_MEMORY_RANGES)
 | 
			
		||||
			break;
 | 
			
		||||
		count = sscanf(line, "%Lx-%Lx : %n",
 | 
			
		||||
			&start, &end, &consumed);
 | 
			
		||||
		if (count != 2) 
 | 
			
		||||
			continue;
 | 
			
		||||
		str = line + consumed;
 | 
			
		||||
		end = end + 1;
 | 
			
		||||
#if 0
 | 
			
		||||
		printf("%016Lx-%016Lx : %s",
 | 
			
		||||
			start, end, str);
 | 
			
		||||
#endif
 | 
			
		||||
		if (memcmp(str, "System RAM\n", 11) == 0) {
 | 
			
		||||
			type = RANGE_RAM;
 | 
			
		||||
		} 
 | 
			
		||||
		else if (memcmp(str, "reserved\n", 9) == 0) {
 | 
			
		||||
			type = RANGE_RESERVED;
 | 
			
		||||
		}
 | 
			
		||||
		else if (memcmp(str, "ACPI Tables\n", 12) == 0) {
 | 
			
		||||
			type = RANGE_ACPI;
 | 
			
		||||
		}
 | 
			
		||||
		else if (memcmp(str, "ACPI Non-volatile Storage\n", 26) == 0) {
 | 
			
		||||
			type = RANGE_ACPI_NVS;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		/* Don't report the interrupt table as ram */
 | 
			
		||||
		if (type == RANGE_RAM && (start < 0x100)) {
 | 
			
		||||
			start = 0x100;
 | 
			
		||||
		}
 | 
			
		||||
		memory_range[memory_ranges].start = start;
 | 
			
		||||
		memory_range[memory_ranges].end = end;
 | 
			
		||||
		memory_range[memory_ranges].type = type;
 | 
			
		||||
#if 0
 | 
			
		||||
		printf("%016Lx-%016Lx : %x\n",
 | 
			
		||||
			start, end, type);
 | 
			
		||||
#endif
 | 
			
		||||
		memory_ranges++;
 | 
			
		||||
	}
 | 
			
		||||
	fclose(fp);
 | 
			
		||||
	*range = memory_range;
 | 
			
		||||
	*ranges = memory_ranges;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct file_type file_type[] = {
 | 
			
		||||
	{ "elf-x86_64", elf_x86_64_probe, elf_x86_64_load, elf_x86_64_usage },
 | 
			
		||||
	{ "multiboot-x86", multiboot_x86_probe, multiboot_x86_load, 
 | 
			
		||||
	  multiboot_x86_usage },
 | 
			
		||||
	{ "elf-x86", elf_x86_probe, elf_x86_load, elf_x86_usage },
 | 
			
		||||
	{ "bzImage", bzImage_probe, bzImage_load, bzImage_usage },
 | 
			
		||||
	{ "beoboot-x86", beoboot_probe, beoboot_load, beoboot_usage },
 | 
			
		||||
	{ "nbi-x86", nbi_probe, nbi_load, nbi_usage },
 | 
			
		||||
};
 | 
			
		||||
int file_types = sizeof(file_type)/sizeof(file_type[0]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void arch_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf(
 | 
			
		||||
		"     --reset-vga               Attempt to reset a standard vga device\n"
 | 
			
		||||
		"     --serial=<port>           Specify the serial port for debug output\n"
 | 
			
		||||
		"     --serial-baud=<buad_rate> Specify the serial port baud rate\n"
 | 
			
		||||
		"     --console-vga             Enable the vga console\n"
 | 
			
		||||
		"     --console-serial          Enable the serial console\n"
 | 
			
		||||
		);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
	uint8_t  reset_vga;
 | 
			
		||||
	uint16_t serial_base;
 | 
			
		||||
	uint32_t serial_baud;
 | 
			
		||||
	uint8_t  console_vga;
 | 
			
		||||
	uint8_t  console_serial;
 | 
			
		||||
} arch_options = {
 | 
			
		||||
	.reset_vga   = 0,
 | 
			
		||||
	.serial_base = 0x3f8,
 | 
			
		||||
	.serial_baud = 0,
 | 
			
		||||
	.console_vga = 0,
 | 
			
		||||
	.console_serial = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int arch_process_options(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_ARCH_OPTIONS
 | 
			
		||||
		{ 0, 			0, NULL, 0 },
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_ARCH_OPT_STR;
 | 
			
		||||
	int opt;
 | 
			
		||||
	unsigned long value;
 | 
			
		||||
	char *end;
 | 
			
		||||
 | 
			
		||||
	opterr = 0; /* Don't complain about unrecognized options here */
 | 
			
		||||
	while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_RESET_VGA:
 | 
			
		||||
			arch_options.reset_vga = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_CONSOLE_VGA:
 | 
			
		||||
			arch_options.console_vga = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_CONSOLE_SERIAL:
 | 
			
		||||
			arch_options.console_serial = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_SERIAL:
 | 
			
		||||
			value = ULONG_MAX;
 | 
			
		||||
			if (strcmp(optarg, "ttyS0") == 0) {
 | 
			
		||||
				value = 0x3f8;
 | 
			
		||||
			}
 | 
			
		||||
			else if (strcmp(optarg, "ttyS1") == 0) {
 | 
			
		||||
				value = 0x2f8;
 | 
			
		||||
			}
 | 
			
		||||
			else if (strncmp(optarg, "0x", 2) == 0) {
 | 
			
		||||
				value = strtoul(optarg +2, &end, 16);
 | 
			
		||||
				if (*end != '\0') {
 | 
			
		||||
					value = ULONG_MAX;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if (value >= 65536) {
 | 
			
		||||
				fprintf(stderr, "Bad serial port base '%s'\n", 
 | 
			
		||||
					optarg);
 | 
			
		||||
				usage();
 | 
			
		||||
				return -1;
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			arch_options.serial_base = value;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_SERIAL_BAUD:
 | 
			
		||||
			value = strtoul(optarg, &end, 0);
 | 
			
		||||
			if ((value > 115200) || ((115200 %value) != 0) || 
 | 
			
		||||
				(value < 9600) || (*end)) 
 | 
			
		||||
			{
 | 
			
		||||
				fprintf(stderr, "Bad serial port baud rate '%s'\n",
 | 
			
		||||
					optarg);
 | 
			
		||||
				usage();
 | 
			
		||||
				return -1;
 | 
			
		||||
				
 | 
			
		||||
			}
 | 
			
		||||
			arch_options.serial_baud = value;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Reset getopt for the next pass; called in other source modules */
 | 
			
		||||
	opterr = 1;
 | 
			
		||||
	optind = 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	struct utsname utsname;
 | 
			
		||||
	result = uname(&utsname);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		fprintf(stderr, "uname failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(utsname.machine, "x86_64") == 0)
 | 
			
		||||
	{
 | 
			
		||||
		/* For compatibility with older patches 
 | 
			
		||||
		 * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_X86_64 here.
 | 
			
		||||
		 */
 | 
			
		||||
		*flags |= KEXEC_ARCH_DEFAULT;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		fprintf(stderr, "Unsupported machine type: %s\n",
 | 
			
		||||
			utsname.machine);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arch_update_purgatory(struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "reset_vga",
 | 
			
		||||
		&arch_options.reset_vga, sizeof(arch_options.reset_vga));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "serial_base", 
 | 
			
		||||
		&arch_options.serial_base, sizeof(arch_options.serial_base));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "serial_baud", 
 | 
			
		||||
		&arch_options.serial_baud, sizeof(arch_options.serial_baud));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "console_vga", 
 | 
			
		||||
		&arch_options.console_vga, sizeof(arch_options.console_vga));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "console_serial", 
 | 
			
		||||
		&arch_options.console_serial, sizeof(arch_options.console_serial));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										31
									
								
								kexec/arch/x86_64/kexec-x86_64.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								kexec/arch/x86_64/kexec-x86_64.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
#ifndef KEXEC_X86_64_H
 | 
			
		||||
#define KEXEC_X86_64_H
 | 
			
		||||
 | 
			
		||||
#include "../i386/kexec-x86.h"
 | 
			
		||||
 | 
			
		||||
struct entry64_regs {
 | 
			
		||||
	uint64_t rax;
 | 
			
		||||
	uint64_t rbx;
 | 
			
		||||
	uint64_t rcx;
 | 
			
		||||
	uint64_t rdx;
 | 
			
		||||
	uint64_t rsi;
 | 
			
		||||
	uint64_t rdi;
 | 
			
		||||
	uint64_t rsp;
 | 
			
		||||
	uint64_t rbp;
 | 
			
		||||
	uint64_t r8;
 | 
			
		||||
	uint64_t r9;
 | 
			
		||||
	uint64_t r10;
 | 
			
		||||
	uint64_t r11;
 | 
			
		||||
	uint64_t r12;
 | 
			
		||||
	uint64_t r13;
 | 
			
		||||
	uint64_t r14;
 | 
			
		||||
	uint64_t r15;
 | 
			
		||||
	uint64_t rip;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int elf_x86_64_probe(const char *buf, off_t len);
 | 
			
		||||
int elf_x86_64_load(int argc, char **argv, const char *buf, off_t len,
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
void elf_x86_64_usage(void);
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_X86_64_H */
 | 
			
		||||
							
								
								
									
										74
									
								
								kexec/ifdown.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								kexec/ifdown.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
 * ifdown.c	Find all network interfaces on the system and
 | 
			
		||||
 *		shut them down.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
char *v_ifdown = "@(#)ifdown.c  1.11  02-Jun-1998  miquels@cistron.nl";
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <sys/ioctl.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#include <sys/errno.h>
 | 
			
		||||
 | 
			
		||||
#include <net/if.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
 | 
			
		||||
#define MAX_IFS	64
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	First, we find all shaper devices and down them. Then we
 | 
			
		||||
 *	down all real interfaces. This is because the comment in the
 | 
			
		||||
 *	shaper driver says "if you down the shaper device before the
 | 
			
		||||
 *	attached inerface your computer will follow".
 | 
			
		||||
 */
 | 
			
		||||
int ifdown(void)
 | 
			
		||||
{
 | 
			
		||||
	struct ifreq ifr[MAX_IFS];
 | 
			
		||||
	struct ifconf ifc;
 | 
			
		||||
	int i, fd;
 | 
			
		||||
	int numif;
 | 
			
		||||
	int shaper;
 | 
			
		||||
 | 
			
		||||
	if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 | 
			
		||||
		fprintf(stderr, "ifdown: ");
 | 
			
		||||
		perror("socket");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	ifc.ifc_len = sizeof(ifr);
 | 
			
		||||
	ifc.ifc_req = ifr;
 | 
			
		||||
 | 
			
		||||
	if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
 | 
			
		||||
		fprintf(stderr, "ifdown: ");
 | 
			
		||||
		perror("SIOCGIFCONF");
 | 
			
		||||
		close(fd);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	numif = ifc.ifc_len / sizeof(struct ifreq);
 | 
			
		||||
 | 
			
		||||
	for (shaper = 1; shaper >= 0; shaper--) {
 | 
			
		||||
		for (i = 0; i < numif; i++) {
 | 
			
		||||
 | 
			
		||||
			if ((strncmp(ifr[i].ifr_name, "shaper", 6) == 0)
 | 
			
		||||
			    != shaper) continue;
 | 
			
		||||
 | 
			
		||||
			if (strcmp(ifr[i].ifr_name, "lo") == 0)
 | 
			
		||||
				continue;
 | 
			
		||||
			if (strchr(ifr[i].ifr_name, ':') != NULL)
 | 
			
		||||
				continue;
 | 
			
		||||
			ifr[i].ifr_flags &= ~(IFF_UP);
 | 
			
		||||
			if (ioctl(fd, SIOCSIFFLAGS, &ifr[i]) < 0) {
 | 
			
		||||
				fprintf(stderr, "ifdown: shutdown ");
 | 
			
		||||
				perror(ifr[i].ifr_name);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	close(fd);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										95
									
								
								kexec/kexec-elf-boot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								kexec/kexec-elf-boot.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,95 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <elf.h>
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include <ip_checksum.h>
 | 
			
		||||
#include <x86/x86-linux.h>
 | 
			
		||||
#include "kexec.h"
 | 
			
		||||
#include "kexec-elf.h"
 | 
			
		||||
#include "kexec-elf-boot.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define UPSZ(X) ((sizeof(X) + 3) &~3)
 | 
			
		||||
 | 
			
		||||
static struct boot_notes {
 | 
			
		||||
	Elf_Bhdr hdr;
 | 
			
		||||
	Elf_Nhdr bl_hdr;
 | 
			
		||||
	unsigned char bl_desc[UPSZ(BOOTLOADER)];
 | 
			
		||||
	Elf_Nhdr blv_hdr;
 | 
			
		||||
	unsigned char blv_desc[UPSZ(BOOTLOADER_VERSION)];
 | 
			
		||||
	Elf_Nhdr cmd_hdr;
 | 
			
		||||
	unsigned char command_line[0];
 | 
			
		||||
} boot_notes = {
 | 
			
		||||
	.hdr = {
 | 
			
		||||
		.b_signature = ELF_BOOT_MAGIC,
 | 
			
		||||
		.b_size = sizeof(boot_notes),
 | 
			
		||||
		.b_checksum = 0,
 | 
			
		||||
		.b_records = 3,
 | 
			
		||||
	},
 | 
			
		||||
	.bl_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = sizeof(BOOTLOADER),
 | 
			
		||||
		.n_type = EBN_BOOTLOADER_NAME,
 | 
			
		||||
	},
 | 
			
		||||
	.bl_desc = BOOTLOADER,
 | 
			
		||||
	.blv_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = sizeof(BOOTLOADER_VERSION),
 | 
			
		||||
		.n_type = EBN_BOOTLOADER_VERSION,
 | 
			
		||||
	},
 | 
			
		||||
	.blv_desc = BOOTLOADER_VERSION,
 | 
			
		||||
	.cmd_hdr = {
 | 
			
		||||
		.n_namesz = 0,
 | 
			
		||||
		.n_descsz = 0,
 | 
			
		||||
		.n_type = EBN_COMMAND_LINE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline unsigned long align(unsigned long val, unsigned long align)
 | 
			
		||||
{
 | 
			
		||||
	return (val + align - 1) & ~(align - 1);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned long elf_boot_notes(
 | 
			
		||||
	struct kexec_info *info, unsigned long max_addr,
 | 
			
		||||
	const unsigned char *cmdline, int cmdline_len)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long note_bytes;
 | 
			
		||||
	unsigned long note_base;
 | 
			
		||||
	struct boot_notes *notes;
 | 
			
		||||
	note_bytes = sizeof(*notes) + align(cmdline_len, 4);
 | 
			
		||||
	notes = xmalloc(note_bytes);
 | 
			
		||||
	memcpy(notes, &boot_notes, sizeof(boot_notes));
 | 
			
		||||
	memcpy(notes->command_line, cmdline, cmdline_len);
 | 
			
		||||
	notes->hdr.b_size = note_bytes;
 | 
			
		||||
	notes->cmd_hdr.n_descsz = cmdline_len;
 | 
			
		||||
	notes->hdr.b_checksum = compute_ip_checksum(notes, note_bytes);
 | 
			
		||||
 | 
			
		||||
	note_base = add_buffer(info, notes, note_bytes, note_bytes, 
 | 
			
		||||
		4, 0, max_addr, 1);
 | 
			
		||||
 | 
			
		||||
	return note_base;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								kexec/kexec-elf-boot.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								kexec/kexec-elf-boot.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
#ifndef KEXEC_ELF_BOOT_H
 | 
			
		||||
#define KEXEC_ELF_BOOT_H
 | 
			
		||||
 | 
			
		||||
unsigned long elf_boot_notes(
 | 
			
		||||
	struct kexec_info *info, unsigned long max_addr, 
 | 
			
		||||
	const unsigned char *cmdline, int cmdline_len);
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_ELF_BOOT_H */
 | 
			
		||||
							
								
								
									
										149
									
								
								kexec/kexec-elf-exec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								kexec/kexec-elf-exec.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,149 @@
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "elf.h"
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include "kexec.h"
 | 
			
		||||
#include "kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_phdr *phdr, *end_phdr;
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_elf_info(buf, len, ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN)) {
 | 
			
		||||
		/* not an ELF executable */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not ELF type ET_EXEC or ET_DYN\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (!ehdr->e_phdr) {
 | 
			
		||||
		/* No program header */
 | 
			
		||||
		fprintf(stderr, "No ELF program header\n");
 | 
			
		||||
		return -1; 
 | 
			
		||||
	}
 | 
			
		||||
	end_phdr = &ehdr->e_phdr[ehdr->e_phnum];
 | 
			
		||||
	for(phdr = ehdr->e_phdr; phdr != end_phdr; phdr++) {
 | 
			
		||||
		/* Kexec does not support loading interpreters.
 | 
			
		||||
		 * In addition this check keeps us from attempting
 | 
			
		||||
		 * to kexec ordinay executables.
 | 
			
		||||
		 */
 | 
			
		||||
		if (phdr->p_type == PT_INTERP) {
 | 
			
		||||
			fprintf(stderr, "Requires an ELF interpreter\n");
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int elf_exec_load(const struct mem_ehdr *ehdr, struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long base;
 | 
			
		||||
	int result;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!ehdr->e_phdr) {
 | 
			
		||||
		fprintf(stderr, "No program header?\n");
 | 
			
		||||
		result = -1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If I have a dynamic executable find it's size
 | 
			
		||||
	 * and then find a location for it in memory.
 | 
			
		||||
	 */
 | 
			
		||||
	base = 0;
 | 
			
		||||
	if (ehdr->e_type == ET_DYN) {
 | 
			
		||||
		unsigned long first, last, align;
 | 
			
		||||
		first = ULONG_MAX;
 | 
			
		||||
		last  = 0;
 | 
			
		||||
		align = 0;
 | 
			
		||||
		for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
			unsigned long start, stop;
 | 
			
		||||
			struct mem_phdr *phdr;
 | 
			
		||||
			phdr = &ehdr->e_phdr[i];
 | 
			
		||||
			if ((phdr->p_type != PT_LOAD) ||
 | 
			
		||||
				(phdr->p_memsz == 0))
 | 
			
		||||
			{
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			start = phdr->p_paddr;
 | 
			
		||||
			stop  = start + phdr->p_memsz;
 | 
			
		||||
			if (start > first) {
 | 
			
		||||
				start = first;
 | 
			
		||||
			}
 | 
			
		||||
			if (last < stop) {
 | 
			
		||||
				last = stop;
 | 
			
		||||
			}
 | 
			
		||||
			if (align < phdr->p_align) {
 | 
			
		||||
				align = phdr->p_align;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		/* If I can't use the default paddr find a new
 | 
			
		||||
		 * hole for the dynamic executable.
 | 
			
		||||
		 */
 | 
			
		||||
		if (!valid_memory_range(first, last)) {
 | 
			
		||||
			unsigned long hole;
 | 
			
		||||
			hole = locate_hole(info,
 | 
			
		||||
				last - first + 1, align, 
 | 
			
		||||
				0, elf_max_addr(ehdr), 1);
 | 
			
		||||
			if (hole == ULONG_MAX) {
 | 
			
		||||
				result = -1;
 | 
			
		||||
				goto out;
 | 
			
		||||
			}
 | 
			
		||||
			/* Base is the value that when added
 | 
			
		||||
			 * to any virtual address in the file
 | 
			
		||||
			 * yields it's load virtual address.
 | 
			
		||||
			 */
 | 
			
		||||
			base = hole - first;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Read in the PT_LOAD segments */
 | 
			
		||||
	for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
		struct mem_phdr *phdr;
 | 
			
		||||
		size_t size;
 | 
			
		||||
		phdr = &ehdr->e_phdr[i];
 | 
			
		||||
		if (phdr->p_type != PT_LOAD) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		size = phdr->p_filesz;
 | 
			
		||||
		if (size > phdr->p_memsz) {
 | 
			
		||||
			size = phdr->p_memsz;
 | 
			
		||||
		}
 | 
			
		||||
		add_segment(info,
 | 
			
		||||
			phdr->p_data, size,
 | 
			
		||||
			phdr->p_paddr + base, phdr->p_memsz);
 | 
			
		||||
	}
 | 
			
		||||
	result = 0;
 | 
			
		||||
 out:
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, 
 | 
			
		||||
	const char *buf, off_t len)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	/* Parse the Elf file */
 | 
			
		||||
	result = build_elf_exec_info(buf, len, ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("ELF exec parse failed\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load the Elf data */
 | 
			
		||||
	result = elf_exec_load(ehdr, info);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("ELF exec load failed\n");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										531
									
								
								kexec/kexec-elf-rel.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								kexec/kexec-elf-rel.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,531 @@
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "elf.h"
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include "kexec.h"
 | 
			
		||||
#include "kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
static size_t elf_sym_size(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	size_t sym_size = 0;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		sym_size = sizeof(Elf32_Sym);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		sym_size = sizeof(Elf64_Sym);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Bad elf class");
 | 
			
		||||
	}
 | 
			
		||||
	return sym_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_rel_size(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	size_t rel_size = 0;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		rel_size = sizeof(Elf32_Rel);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		rel_size = sizeof(Elf64_Rel);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Bad elf class");
 | 
			
		||||
	}
 | 
			
		||||
	return rel_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t elf_rela_size(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	size_t rel_size = 0;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		rel_size = sizeof(Elf32_Rela);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		rel_size = sizeof(Elf64_Rela);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Bad elf class");
 | 
			
		||||
	}
 | 
			
		||||
	return rel_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct mem_sym elf_sym(struct mem_ehdr *ehdr, const unsigned char *ptr)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_sym sym;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		Elf32_Sym lsym;
 | 
			
		||||
		memcpy(&lsym, ptr, sizeof(lsym));
 | 
			
		||||
		sym.st_name  = elf32_to_cpu(ehdr, lsym.st_name);
 | 
			
		||||
		sym.st_value = elf32_to_cpu(ehdr, lsym.st_value);
 | 
			
		||||
		sym.st_size  = elf32_to_cpu(ehdr, lsym.st_size);
 | 
			
		||||
		sym.st_info  = lsym.st_info;
 | 
			
		||||
		sym.st_other = lsym.st_other;
 | 
			
		||||
		sym.st_shndx = elf16_to_cpu(ehdr, lsym.st_shndx);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		Elf64_Sym lsym;
 | 
			
		||||
		memcpy(&lsym, ptr, sizeof(lsym));
 | 
			
		||||
		sym.st_name  = elf32_to_cpu(ehdr, lsym.st_name);
 | 
			
		||||
		sym.st_value = elf64_to_cpu(ehdr, lsym.st_value);
 | 
			
		||||
		sym.st_size  = elf64_to_cpu(ehdr, lsym.st_size);
 | 
			
		||||
		sym.st_info  = lsym.st_info;
 | 
			
		||||
		sym.st_other = lsym.st_other;
 | 
			
		||||
		sym.st_shndx = elf16_to_cpu(ehdr, lsym.st_shndx);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Bad elf class");
 | 
			
		||||
	}
 | 
			
		||||
	return sym;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct mem_rela elf_rel(struct mem_ehdr *ehdr, const unsigned char *ptr)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_rela rela;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		Elf32_Rel lrel;
 | 
			
		||||
		memcpy(&lrel, ptr, sizeof(lrel));
 | 
			
		||||
		rela.r_offset = elf32_to_cpu(ehdr, lrel.r_offset);
 | 
			
		||||
		rela.r_sym    = ELF32_R_SYM(elf32_to_cpu(ehdr, lrel.r_info));
 | 
			
		||||
		rela.r_type   = ELF32_R_TYPE(elf32_to_cpu(ehdr, lrel.r_info));
 | 
			
		||||
		rela.r_addend = 0;
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		Elf64_Rel lrel;
 | 
			
		||||
		memcpy(&lrel, ptr, sizeof(lrel));
 | 
			
		||||
		rela.r_offset = elf64_to_cpu(ehdr, lrel.r_offset);
 | 
			
		||||
		rela.r_sym    = ELF64_R_SYM(elf64_to_cpu(ehdr, lrel.r_info));
 | 
			
		||||
		rela.r_type   = ELF64_R_TYPE(elf64_to_cpu(ehdr, lrel.r_info));
 | 
			
		||||
		rela.r_addend = 0;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Bad elf class");
 | 
			
		||||
	}
 | 
			
		||||
	return rela;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct mem_rela elf_rela(struct mem_ehdr *ehdr, const unsigned char *ptr)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_rela rela;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		Elf32_Rela lrela;
 | 
			
		||||
		memcpy(&lrela, ptr, sizeof(lrela));
 | 
			
		||||
		rela.r_offset = elf32_to_cpu(ehdr, lrela.r_offset);
 | 
			
		||||
		rela.r_sym    = ELF32_R_SYM(elf32_to_cpu(ehdr, lrela.r_info));
 | 
			
		||||
		rela.r_type   = ELF32_R_TYPE(elf32_to_cpu(ehdr, lrela.r_info));
 | 
			
		||||
		rela.r_addend = elf32_to_cpu(ehdr, lrela.r_addend);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		Elf64_Rela lrela;
 | 
			
		||||
		memcpy(&lrela, ptr, sizeof(lrela));
 | 
			
		||||
		rela.r_offset = elf64_to_cpu(ehdr, lrela.r_offset);
 | 
			
		||||
		rela.r_sym    = ELF64_R_SYM(elf64_to_cpu(ehdr, lrela.r_info));
 | 
			
		||||
		rela.r_type   = ELF64_R_TYPE(elf64_to_cpu(ehdr, lrela.r_info));
 | 
			
		||||
		rela.r_addend = elf64_to_cpu(ehdr, lrela.r_addend);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		die("Bad elf class");
 | 
			
		||||
	}
 | 
			
		||||
	return rela;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_elf_info(buf, len, ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	if (ehdr->e_type != ET_REL) {
 | 
			
		||||
		/* not an ELF relocate object */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not ELF type ET_REL\n");
 | 
			
		||||
			fprintf(stderr, "ELF Type: %x\n", ehdr->e_type);
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (!ehdr->e_shdr) {
 | 
			
		||||
		/* No section headers */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "No ELF section headers\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1; 
 | 
			
		||||
	}
 | 
			
		||||
	if (!machine_verify_elf_rel(ehdr)) {
 | 
			
		||||
		/* It does not meant the native architecture constraints */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF architecture constraint failure\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
 | 
			
		||||
	unsigned long min, unsigned long max, int end)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_shdr *shdr, *shdr_end, *entry_shdr;
 | 
			
		||||
	unsigned long entry;
 | 
			
		||||
	int result;
 | 
			
		||||
	unsigned char *buf;
 | 
			
		||||
	unsigned long buf_align, bufsz, bss_align, bsssz, bss_pad;
 | 
			
		||||
	unsigned long buf_addr, data_addr, bss_addr;
 | 
			
		||||
 | 
			
		||||
	if (max > elf_max_addr(ehdr)) {
 | 
			
		||||
		max = elf_max_addr(ehdr);
 | 
			
		||||
	}
 | 
			
		||||
	if (!ehdr->e_shdr) {
 | 
			
		||||
		fprintf(stderr, "No section header?\n");
 | 
			
		||||
		result = -1;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	shdr_end = &ehdr->e_shdr[ehdr->e_shnum];
 | 
			
		||||
 | 
			
		||||
	/* Find which section entry is in */
 | 
			
		||||
	entry_shdr = NULL;
 | 
			
		||||
	entry = ehdr->e_entry;
 | 
			
		||||
	for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
 | 
			
		||||
		if (!(shdr->sh_flags & SHF_ALLOC)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (!(shdr->sh_flags & SHF_EXECINSTR)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		/* Make entry section relative */
 | 
			
		||||
		if ((shdr->sh_addr <= ehdr->e_entry) &&
 | 
			
		||||
			((shdr->sh_addr + shdr->sh_size) > ehdr->e_entry)) {
 | 
			
		||||
			entry_shdr = shdr;
 | 
			
		||||
			entry -= shdr->sh_addr;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Find the memory footprint of the relocatable object */
 | 
			
		||||
	buf_align = 1;
 | 
			
		||||
	bss_align = 1;
 | 
			
		||||
	bufsz = 0;
 | 
			
		||||
	bsssz = 0;
 | 
			
		||||
	for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
 | 
			
		||||
		if (!(shdr->sh_flags & SHF_ALLOC)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (shdr->sh_type != SHT_NOBITS) {
 | 
			
		||||
			unsigned long align;
 | 
			
		||||
			align = shdr->sh_addralign;
 | 
			
		||||
			/* See if I need more alignment */
 | 
			
		||||
			if (buf_align < align) {
 | 
			
		||||
				buf_align = align;
 | 
			
		||||
			}
 | 
			
		||||
			/* Now align bufsz */
 | 
			
		||||
			bufsz = (bufsz + (align - 1)) & ~(align - 1);
 | 
			
		||||
			/* And now add our buffer */
 | 
			
		||||
			bufsz += shdr->sh_size;
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			unsigned long align;
 | 
			
		||||
			align = shdr->sh_addralign;
 | 
			
		||||
			/* See if I need more alignment */
 | 
			
		||||
			if (bss_align < align) {
 | 
			
		||||
				bss_align = align;
 | 
			
		||||
			}
 | 
			
		||||
			/* Now align bsssz */
 | 
			
		||||
			bsssz = (bsssz + (align - 1)) & ~(align -1);
 | 
			
		||||
			/* And now add our buffer */
 | 
			
		||||
			bsssz += shdr->sh_size;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (buf_align < bss_align) {
 | 
			
		||||
		buf_align = bss_align;
 | 
			
		||||
	}
 | 
			
		||||
	bss_pad = 0;
 | 
			
		||||
	if (bufsz & (bss_align - 1)) {
 | 
			
		||||
		bss_pad = bss_align - (bufsz & (bss_align - 1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Allocate where we will put the relocated object */
 | 
			
		||||
	buf = xmalloc(bufsz);
 | 
			
		||||
	buf_addr = add_buffer(info, buf, bufsz, bufsz + bss_pad + bsssz, 
 | 
			
		||||
		buf_align, min, max, end);
 | 
			
		||||
	ehdr->rel_addr = buf_addr;
 | 
			
		||||
	ehdr->rel_size = bufsz + bss_pad + bsssz;
 | 
			
		||||
 | 
			
		||||
	/* Walk through and find an address for each SHF_ALLOC section */
 | 
			
		||||
	data_addr = buf_addr;
 | 
			
		||||
	bss_addr  = buf_addr + bufsz + bss_pad;
 | 
			
		||||
	for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
 | 
			
		||||
		unsigned long align;
 | 
			
		||||
		if (!(shdr->sh_flags & SHF_ALLOC)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		align = shdr->sh_addralign;
 | 
			
		||||
		if (shdr->sh_type != SHT_NOBITS) {
 | 
			
		||||
			unsigned long off;
 | 
			
		||||
			/* Adjust the address */
 | 
			
		||||
			data_addr = (data_addr + (align - 1)) & ~(align -1);
 | 
			
		||||
			
 | 
			
		||||
			/* Update the section */
 | 
			
		||||
			off = data_addr - buf_addr;
 | 
			
		||||
			memcpy(buf + off, shdr->sh_data, shdr->sh_size);
 | 
			
		||||
			shdr->sh_addr = data_addr;
 | 
			
		||||
			shdr->sh_data = buf + off;
 | 
			
		||||
 | 
			
		||||
			/* Advance to the next address */
 | 
			
		||||
			data_addr += shdr->sh_size;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* Adjust the address */
 | 
			
		||||
			bss_addr = (bss_addr + (align - 1)) & ~(align -1);
 | 
			
		||||
 | 
			
		||||
			/* Update the section */
 | 
			
		||||
			shdr->sh_addr = bss_addr;
 | 
			
		||||
 | 
			
		||||
			/* Advance to the next address */
 | 
			
		||||
			bss_addr += shdr->sh_size;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Compute the relocated value for entry, and load it */
 | 
			
		||||
	if (entry_shdr) {
 | 
			
		||||
		entry += entry_shdr->sh_addr;
 | 
			
		||||
		ehdr->e_entry = entry;
 | 
			
		||||
	}
 | 
			
		||||
	info->entry = (void *)entry;
 | 
			
		||||
 | 
			
		||||
	/* Now that the load address is known apply relocations */
 | 
			
		||||
	for(shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
 | 
			
		||||
		struct mem_shdr *section, *symtab;
 | 
			
		||||
		const unsigned char *strtab;
 | 
			
		||||
		size_t rel_size;
 | 
			
		||||
		const unsigned char *ptr, *rel_end;
 | 
			
		||||
		if ((shdr->sh_type != SHT_RELA) && (shdr->sh_type != SHT_REL)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if ((shdr->sh_info > ehdr->e_shnum) ||
 | 
			
		||||
			(shdr->sh_link > ehdr->e_shnum)) 
 | 
			
		||||
		{
 | 
			
		||||
			die("Invalid section number\n");
 | 
			
		||||
		}
 | 
			
		||||
		section = &ehdr->e_shdr[shdr->sh_info];
 | 
			
		||||
		symtab = &ehdr->e_shdr[shdr->sh_link];
 | 
			
		||||
 | 
			
		||||
		if (!(section->sh_flags & SHF_ALLOC)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (symtab->sh_link > ehdr->e_shnum) {
 | 
			
		||||
			/* Invalid section number? */
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		strtab = ehdr->e_shdr[symtab->sh_link].sh_data;
 | 
			
		||||
 | 
			
		||||
		rel_size = 0;
 | 
			
		||||
		if (shdr->sh_type == SHT_REL) {
 | 
			
		||||
			rel_size = elf_rel_size(ehdr);
 | 
			
		||||
		}
 | 
			
		||||
		else if (shdr->sh_type == SHT_RELA) {
 | 
			
		||||
			rel_size = elf_rela_size(ehdr);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			die("Cannot find elf rel size\n");
 | 
			
		||||
		}
 | 
			
		||||
		rel_end = shdr->sh_data + shdr->sh_size;
 | 
			
		||||
		for(ptr = shdr->sh_data; ptr < rel_end; ptr += rel_size) {
 | 
			
		||||
			struct mem_rela rel;
 | 
			
		||||
			struct mem_sym sym;
 | 
			
		||||
			const void *location;
 | 
			
		||||
			unsigned long address, value, sec_base;
 | 
			
		||||
			if (shdr->sh_type == SHT_REL) {
 | 
			
		||||
				rel = elf_rel(ehdr, ptr);
 | 
			
		||||
			}
 | 
			
		||||
			else if (shdr->sh_type == SHT_RELA) {
 | 
			
		||||
				rel = elf_rela(ehdr, ptr);
 | 
			
		||||
			}
 | 
			
		||||
			/* the location to change */
 | 
			
		||||
			location = section->sh_data + rel.r_offset;
 | 
			
		||||
 | 
			
		||||
			/* The final address of that location */
 | 
			
		||||
			address = section->sh_addr + rel.r_offset;
 | 
			
		||||
			
 | 
			
		||||
			/* The relevant symbol */
 | 
			
		||||
			sym = elf_sym(ehdr, symtab->sh_data + (rel.r_sym * elf_sym_size(ehdr)));
 | 
			
		||||
#if 0
 | 
			
		||||
			fprintf(stderr, "sym: %10s info: %02x other: %02x shndx: %lx value: %lx size: %lx\n",
 | 
			
		||||
				strtab + sym.st_name, 
 | 
			
		||||
				sym.st_info,
 | 
			
		||||
				sym.st_other,
 | 
			
		||||
				sym.st_shndx,
 | 
			
		||||
				sym.st_value,
 | 
			
		||||
				sym.st_size);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
			if (sym.st_shndx == STN_UNDEF) {
 | 
			
		||||
				die("Undefined symbol: %s\n", 
 | 
			
		||||
					strtab + sym.st_name);
 | 
			
		||||
			}
 | 
			
		||||
			sec_base = 0;
 | 
			
		||||
			if (sym.st_shndx == SHN_COMMON) {
 | 
			
		||||
				die("symbol: '%s' in common section\n",
 | 
			
		||||
					strtab + sym.st_name);
 | 
			
		||||
			}
 | 
			
		||||
			else if (sym.st_shndx == SHN_ABS) {
 | 
			
		||||
				sec_base = 0;
 | 
			
		||||
			}
 | 
			
		||||
			else if (sym.st_shndx > ehdr->e_shnum) {
 | 
			
		||||
				die("Invalid section: %d for symbol %s\n",
 | 
			
		||||
					sym.st_shndx,
 | 
			
		||||
					strtab + sym.st_name);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				sec_base = ehdr->e_shdr[sym.st_shndx].sh_addr;
 | 
			
		||||
			}
 | 
			
		||||
#if 0
 | 
			
		||||
			fprintf(stderr, "sym: %s value: %lx addr: %lx\n",
 | 
			
		||||
				strtab + sym.st_name, value, address);
 | 
			
		||||
#endif
 | 
			
		||||
			value = sym.st_value;
 | 
			
		||||
			value += sec_base;
 | 
			
		||||
			value += rel.r_addend;
 | 
			
		||||
			machine_apply_elf_rel(ehdr, rel.r_type, 
 | 
			
		||||
				(void *)location, address, value);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	result = 0;
 | 
			
		||||
 out:
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, 
 | 
			
		||||
	const char *buf, off_t len, unsigned long min, unsigned long max,
 | 
			
		||||
	int end)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	/* Parse the Elf file */
 | 
			
		||||
	result = build_elf_rel_info(purgatory, purgatory_size, ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("ELF rel parse failed\n");
 | 
			
		||||
	}
 | 
			
		||||
	/* Load the Elf data */
 | 
			
		||||
	result = elf_rel_load(ehdr, info, min, max, end);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("ELF rel load failed\n");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int elf_rel_find_symbol(struct mem_ehdr *ehdr,
 | 
			
		||||
	const char *name, struct mem_sym *ret_sym)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_shdr *shdr, *shdr_end;
 | 
			
		||||
 | 
			
		||||
	if (!ehdr->e_shdr) {
 | 
			
		||||
		/* "No section header? */
 | 
			
		||||
		return  -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Walk through the sections and find the symbol table */
 | 
			
		||||
	shdr_end = &ehdr->e_shdr[ehdr->e_shnum];
 | 
			
		||||
	for (shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) {
 | 
			
		||||
		const char *strtab;
 | 
			
		||||
		size_t sym_size;
 | 
			
		||||
		const unsigned char *ptr, *sym_end;
 | 
			
		||||
		if (shdr->sh_type != SHT_SYMTAB) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		if (shdr->sh_link > ehdr->e_shnum) {
 | 
			
		||||
			/* Invalid strtab section number? */
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		strtab = ehdr->e_shdr[shdr->sh_link].sh_data;
 | 
			
		||||
		/* Walk through the symbol table and find the symbol */
 | 
			
		||||
		sym_size = elf_sym_size(ehdr);
 | 
			
		||||
		sym_end = shdr->sh_data + shdr->sh_size;
 | 
			
		||||
		for(ptr = shdr->sh_data; ptr < sym_end; ptr += sym_size) {
 | 
			
		||||
			struct mem_sym sym;
 | 
			
		||||
			sym = elf_sym(ehdr, ptr);
 | 
			
		||||
			if (ELF32_ST_BIND(sym.st_info) != STB_GLOBAL) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if (strcmp(strtab + sym.st_name, name) != 0) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			if ((sym.st_shndx == STN_UNDEF) || 
 | 
			
		||||
				(sym.st_shndx > ehdr->e_shnum)) 
 | 
			
		||||
			{
 | 
			
		||||
				die("Symbol: %s has Bad section index %d\n",
 | 
			
		||||
					name, sym.st_shndx);
 | 
			
		||||
			}
 | 
			
		||||
			*ret_sym = sym;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* I did not find it :( */
 | 
			
		||||
	return -1;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned long elf_rel_get_addr(struct mem_ehdr *ehdr, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_shdr *shdr;
 | 
			
		||||
	struct mem_sym sym;
 | 
			
		||||
	int result;
 | 
			
		||||
	result = elf_rel_find_symbol(ehdr, name, &sym);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("Symbol: %s not found cannot retrive it's address\n",
 | 
			
		||||
			name);
 | 
			
		||||
	}
 | 
			
		||||
	shdr = &ehdr->e_shdr[sym.st_shndx];
 | 
			
		||||
	return shdr->sh_addr + sym.st_value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_rel_set_symbol(struct mem_ehdr *ehdr,
 | 
			
		||||
	const char *name, const void *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *sym_buf;
 | 
			
		||||
	struct mem_shdr *shdr;
 | 
			
		||||
	struct mem_sym sym;
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	result = elf_rel_find_symbol(ehdr, name, &sym);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("Symbol: %s not found cannot set\n", 
 | 
			
		||||
			name);
 | 
			
		||||
	}
 | 
			
		||||
	if (sym.st_size != size) {
 | 
			
		||||
		die("Symbol: %s has size: %ld not %ld\n",
 | 
			
		||||
			name, sym.st_size, size);
 | 
			
		||||
	}
 | 
			
		||||
	shdr = &ehdr->e_shdr[sym.st_shndx];
 | 
			
		||||
	if (shdr->sh_type == SHT_NOBITS) {
 | 
			
		||||
		die("Symbol: %s is in a bss section cannot set\n", name);
 | 
			
		||||
	}
 | 
			
		||||
	sym_buf = (unsigned char *)(shdr->sh_data + sym.st_value);
 | 
			
		||||
	memcpy(sym_buf, buf, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void elf_rel_get_symbol(struct mem_ehdr *ehdr,
 | 
			
		||||
	const char *name, void *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	const unsigned char *sym_buf;
 | 
			
		||||
	struct mem_shdr *shdr;
 | 
			
		||||
	struct mem_sym sym;
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	result = elf_rel_find_symbol(ehdr, name, &sym);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("Symbol: %s not found cannot get\n");
 | 
			
		||||
	}
 | 
			
		||||
	if (sym.st_size != size) {
 | 
			
		||||
		die("Symbol: %s has size: %ld not %ld\n",
 | 
			
		||||
			name, sym.st_size, size);
 | 
			
		||||
	}
 | 
			
		||||
	shdr = &ehdr->e_shdr[sym.st_shndx];
 | 
			
		||||
	if (shdr->sh_type == SHT_NOBITS) {
 | 
			
		||||
		die("Symbol: %s is in a bss section cannot set\n", name);
 | 
			
		||||
	}
 | 
			
		||||
	sym_buf = shdr->sh_data + sym.st_value;
 | 
			
		||||
	memcpy(buf, sym_buf,size);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										760
									
								
								kexec/kexec-elf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										760
									
								
								kexec/kexec-elf.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,760 @@
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "elf.h"
 | 
			
		||||
#include <boot/elf_boot.h>
 | 
			
		||||
#include "kexec.h"
 | 
			
		||||
#include "kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
static const int probe_debug = 0;
 | 
			
		||||
 | 
			
		||||
uint16_t elf16_to_cpu(const struct mem_ehdr *ehdr, uint16_t value)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data == ELFDATA2LSB) {
 | 
			
		||||
		value = le16_to_cpu(value);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_data == ELFDATA2MSB) {
 | 
			
		||||
		value = be16_to_cpu(value);
 | 
			
		||||
	}
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t elf32_to_cpu(const struct mem_ehdr *ehdr, uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data == ELFDATA2LSB) {
 | 
			
		||||
		value = le32_to_cpu(value);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_data == ELFDATA2MSB) {
 | 
			
		||||
		value = be32_to_cpu(value);
 | 
			
		||||
	}
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t elf64_to_cpu(const struct mem_ehdr *ehdr, uint64_t value)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data == ELFDATA2LSB) {
 | 
			
		||||
		value = le64_to_cpu(value);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_data == ELFDATA2MSB) {
 | 
			
		||||
		value = be64_to_cpu(value);
 | 
			
		||||
	}
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint16_t cpu_to_elf16(const struct mem_ehdr *ehdr, uint16_t value)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data == ELFDATA2LSB) {
 | 
			
		||||
		value = cpu_to_le16(value);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_data == ELFDATA2MSB) {
 | 
			
		||||
		value = cpu_to_be16(value);
 | 
			
		||||
	}
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t cpu_to_elf32(const struct mem_ehdr *ehdr, uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data == ELFDATA2LSB) {
 | 
			
		||||
		value = cpu_to_le32(value);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_data == ELFDATA2MSB) {
 | 
			
		||||
		value = cpu_to_be32(value);
 | 
			
		||||
	}
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t cpu_to_elf64(const struct mem_ehdr *ehdr, uint64_t value)
 | 
			
		||||
{
 | 
			
		||||
	if (ehdr->ei_data == ELFDATA2LSB) {
 | 
			
		||||
		value = cpu_to_le64(value);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_data == ELFDATA2MSB) {
 | 
			
		||||
		value = cpu_to_be64(value);
 | 
			
		||||
	}
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ELF32_MAX 0xffffffff
 | 
			
		||||
#define ELF64_MAX 0xffffffffffffffff
 | 
			
		||||
#if ELF64_MAX > ULONG_MAX
 | 
			
		||||
#undef ELF64_MAX
 | 
			
		||||
#define ELF64_MAX ULONG_MAX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
unsigned long elf_max_addr(const struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long max_addr = 0;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		max_addr = ELF32_MAX;
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		max_addr = ELF64_MAX;
 | 
			
		||||
	}
 | 
			
		||||
	return max_addr;
 | 
			
		||||
}
 | 
			
		||||
static int build_mem_elf32_ehdr(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	Elf32_Ehdr lehdr;
 | 
			
		||||
	if (len < sizeof(lehdr)) {
 | 
			
		||||
		/* Buffer is to small to be an elf executable */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Buffer is to small to hold ELF header\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(&lehdr, buf, sizeof(lehdr));
 | 
			
		||||
	if (elf16_to_cpu(ehdr, lehdr.e_ehsize) != sizeof(Elf32_Ehdr)) {
 | 
			
		||||
		/* Invalid Elf header size */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Bad ELF header size\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (elf32_to_cpu(ehdr, lehdr.e_entry) > ULONG_MAX) {
 | 
			
		||||
		/* entry is to large */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF e_entry to large\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (elf32_to_cpu(ehdr, lehdr.e_phoff) > ULONG_MAX) {
 | 
			
		||||
		/* phoff is to large */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF e_phoff to large\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (elf32_to_cpu(ehdr, lehdr.e_shoff) > ULONG_MAX) {
 | 
			
		||||
		/* shoff is to large */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF e_shoff to large\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr.e_type);
 | 
			
		||||
	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr.e_machine);
 | 
			
		||||
	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr.e_version);
 | 
			
		||||
	ehdr->e_entry     = elf32_to_cpu(ehdr, lehdr.e_entry);
 | 
			
		||||
	ehdr->e_phoff     = elf32_to_cpu(ehdr, lehdr.e_phoff);
 | 
			
		||||
	ehdr->e_shoff     = elf32_to_cpu(ehdr, lehdr.e_shoff);
 | 
			
		||||
	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr.e_flags);
 | 
			
		||||
	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr.e_phnum);
 | 
			
		||||
	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr.e_shnum);
 | 
			
		||||
	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr.e_shstrndx);
 | 
			
		||||
 | 
			
		||||
	if ((ehdr->e_phnum > 0) &&
 | 
			
		||||
		(elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf32_Phdr))) 
 | 
			
		||||
	{
 | 
			
		||||
		/* Invalid program header size */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF bad program header size\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ehdr->e_shnum > 0) &&
 | 
			
		||||
		(elf16_to_cpu(ehdr, lehdr.e_shentsize) != sizeof(Elf32_Shdr)))
 | 
			
		||||
	{
 | 
			
		||||
		/* Invalid section header size */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF bad section header size\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_elf64_ehdr(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	Elf64_Ehdr lehdr;
 | 
			
		||||
	if (len < sizeof(lehdr)) {
 | 
			
		||||
		/* Buffer is to small to be an elf executable */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Buffer is to small to hold ELF header\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(&lehdr, buf, sizeof(lehdr));
 | 
			
		||||
	if (elf16_to_cpu(ehdr, lehdr.e_ehsize) != sizeof(Elf64_Ehdr)) {
 | 
			
		||||
		/* Invalid Elf header size */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Bad ELF header size\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (elf32_to_cpu(ehdr, lehdr.e_entry) > ULONG_MAX) {
 | 
			
		||||
		/* entry is to large */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF e_entry to large\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (elf32_to_cpu(ehdr, lehdr.e_phoff) > ULONG_MAX) {
 | 
			
		||||
		/* phoff is to large */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF e_phoff to large\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (elf32_to_cpu(ehdr, lehdr.e_shoff) > ULONG_MAX) {
 | 
			
		||||
		/* shoff is to large */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF e_shoff to large\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	ehdr->e_type      = elf16_to_cpu(ehdr, lehdr.e_type);
 | 
			
		||||
	ehdr->e_machine   = elf16_to_cpu(ehdr, lehdr.e_machine);
 | 
			
		||||
	ehdr->e_version   = elf32_to_cpu(ehdr, lehdr.e_version);
 | 
			
		||||
	ehdr->e_entry     = elf64_to_cpu(ehdr, lehdr.e_entry);
 | 
			
		||||
	ehdr->e_phoff     = elf64_to_cpu(ehdr, lehdr.e_phoff);
 | 
			
		||||
	ehdr->e_shoff     = elf64_to_cpu(ehdr, lehdr.e_shoff);
 | 
			
		||||
	ehdr->e_flags     = elf32_to_cpu(ehdr, lehdr.e_flags);
 | 
			
		||||
	ehdr->e_phnum     = elf16_to_cpu(ehdr, lehdr.e_phnum);
 | 
			
		||||
	ehdr->e_shnum     = elf16_to_cpu(ehdr, lehdr.e_shnum);
 | 
			
		||||
	ehdr->e_shstrndx  = elf16_to_cpu(ehdr, lehdr.e_shstrndx);
 | 
			
		||||
 | 
			
		||||
	if ((ehdr->e_phnum > 0) &&
 | 
			
		||||
		(elf16_to_cpu(ehdr, lehdr.e_phentsize) != sizeof(Elf64_Phdr))) 
 | 
			
		||||
	{
 | 
			
		||||
		/* Invalid program header size */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF bad program header size\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ehdr->e_shnum > 0) &&
 | 
			
		||||
		(elf16_to_cpu(ehdr, lehdr.e_shentsize) != sizeof(Elf64_Shdr)))
 | 
			
		||||
	{
 | 
			
		||||
		/* Invalid section header size */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF bad section header size\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_ehdr(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char e_ident[EI_NIDENT];
 | 
			
		||||
	int result;
 | 
			
		||||
	memset(ehdr, 0, sizeof(*ehdr));
 | 
			
		||||
	if (len < sizeof(e_ident)) {
 | 
			
		||||
		/* Buffer is to small to be an elf executable */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Buffer is to small to hold ELF e_ident\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	memcpy(e_ident, buf, sizeof(e_ident));
 | 
			
		||||
	if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
 | 
			
		||||
		/* No ELF header magic */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "NO ELF header magic\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	ehdr->ei_class   = e_ident[EI_CLASS];
 | 
			
		||||
	ehdr->ei_data    = e_ident[EI_DATA];
 | 
			
		||||
	if (	(ehdr->ei_class != ELFCLASS32) &&
 | 
			
		||||
		(ehdr->ei_class != ELFCLASS64))
 | 
			
		||||
	{
 | 
			
		||||
		/* Not a supported elf class */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not a supported ELF class\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (	(ehdr->ei_data != ELFDATA2LSB) &&
 | 
			
		||||
		(ehdr->ei_data != ELFDATA2MSB))
 | 
			
		||||
	{
 | 
			
		||||
		/* Not a supported elf data type */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Not a supported ELF data format\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	result = -1;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		result = build_mem_elf32_ehdr(buf, len, ehdr);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		result = build_mem_elf64_ehdr(buf, len, ehdr);
 | 
			
		||||
	}
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	if ((e_ident[EI_VERSION] != EV_CURRENT) ||
 | 
			
		||||
		(ehdr->e_version != EV_CURRENT))
 | 
			
		||||
	{
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "Unknown ELF version\n");
 | 
			
		||||
		}
 | 
			
		||||
		/* Unknwon elf version */
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_elf32_phdr(const char *buf, off_t len, 
 | 
			
		||||
	struct mem_ehdr *ehdr, int idx)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_phdr *phdr;
 | 
			
		||||
	const char *pbuf;
 | 
			
		||||
	Elf32_Phdr lphdr;
 | 
			
		||||
	pbuf = buf + ehdr->e_phoff + (idx * sizeof(lphdr));
 | 
			
		||||
	phdr = &ehdr->e_phdr[idx];
 | 
			
		||||
	memcpy(&lphdr, pbuf, sizeof(lphdr));
 | 
			
		||||
 | 
			
		||||
	if (	(elf32_to_cpu(ehdr, lphdr.p_filesz) > ULONG_MAX) || 
 | 
			
		||||
		(elf32_to_cpu(ehdr, lphdr.p_memsz)  > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lphdr.p_offset) > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lphdr.p_paddr)  > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lphdr.p_vaddr)  > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lphdr.p_align)  > ULONG_MAX))
 | 
			
		||||
	{
 | 
			
		||||
		fprintf(stderr, "Program segment size out of range\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	phdr->p_type   = elf32_to_cpu(ehdr, lphdr.p_type);
 | 
			
		||||
	phdr->p_paddr  = elf32_to_cpu(ehdr, lphdr.p_paddr);
 | 
			
		||||
	phdr->p_vaddr  = elf32_to_cpu(ehdr, lphdr.p_vaddr);
 | 
			
		||||
	phdr->p_filesz = elf32_to_cpu(ehdr, lphdr.p_filesz);
 | 
			
		||||
	phdr->p_memsz  = elf32_to_cpu(ehdr, lphdr.p_memsz);
 | 
			
		||||
	phdr->p_offset = elf32_to_cpu(ehdr, lphdr.p_offset);
 | 
			
		||||
	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr.p_flags);
 | 
			
		||||
	phdr->p_align  = elf32_to_cpu(ehdr, lphdr.p_align);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_elf64_phdr(const char *buf, off_t len,
 | 
			
		||||
	struct mem_ehdr *ehdr, int idx)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_phdr *phdr;
 | 
			
		||||
	const char *pbuf;
 | 
			
		||||
	Elf64_Phdr lphdr;
 | 
			
		||||
	pbuf = buf + ehdr->e_phoff + (idx * sizeof(lphdr));
 | 
			
		||||
	phdr = &ehdr->e_phdr[idx];
 | 
			
		||||
	memcpy(&lphdr, pbuf, sizeof(lphdr));
 | 
			
		||||
 | 
			
		||||
	if (	(elf64_to_cpu(ehdr, lphdr.p_filesz) > ULONG_MAX) || 
 | 
			
		||||
		(elf64_to_cpu(ehdr, lphdr.p_memsz)  > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lphdr.p_offset) > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lphdr.p_paddr)  > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lphdr.p_vaddr)  > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lphdr.p_align)  > ULONG_MAX))
 | 
			
		||||
	{
 | 
			
		||||
		fprintf(stderr, "Program segment size out of range\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	phdr->p_type   = elf32_to_cpu(ehdr, lphdr.p_type);
 | 
			
		||||
	phdr->p_paddr  = elf64_to_cpu(ehdr, lphdr.p_paddr);
 | 
			
		||||
	phdr->p_vaddr  = elf64_to_cpu(ehdr, lphdr.p_vaddr);
 | 
			
		||||
	phdr->p_filesz = elf64_to_cpu(ehdr, lphdr.p_filesz);
 | 
			
		||||
	phdr->p_memsz  = elf64_to_cpu(ehdr, lphdr.p_memsz);
 | 
			
		||||
	phdr->p_offset = elf64_to_cpu(ehdr, lphdr.p_offset);
 | 
			
		||||
	phdr->p_flags  = elf32_to_cpu(ehdr, lphdr.p_flags);
 | 
			
		||||
	phdr->p_align  = elf64_to_cpu(ehdr, lphdr.p_align);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_phdrs(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	size_t phdr_size, mem_phdr_size;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* e_phnum is at most 65535 so calculating
 | 
			
		||||
	 * the size of the program header cannot overflow.
 | 
			
		||||
	 */
 | 
			
		||||
	/* Is the program header in the file buffer? */
 | 
			
		||||
	phdr_size = 0;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		phdr_size = sizeof(Elf32_Phdr);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		phdr_size = sizeof(Elf64_Phdr);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		fprintf(stderr, "Invalid ei_class?\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	phdr_size *= ehdr->e_phnum; 
 | 
			
		||||
	if (ehdr->e_phoff + phdr_size > len) {
 | 
			
		||||
		/* The program header did not fit in the file buffer */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF program segment truncated\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Allocate the e_phdr array */
 | 
			
		||||
	mem_phdr_size = sizeof(ehdr->e_phdr[0]) * ehdr->e_phnum;
 | 
			
		||||
	ehdr->e_phdr = xmalloc(mem_phdr_size);
 | 
			
		||||
 | 
			
		||||
	for(i = 0; i < ehdr->e_phnum; i++) {
 | 
			
		||||
		struct mem_phdr *phdr;
 | 
			
		||||
		int result;
 | 
			
		||||
		result = -1;
 | 
			
		||||
		if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
			result = build_mem_elf32_phdr(buf, len, ehdr, i);
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
			result = build_mem_elf64_phdr(buf, len, ehdr, i);
 | 
			
		||||
		}
 | 
			
		||||
		if (result < 0) {
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Check the program headers to be certain
 | 
			
		||||
		 * they are safe to use.
 | 
			
		||||
		 */
 | 
			
		||||
		phdr = &ehdr->e_phdr[i];
 | 
			
		||||
		if ((phdr->p_offset + phdr->p_filesz) > len) {
 | 
			
		||||
			/* The segment does not fit in the buffer */
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "ELF segment not in file\n");
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		if ((phdr->p_paddr + phdr->p_memsz) < phdr->p_paddr) {
 | 
			
		||||
			/* The memory address wraps */
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "ELF address wrap around\n");
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		/* Remember where the segment lives in the buffer */
 | 
			
		||||
		phdr->p_data = buf + phdr->p_offset;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_elf32_shdr(const char *buf, off_t len, 
 | 
			
		||||
	struct mem_ehdr *ehdr, int idx)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_shdr *shdr;
 | 
			
		||||
	const char *sbuf;
 | 
			
		||||
	int size_ok;
 | 
			
		||||
	Elf32_Shdr lshdr;
 | 
			
		||||
	sbuf = buf + ehdr->e_shoff + (idx * sizeof(lshdr));
 | 
			
		||||
	shdr = &ehdr->e_shdr[idx];
 | 
			
		||||
	memcpy(&lshdr, sbuf, sizeof(lshdr));
 | 
			
		||||
 | 
			
		||||
	if (	(elf32_to_cpu(ehdr, lshdr.sh_flags)     > ULONG_MAX) || 
 | 
			
		||||
		(elf32_to_cpu(ehdr, lshdr.sh_addr)      > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lshdr.sh_offset)    > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lshdr.sh_size)      > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lshdr.sh_addralign) > ULONG_MAX) ||
 | 
			
		||||
		(elf32_to_cpu(ehdr, lshdr.sh_entsize)   > ULONG_MAX))
 | 
			
		||||
	{
 | 
			
		||||
		fprintf(stderr, "Program section size out of range\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr.sh_name);
 | 
			
		||||
	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr.sh_type);
 | 
			
		||||
	shdr->sh_flags     = elf32_to_cpu(ehdr, lshdr.sh_flags);
 | 
			
		||||
	shdr->sh_addr      = elf32_to_cpu(ehdr, lshdr.sh_addr);
 | 
			
		||||
	shdr->sh_offset    = elf32_to_cpu(ehdr, lshdr.sh_offset);
 | 
			
		||||
	shdr->sh_size      = elf32_to_cpu(ehdr, lshdr.sh_size);
 | 
			
		||||
	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr.sh_link);
 | 
			
		||||
	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr.sh_info);
 | 
			
		||||
	shdr->sh_addralign = elf32_to_cpu(ehdr, lshdr.sh_addralign);
 | 
			
		||||
	shdr->sh_entsize   = elf32_to_cpu(ehdr, lshdr.sh_entsize);
 | 
			
		||||
 | 
			
		||||
	/* Now verify sh_entsize */
 | 
			
		||||
	size_ok = 0;
 | 
			
		||||
	switch(shdr->sh_type) {
 | 
			
		||||
	case SHT_SYMTAB:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf32_Sym);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_RELA:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf32_Rela);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_DYNAMIC:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf32_Dyn);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_REL:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf32_Rel);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_NOTE:
 | 
			
		||||
	case SHT_NULL:
 | 
			
		||||
	case SHT_PROGBITS:
 | 
			
		||||
	case SHT_HASH:
 | 
			
		||||
	case SHT_NOBITS:
 | 
			
		||||
	default:
 | 
			
		||||
		/* This is a section whose entsize requirements
 | 
			
		||||
		 * I don't care about.  If I don't know about
 | 
			
		||||
		 * the section I can't care about it's entsize
 | 
			
		||||
		 * requirements.
 | 
			
		||||
		 */
 | 
			
		||||
		size_ok = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	if (!size_ok) {
 | 
			
		||||
		fprintf(stderr, "Bad section header(%x) entsize: %ld\n",
 | 
			
		||||
			shdr->sh_type, shdr->sh_entsize);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_elf64_shdr(const char *buf, off_t len, 
 | 
			
		||||
	struct mem_ehdr *ehdr, int idx)
 | 
			
		||||
{
 | 
			
		||||
	struct mem_shdr *shdr;
 | 
			
		||||
	const char *sbuf;
 | 
			
		||||
	int size_ok;
 | 
			
		||||
	Elf64_Shdr lshdr;
 | 
			
		||||
	sbuf = buf + ehdr->e_shoff + (idx * sizeof(lshdr));
 | 
			
		||||
	shdr = &ehdr->e_shdr[idx];
 | 
			
		||||
	memcpy(&lshdr, sbuf, sizeof(lshdr));
 | 
			
		||||
 | 
			
		||||
	if (	(elf64_to_cpu(ehdr, lshdr.sh_flags)     > ULONG_MAX) || 
 | 
			
		||||
		(elf64_to_cpu(ehdr, lshdr.sh_addr)      > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lshdr.sh_offset)    > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lshdr.sh_size)      > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lshdr.sh_addralign) > ULONG_MAX) ||
 | 
			
		||||
		(elf64_to_cpu(ehdr, lshdr.sh_entsize)   > ULONG_MAX))
 | 
			
		||||
	{
 | 
			
		||||
		fprintf(stderr, "Program section size out of range\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	shdr->sh_name      = elf32_to_cpu(ehdr, lshdr.sh_name);
 | 
			
		||||
	shdr->sh_type      = elf32_to_cpu(ehdr, lshdr.sh_type);
 | 
			
		||||
	shdr->sh_flags     = elf64_to_cpu(ehdr, lshdr.sh_flags);
 | 
			
		||||
	shdr->sh_addr      = elf64_to_cpu(ehdr, lshdr.sh_addr);
 | 
			
		||||
	shdr->sh_offset    = elf64_to_cpu(ehdr, lshdr.sh_offset);
 | 
			
		||||
	shdr->sh_size      = elf64_to_cpu(ehdr, lshdr.sh_size);
 | 
			
		||||
	shdr->sh_link      = elf32_to_cpu(ehdr, lshdr.sh_link);
 | 
			
		||||
	shdr->sh_info      = elf32_to_cpu(ehdr, lshdr.sh_info);
 | 
			
		||||
	shdr->sh_addralign = elf64_to_cpu(ehdr, lshdr.sh_addralign);
 | 
			
		||||
	shdr->sh_entsize   = elf64_to_cpu(ehdr, lshdr.sh_entsize);
 | 
			
		||||
 | 
			
		||||
	/* Now verify sh_entsize */
 | 
			
		||||
	size_ok = 0;
 | 
			
		||||
	switch(shdr->sh_type) {
 | 
			
		||||
	case SHT_SYMTAB:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf64_Sym);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_RELA:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf64_Rela);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_DYNAMIC:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf64_Dyn);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_REL:
 | 
			
		||||
		size_ok = shdr->sh_entsize == sizeof(Elf64_Rel);
 | 
			
		||||
		break;
 | 
			
		||||
	case SHT_NOTE:
 | 
			
		||||
	case SHT_NULL:
 | 
			
		||||
	case SHT_PROGBITS:
 | 
			
		||||
	case SHT_HASH:
 | 
			
		||||
	case SHT_NOBITS:
 | 
			
		||||
	default:
 | 
			
		||||
		/* This is a section whose entsize requirements
 | 
			
		||||
		 * I don't care about.  If I don't know about
 | 
			
		||||
		 * the section I can't care about it's entsize
 | 
			
		||||
		 * requirements.
 | 
			
		||||
		 */
 | 
			
		||||
		size_ok = 1;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
	if (!size_ok) {
 | 
			
		||||
		fprintf(stderr, "Bad section header(%x) entsize: %ld\n",
 | 
			
		||||
			shdr->sh_type, shdr->sh_entsize);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int build_mem_shdrs(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	size_t shdr_size, mem_shdr_size;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* e_shnum is at most 65536 so calculating
 | 
			
		||||
	 * the size of the section header cannot overflow.
 | 
			
		||||
	 */
 | 
			
		||||
	/* Is the program header in the file buffer? */
 | 
			
		||||
	shdr_size = 0;
 | 
			
		||||
	if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
		shdr_size = sizeof(Elf32_Shdr);
 | 
			
		||||
	}
 | 
			
		||||
	else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
		shdr_size = sizeof(Elf64_Shdr);
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		fprintf(stderr, "Invalid ei_class?\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	shdr_size *= ehdr->e_shnum;
 | 
			
		||||
	if (ehdr->e_shoff + shdr_size > len) {
 | 
			
		||||
		/* The section header did not fit in the file buffer */
 | 
			
		||||
		if (probe_debug) {
 | 
			
		||||
			fprintf(stderr, "ELF section header does not fit in file\n");
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Allocate the e_shdr array */
 | 
			
		||||
	mem_shdr_size = sizeof(ehdr->e_shdr[0]) * ehdr->e_shnum;
 | 
			
		||||
	ehdr->e_shdr = xmalloc(mem_shdr_size);
 | 
			
		||||
 | 
			
		||||
	for(i = 0; i < ehdr->e_shnum; i++) {
 | 
			
		||||
		struct mem_shdr *shdr;
 | 
			
		||||
		int result;
 | 
			
		||||
		result = -1;
 | 
			
		||||
		if (ehdr->ei_class == ELFCLASS32) {
 | 
			
		||||
			result = build_mem_elf32_shdr(buf, len, ehdr, i);
 | 
			
		||||
		}
 | 
			
		||||
		else if (ehdr->ei_class == ELFCLASS64) {
 | 
			
		||||
			result = build_mem_elf64_shdr(buf, len, ehdr, i);
 | 
			
		||||
		}
 | 
			
		||||
		if (result < 0) {
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
		/* Check the section headers to be certain
 | 
			
		||||
		 * they are safe to use.
 | 
			
		||||
		 */
 | 
			
		||||
		shdr = &ehdr->e_shdr[i];
 | 
			
		||||
		if ((shdr->sh_type != SHT_NOBITS) &&
 | 
			
		||||
			((shdr->sh_offset + shdr->sh_size) > len))
 | 
			
		||||
		{
 | 
			
		||||
			/* The section does not fit in the buffer */
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "ELF section %d not in file\n", 
 | 
			
		||||
					i);
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		if ((shdr->sh_addr + shdr->sh_size) < shdr->sh_addr) {
 | 
			
		||||
			/* The memory address wraps */
 | 
			
		||||
			if (probe_debug) {
 | 
			
		||||
				fprintf(stderr, "ELF address wrap around\n");
 | 
			
		||||
			}
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		/* Remember where the section lives in the buffer */
 | 
			
		||||
		shdr->sh_data = buf + shdr->sh_offset;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void read_nhdr(const struct mem_ehdr *ehdr, 
 | 
			
		||||
	ElfNN_Nhdr *hdr, const unsigned char *note)
 | 
			
		||||
{
 | 
			
		||||
	memcpy(hdr, note, sizeof(*hdr));
 | 
			
		||||
	hdr->n_namesz = elf32_to_cpu(ehdr, hdr->n_namesz);
 | 
			
		||||
	hdr->n_descsz = elf32_to_cpu(ehdr, hdr->n_descsz);
 | 
			
		||||
	hdr->n_type   = elf32_to_cpu(ehdr, hdr->n_type);
 | 
			
		||||
		
 | 
			
		||||
}
 | 
			
		||||
static int build_mem_notes(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	const unsigned char *note_start, *note_end, *note;
 | 
			
		||||
	size_t note_size;
 | 
			
		||||
	int i;
 | 
			
		||||
	/* First find the note segment or section */
 | 
			
		||||
	note_start = note_end = NULL;
 | 
			
		||||
	for(i = 0; !note_start && (i < ehdr->e_phnum); i++) {
 | 
			
		||||
		struct mem_phdr *phdr = &ehdr->e_phdr[i];
 | 
			
		||||
		if (phdr->p_type == PT_NOTE) {
 | 
			
		||||
			note_start = phdr->p_data;
 | 
			
		||||
			note_end = note_start + phdr->p_filesz;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for(i = 0; !note_start && (i < ehdr->e_shnum); i++) {
 | 
			
		||||
		struct mem_shdr *shdr = &ehdr->e_shdr[i];
 | 
			
		||||
		if (shdr->sh_type == SHT_NOTE) {
 | 
			
		||||
			note_start = shdr->sh_data;
 | 
			
		||||
			note_end = note_start + shdr->sh_size;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!note_start) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	/* Walk through and count the notes */
 | 
			
		||||
	ehdr->e_notenum = 0;
 | 
			
		||||
	for(note = note_start; note < note_end; note+= note_size) {
 | 
			
		||||
		ElfNN_Nhdr hdr;
 | 
			
		||||
		read_nhdr(ehdr, &hdr, note);
 | 
			
		||||
		note_size  = sizeof(hdr);
 | 
			
		||||
		note_size += (hdr.n_namesz + 3) & ~3;
 | 
			
		||||
		note_size += (hdr.n_descsz + 3) & ~3;
 | 
			
		||||
		ehdr->e_notenum += 1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Now walk and normalize the notes */
 | 
			
		||||
	ehdr->e_note = xmalloc(sizeof(*ehdr->e_note) * ehdr->e_notenum);
 | 
			
		||||
	for(i = 0, note = note_start; note < note_end; note+= note_size, i++) {
 | 
			
		||||
		const unsigned char *name, *desc;
 | 
			
		||||
		ElfNN_Nhdr hdr;
 | 
			
		||||
		read_nhdr(ehdr, &hdr, note);
 | 
			
		||||
		note_size  = sizeof(hdr);
 | 
			
		||||
		name       = note + note_size;
 | 
			
		||||
		note_size += (hdr.n_namesz + 3) & ~3;
 | 
			
		||||
		desc       = note + note_size;
 | 
			
		||||
		note_size += (hdr.n_descsz + 3) & ~3;
 | 
			
		||||
		
 | 
			
		||||
		if ((hdr.n_namesz != 0) && (name[hdr.n_namesz -1] != '\0')) {
 | 
			
		||||
			die("Note name is not null termiated");
 | 
			
		||||
		}
 | 
			
		||||
		ehdr->e_note[i].n_type = hdr.n_type;
 | 
			
		||||
		ehdr->e_note[i].n_name = name;
 | 
			
		||||
		ehdr->e_note[i].n_desc = desc;
 | 
			
		||||
		ehdr->e_note[i].n_descsz = hdr.n_descsz;
 | 
			
		||||
		
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void free_elf_info(struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	free(ehdr->e_phdr);
 | 
			
		||||
	free(ehdr->e_shdr);
 | 
			
		||||
	memset(ehdr, 0, sizeof(*ehdr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
	result = build_mem_ehdr(buf, len, ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	if ((ehdr->e_phoff > 0) && (ehdr->e_phnum > 0)) {
 | 
			
		||||
		result = build_mem_phdrs(buf, len, ehdr);
 | 
			
		||||
		if (result < 0) {
 | 
			
		||||
			free_elf_info(ehdr);
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ((ehdr->e_shoff > 0) && (ehdr->e_shnum > 0)) {
 | 
			
		||||
		result = build_mem_shdrs(buf, len, ehdr);
 | 
			
		||||
		if (result < 0) {
 | 
			
		||||
			free_elf_info(ehdr);
 | 
			
		||||
			return result;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	result = build_mem_notes(buf, len, ehdr);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		free_elf_info(ehdr);
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										125
									
								
								kexec/kexec-elf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								kexec/kexec-elf.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,125 @@
 | 
			
		||||
#ifndef KEXEC_ELF_H
 | 
			
		||||
#define KEXEC_ELF_H
 | 
			
		||||
 | 
			
		||||
struct kexec_info;
 | 
			
		||||
 | 
			
		||||
struct mem_ehdr {
 | 
			
		||||
	unsigned ei_class;
 | 
			
		||||
	unsigned ei_data;
 | 
			
		||||
	unsigned e_type;
 | 
			
		||||
	unsigned e_machine;
 | 
			
		||||
	unsigned e_version;
 | 
			
		||||
	unsigned e_flags;
 | 
			
		||||
	unsigned e_phnum;
 | 
			
		||||
	unsigned e_shnum;
 | 
			
		||||
	unsigned e_shstrndx;
 | 
			
		||||
	unsigned long e_entry;
 | 
			
		||||
	unsigned long e_phoff;
 | 
			
		||||
	unsigned long e_shoff;
 | 
			
		||||
	unsigned e_notenum;
 | 
			
		||||
	struct mem_phdr *e_phdr;
 | 
			
		||||
	struct mem_shdr *e_shdr;
 | 
			
		||||
	struct mem_note *e_note;
 | 
			
		||||
	unsigned long rel_addr, rel_size;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mem_phdr {
 | 
			
		||||
	unsigned long p_paddr;
 | 
			
		||||
	unsigned long p_vaddr;
 | 
			
		||||
	unsigned long p_filesz;
 | 
			
		||||
	unsigned long p_memsz;
 | 
			
		||||
	unsigned long p_offset;
 | 
			
		||||
	const char *p_data;
 | 
			
		||||
	unsigned p_type;
 | 
			
		||||
	unsigned p_flags;
 | 
			
		||||
	unsigned p_align;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mem_shdr {
 | 
			
		||||
	unsigned sh_name;
 | 
			
		||||
	unsigned sh_type;
 | 
			
		||||
	unsigned long sh_flags;
 | 
			
		||||
	unsigned long sh_addr;
 | 
			
		||||
	unsigned long sh_offset;
 | 
			
		||||
	unsigned long sh_size;
 | 
			
		||||
	unsigned sh_link;
 | 
			
		||||
	unsigned sh_info;
 | 
			
		||||
	unsigned long sh_addralign;
 | 
			
		||||
	unsigned long sh_entsize;
 | 
			
		||||
	const unsigned char *sh_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mem_sym {
 | 
			
		||||
	unsigned long st_name;   /* Symbol name (string tbl index) */
 | 
			
		||||
	unsigned char st_info;   /* No defined meaning, 0 */
 | 
			
		||||
	unsigned char st_other;  /* Symbol type and binding */
 | 
			
		||||
	unsigned long st_shndx;  /* Section index */
 | 
			
		||||
	unsigned long st_value;  /* Symbol value */
 | 
			
		||||
	unsigned long st_size;   /* Symbol size */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct  mem_rela {
 | 
			
		||||
	unsigned long r_offset;
 | 
			
		||||
	unsigned long r_sym;
 | 
			
		||||
	unsigned long r_type;
 | 
			
		||||
	unsigned long r_addend;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mem_note {
 | 
			
		||||
	unsigned n_type;
 | 
			
		||||
	unsigned n_descsz;
 | 
			
		||||
	const char *n_name;
 | 
			
		||||
	const void *n_desc;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* The definition of an ELF note does not vary depending
 | 
			
		||||
 * on ELFCLASS.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
	uint32_t n_namesz;		/* Length of the note's name.  */
 | 
			
		||||
	uint32_t n_descsz;		/* Length of the note's descriptor.  */
 | 
			
		||||
	uint32_t n_type;		/* Type of the note.  */
 | 
			
		||||
} ElfNN_Nhdr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern void free_elf_info(struct mem_ehdr *ehdr);
 | 
			
		||||
extern int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
 | 
			
		||||
extern int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
 | 
			
		||||
extern int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr);
 | 
			
		||||
 | 
			
		||||
extern int elf_exec_load(const struct mem_ehdr *ehdr, struct kexec_info *info);
 | 
			
		||||
extern int elf_rel_load(struct mem_ehdr *ehdr, struct kexec_info *info,
 | 
			
		||||
	unsigned long min, unsigned long max, int end);
 | 
			
		||||
 | 
			
		||||
extern void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, 
 | 
			
		||||
	const char *buf, off_t len);
 | 
			
		||||
extern void elf_rel_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, 
 | 
			
		||||
	const char *buf, off_t len, unsigned long min, unsigned long max, 
 | 
			
		||||
	int end);
 | 
			
		||||
 | 
			
		||||
extern int elf_rel_find_symbol(struct mem_ehdr *ehdr,
 | 
			
		||||
	const char *name, struct mem_sym *ret_sym);
 | 
			
		||||
extern unsigned long elf_rel_get_addr(struct mem_ehdr *ehdr, const char *name);
 | 
			
		||||
extern void elf_rel_set_symbol(struct mem_ehdr *ehdr,
 | 
			
		||||
	const char *name, const void *buf, size_t size);
 | 
			
		||||
extern void elf_rel_get_symbol(struct mem_ehdr *ehdr,
 | 
			
		||||
	const char *name, void *buf, size_t size);
 | 
			
		||||
 | 
			
		||||
uint16_t elf16_to_cpu(const struct mem_ehdr *ehdr, uint16_t value);
 | 
			
		||||
uint32_t elf32_to_cpu(const struct mem_ehdr *ehdr, uint32_t value);
 | 
			
		||||
uint64_t elf64_to_cpu(const struct mem_ehdr *ehdr, uint64_t value);
 | 
			
		||||
 | 
			
		||||
uint16_t cpu_to_elf16(const struct mem_ehdr *ehdr, uint16_t value);
 | 
			
		||||
uint32_t cpu_to_elf32(const struct mem_ehdr *ehdr, uint32_t value);
 | 
			
		||||
uint64_t cpu_to_elf64(const struct mem_ehdr *ehdr, uint64_t value);
 | 
			
		||||
 | 
			
		||||
unsigned long elf_max_addr(const struct mem_ehdr *ehdr);
 | 
			
		||||
 | 
			
		||||
/* Architecture specific helper functions */
 | 
			
		||||
extern int machine_verify_elf_rel(struct mem_ehdr *ehdr);
 | 
			
		||||
extern void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, 
 | 
			
		||||
	void *location, unsigned long address, unsigned long value);
 | 
			
		||||
#endif /* KEXEC_ELF_H */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								kexec/kexec-sha256.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								kexec/kexec-sha256.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef KEXEC_SHA256_H
 | 
			
		||||
#define KEXEC_SHA256_H
 | 
			
		||||
 | 
			
		||||
struct sha256_region {
 | 
			
		||||
	const void *start;
 | 
			
		||||
	unsigned long len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define SHA256_REGIONS 8
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_SHA256_H */
 | 
			
		||||
							
								
								
									
										73
									
								
								kexec/kexec-syscall.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								kexec/kexec-syscall.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
#ifndef KEXEC_SYSCALL_H
 | 
			
		||||
#define KEXEC_SYSCALL_H
 | 
			
		||||
 | 
			
		||||
#define __LIBRARY__
 | 
			
		||||
#include <syscall.h>
 | 
			
		||||
#include <sys/syscall.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#define	LINUX_REBOOT_MAGIC1	0xfee1dead
 | 
			
		||||
#define	LINUX_REBOOT_MAGIC2	672274793
 | 
			
		||||
#define	LINUX_REBOOT_MAGIC2A	85072278
 | 
			
		||||
#define	LINUX_REBOOT_MAGIC2B	369367448
 | 
			
		||||
 | 
			
		||||
#define	LINUX_REBOOT_CMD_RESTART	0x01234567
 | 
			
		||||
#define	LINUX_REBOOT_CMD_HALT		0xCDEF0123
 | 
			
		||||
#define	LINUX_REBOOT_CMD_CAD_ON		0x89ABCDEF
 | 
			
		||||
#define	LINUX_REBOOT_CMD_CAD_OFF	0x00000000
 | 
			
		||||
#define	LINUX_REBOOT_CMD_POWER_OFF	0x4321FEDC
 | 
			
		||||
#define	LINUX_REBOOT_CMD_RESTART2	0xA1B2C3D4
 | 
			
		||||
#define LINUX_REBOOT_CMD_EXEC_KERNEL    0x18273645
 | 
			
		||||
#define LINUX_REBOOT_CMD_KEXEC_OLD	0x81726354
 | 
			
		||||
#define LINUX_REBOOT_CMD_KEXEC_OLD2	0x18263645
 | 
			
		||||
#define LINUX_REBOOT_CMD_KEXEC		0x45584543
 | 
			
		||||
 | 
			
		||||
#ifdef __i386__
 | 
			
		||||
#define __NR_kexec_load		283
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef __ia64__
 | 
			
		||||
#define __NR_kexec_load		1268
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef __powerpc64__
 | 
			
		||||
#define __NR_kexec_load		268
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef __powerpc__
 | 
			
		||||
#define __NR_kexec_load		268
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef __x86_64__
 | 
			
		||||
#define __NR_kexec_load		246
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef __NR_kexec_load
 | 
			
		||||
#error Unknown processor architecture.  Needs a kexec_load syscall number.
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct kexec_segment;
 | 
			
		||||
 | 
			
		||||
static inline long kexec_load(void *entry, unsigned long nr_segments,
 | 
			
		||||
			struct kexec_segment *segments, unsigned long flags)
 | 
			
		||||
{
 | 
			
		||||
	return (long) syscall(__NR_kexec_load, entry, nr_segments, segments, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline long kexec_reboot(void)
 | 
			
		||||
{
 | 
			
		||||
	return (long) syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_KEXEC, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define KEXEC_ON_CRASH  0x00000001
 | 
			
		||||
#define KEXEC_ARCH_MASK 0xffff0000
 | 
			
		||||
 | 
			
		||||
/* These values match the ELF architecture values. 
 | 
			
		||||
 * Unless there is a good reason that should continue to be the case.
 | 
			
		||||
 */
 | 
			
		||||
#define KEXEC_ARCH_DEFAULT ( 0 << 16)
 | 
			
		||||
#define KEXEC_ARCH_386     ( 3 << 16)
 | 
			
		||||
#define KEXEC_ARCH_X86_64  (62 << 16)
 | 
			
		||||
#define KEXEC_ARCH_PPC     (20 << 16)
 | 
			
		||||
#define KEXEC_ARCH_PPC64   (21 << 16)
 | 
			
		||||
#define KEXEC_ARCH_IA_64   (50 << 16)
 | 
			
		||||
 | 
			
		||||
#define KEXEC_MAX_SEGMENTS 8
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_SYSCALL_H */
 | 
			
		||||
							
								
								
									
										45
									
								
								kexec/kexec.8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								kexec/kexec.8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
.\"                                      Hey, EMACS: -*- nroff -*-
 | 
			
		||||
.\" First parameter, NAME, should be all caps
 | 
			
		||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
 | 
			
		||||
.\" other parameters are allowed: see man(7), man(1)
 | 
			
		||||
.TH KEXEC-TOOLS 8 "October 13, 2004"
 | 
			
		||||
.\" Please adjust this date whenever revising the manpage.
 | 
			
		||||
.\"
 | 
			
		||||
.\" Some roff macros, for reference:
 | 
			
		||||
.\" .nh        disable hyphenation
 | 
			
		||||
.\" .hy        enable hyphenation
 | 
			
		||||
.\" .ad l      left justify
 | 
			
		||||
.\" .ad b      justify to both left and right margins
 | 
			
		||||
.\" .nf        disable filling
 | 
			
		||||
.\" .fi        enable filling
 | 
			
		||||
.\" .br        insert line break
 | 
			
		||||
.\" .sp <n>    insert n+1 empty lines
 | 
			
		||||
.\" for manpage-specific macros, see man(7)
 | 
			
		||||
.SH NAME
 | 
			
		||||
kexec-tools \- Tool to load a kernel for warm reboot and initiate a warm reboot
 | 
			
		||||
.SH SYNOPSIS
 | 
			
		||||
.B kexec-tools
 | 
			
		||||
.RI [ options ] " files" ...
 | 
			
		||||
.SH DESCRIPTION
 | 
			
		||||
.PP
 | 
			
		||||
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
 | 
			
		||||
.\" \fI<whatever>\fP escape sequences to invode bold face and italics, 
 | 
			
		||||
.\" respectively.
 | 
			
		||||
\fBkexec-tools\fP does not have a man page yet. Please use "kexec -h" for help.
 | 
			
		||||
.SH OPTIONS
 | 
			
		||||
These programs follow the usual GNU command line syntax, with long
 | 
			
		||||
options starting with two dashes (`-').
 | 
			
		||||
A summary of options is included below.
 | 
			
		||||
For a complete description, see the Info files.
 | 
			
		||||
.TP
 | 
			
		||||
.B \-h, \-\-help
 | 
			
		||||
Show summary of options.
 | 
			
		||||
.TP
 | 
			
		||||
.B \-v, \-\-version
 | 
			
		||||
Show version of program.
 | 
			
		||||
.SH SEE ALSO
 | 
			
		||||
.SH AUTHOR
 | 
			
		||||
kexec-tools was written by Eric Biederman.
 | 
			
		||||
.PP
 | 
			
		||||
This manual page was written by Khalid Aziz <khalid_aziz@hp.com>,
 | 
			
		||||
for the Debian project (but may be used by others).
 | 
			
		||||
							
								
								
									
										810
									
								
								kexec/kexec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										810
									
								
								kexec/kexec.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,810 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <getopt.h>
 | 
			
		||||
#ifdef HAVE_ZLIB_H
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <sha256.h>
 | 
			
		||||
#include "kexec.h"
 | 
			
		||||
#include "kexec-syscall.h"
 | 
			
		||||
#include "kexec-elf.h"
 | 
			
		||||
#include "kexec-sha256.h"
 | 
			
		||||
 | 
			
		||||
static unsigned long long mem_min = 0;
 | 
			
		||||
static unsigned long long mem_max = ULONG_MAX;
 | 
			
		||||
 | 
			
		||||
void die(char *fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	va_list args;
 | 
			
		||||
	va_start(args, fmt);
 | 
			
		||||
	vfprintf(stderr, fmt, args);
 | 
			
		||||
	va_end(args);
 | 
			
		||||
	fflush(stdout);
 | 
			
		||||
	fflush(stderr);
 | 
			
		||||
	exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void *xmalloc(size_t size)
 | 
			
		||||
{
 | 
			
		||||
	void *buf;
 | 
			
		||||
	buf = malloc(size);
 | 
			
		||||
	if (!buf) {
 | 
			
		||||
		die("Cannot malloc %ld bytes: %s\n",
 | 
			
		||||
			size + 0UL, strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *xrealloc(void *ptr, size_t size)
 | 
			
		||||
{
 | 
			
		||||
	void *buf;
 | 
			
		||||
	buf = realloc(ptr, size);
 | 
			
		||||
	if (!buf) {
 | 
			
		||||
		die("Cannot realloc %ld bytes: %s\n",
 | 
			
		||||
			size + 0UL, strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* local variables */
 | 
			
		||||
static struct memory_range *memory_range;
 | 
			
		||||
static int memory_ranges;
 | 
			
		||||
 | 
			
		||||
int valid_memory_range(unsigned long sstart, unsigned long send)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	if (sstart > send) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	if ((send > mem_max) || (sstart < mem_min)) {
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < memory_ranges; i++) {
 | 
			
		||||
		unsigned long mstart, mend;
 | 
			
		||||
		/* Only consider memory ranges */
 | 
			
		||||
		if (memory_range[i].type != RANGE_RAM)
 | 
			
		||||
			continue;
 | 
			
		||||
		mstart = memory_range[i].start;
 | 
			
		||||
		mend = memory_range[i].end;
 | 
			
		||||
		/* Check to see if we are fully contained */
 | 
			
		||||
		if ((mstart <= sstart) && (mend >= send)) {
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int valid_memory_segment(struct kexec_segment *segment)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long sstart, send;
 | 
			
		||||
	sstart = (unsigned long)segment->mem;
 | 
			
		||||
	send   = sstart + segment->memsz - 1;
 | 
			
		||||
 | 
			
		||||
	return valid_memory_range(sstart, send);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_segments(FILE *f, struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	fprintf(f, "nr_segments = %d\n", info->nr_segments);
 | 
			
		||||
	for (i = 0; i < info->nr_segments; i++) {
 | 
			
		||||
		fprintf(f, "segment[%d].buf   = %p\n",	i, info->segment[i].buf);
 | 
			
		||||
		fprintf(f, "segment[%d].bufsz = %zx\n", i, info->segment[i].bufsz);
 | 
			
		||||
		fprintf(f, "segment[%d].mem   = %p\n",	i, info->segment[i].mem);
 | 
			
		||||
		fprintf(f, "segment[%d].memsz = %zx\n", i, info->segment[i].memsz);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int sort_segments(struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	int i, j;
 | 
			
		||||
	void *end;
 | 
			
		||||
 | 
			
		||||
	/* Do a stupid insertion sort... */
 | 
			
		||||
	for (i = 0; i < info->nr_segments; i++) {
 | 
			
		||||
		int tidx;
 | 
			
		||||
		struct kexec_segment temp;
 | 
			
		||||
		tidx = i;
 | 
			
		||||
		for (j = i +1; j < info->nr_segments; j++) {
 | 
			
		||||
			if (info->segment[j].mem < info->segment[tidx].mem) {
 | 
			
		||||
				tidx = j;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (tidx != i) {
 | 
			
		||||
			temp = info->segment[tidx];
 | 
			
		||||
			info->segment[tidx] = info->segment[i];
 | 
			
		||||
			info->segment[i] = temp;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Now see if any of the segments overlap */
 | 
			
		||||
	end = 0;
 | 
			
		||||
	for (i = 0; i < info->nr_segments; i++) {
 | 
			
		||||
		if (end > info->segment[i].mem) {
 | 
			
		||||
			fprintf(stderr, "Overlapping memory segments at %p\n",
 | 
			
		||||
				end);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
		end = ((char *)info->segment[i].mem) + info->segment[i].memsz;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned long locate_hole(struct kexec_info *info,
 | 
			
		||||
	unsigned long hole_size, unsigned long hole_align, 
 | 
			
		||||
	unsigned long hole_min, unsigned long hole_max, 
 | 
			
		||||
	int hole_end)
 | 
			
		||||
{
 | 
			
		||||
	int i, j;
 | 
			
		||||
	struct memory_range *mem_range;
 | 
			
		||||
	int max_mem_ranges, mem_ranges;
 | 
			
		||||
	unsigned long hole_base;
 | 
			
		||||
 | 
			
		||||
	if (hole_end == 0) {
 | 
			
		||||
		die("Invalid hole end argument of 0 specified to locate_hole");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set an intial invalid value for the hole base */
 | 
			
		||||
	hole_base = ULONG_MAX;
 | 
			
		||||
 | 
			
		||||
	/* Ensure I have a sane alignment value */
 | 
			
		||||
	if (hole_align == 0) {
 | 
			
		||||
		hole_align = 1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Align everything to at least a page size boundary */
 | 
			
		||||
	if (hole_align < getpagesize()) {
 | 
			
		||||
		hole_align = getpagesize();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Compute the free memory ranges */
 | 
			
		||||
	max_mem_ranges = memory_ranges + (info->nr_segments -1);
 | 
			
		||||
	mem_range = malloc(max_mem_ranges *sizeof(struct memory_range));
 | 
			
		||||
	mem_ranges = 0;
 | 
			
		||||
		
 | 
			
		||||
	/* Perform a merge on the 2 sorted lists of memory ranges  */
 | 
			
		||||
	for (j = 0, i = 0; i < memory_ranges; i++) {
 | 
			
		||||
		unsigned long sstart, send;
 | 
			
		||||
		unsigned long mstart, mend;
 | 
			
		||||
		mstart = memory_range[i].start;
 | 
			
		||||
		mend = memory_range[i].end;
 | 
			
		||||
		if (memory_range[i].type != RANGE_RAM)
 | 
			
		||||
			continue;
 | 
			
		||||
		while ((j < info->nr_segments) && (((unsigned long)info->segment[j].mem) <= mend)) {
 | 
			
		||||
			sstart = (unsigned long)info->segment[j].mem;
 | 
			
		||||
			send = sstart + info->segment[j].memsz -1;
 | 
			
		||||
			if (mstart < sstart) {
 | 
			
		||||
				mem_range[mem_ranges].start = mstart;
 | 
			
		||||
				mem_range[mem_ranges].end = sstart -1;
 | 
			
		||||
				mem_range[mem_ranges].type = RANGE_RAM;
 | 
			
		||||
				mem_ranges++;
 | 
			
		||||
			}
 | 
			
		||||
			mstart = send +1;
 | 
			
		||||
			j++;
 | 
			
		||||
		}
 | 
			
		||||
		if (mstart <= mend) {
 | 
			
		||||
			mem_range[mem_ranges].start = mstart;
 | 
			
		||||
			mem_range[mem_ranges].end = mend;
 | 
			
		||||
			mem_range[mem_ranges].type = RANGE_RAM;
 | 
			
		||||
			mem_ranges++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Now find the end of the last memory_range I can use */
 | 
			
		||||
	for (i = 0; i < mem_ranges; i++) {
 | 
			
		||||
		unsigned long long start, end, size;
 | 
			
		||||
		start = mem_range[i].start;
 | 
			
		||||
		end   = mem_range[i].end;
 | 
			
		||||
		/* First filter the range start and end values
 | 
			
		||||
		 * through the lens of mem_min, mem_max and hole_align.
 | 
			
		||||
		 */
 | 
			
		||||
		if (start < mem_min) {
 | 
			
		||||
			start = mem_min;
 | 
			
		||||
		}
 | 
			
		||||
		if (start < hole_min) {
 | 
			
		||||
			start = hole_min;
 | 
			
		||||
		}
 | 
			
		||||
		start = (start + hole_align - 1) & ~(hole_align - 1);
 | 
			
		||||
		if (end > mem_max) {
 | 
			
		||||
			end = mem_max;
 | 
			
		||||
		}
 | 
			
		||||
		if (end > hole_max) {
 | 
			
		||||
			end = hole_max;
 | 
			
		||||
		}
 | 
			
		||||
		/* Is this still a valid memory range? */
 | 
			
		||||
		if ((start >= end) || (start >= mem_max) || (end <= mem_min)) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		/* Is there enough space left so we can use it? */
 | 
			
		||||
		size = end - start;
 | 
			
		||||
		if (size >= hole_size) {
 | 
			
		||||
			if (hole_end > 0) {
 | 
			
		||||
				hole_base = start;
 | 
			
		||||
				break;
 | 
			
		||||
			} else {
 | 
			
		||||
				hole_base = (end - hole_size) & ~(hole_align - 1);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (hole_base == ULONG_MAX) {
 | 
			
		||||
		fprintf(stderr, "Could not find a free area of memory of %lx bytes...\n",
 | 
			
		||||
			hole_size);
 | 
			
		||||
		return ULONG_MAX;
 | 
			
		||||
	}
 | 
			
		||||
	if ((hole_base + hole_size)  > hole_max) {
 | 
			
		||||
		fprintf(stderr, "Could not find a free area of memory below: %lx...\n",
 | 
			
		||||
			hole_max);
 | 
			
		||||
		return ULONG_MAX;
 | 
			
		||||
	}
 | 
			
		||||
	return hole_base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_segment(struct kexec_info *info,
 | 
			
		||||
	const void *buf, size_t bufsz,
 | 
			
		||||
	unsigned long base, size_t memsz)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long last;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	int pagesize;
 | 
			
		||||
 | 
			
		||||
	if (bufsz > memsz) {
 | 
			
		||||
		bufsz = memsz;
 | 
			
		||||
	}
 | 
			
		||||
	/* Forget empty segments */
 | 
			
		||||
	if (memsz == 0) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Round memsz up to a multiple of pagesize */
 | 
			
		||||
	pagesize = getpagesize();
 | 
			
		||||
	memsz = (memsz + (pagesize - 1)) & ~(pagesize - 1);
 | 
			
		||||
 | 
			
		||||
	/* Verify base is pagesize aligned.
 | 
			
		||||
	 * Finding a way to cope with this problem
 | 
			
		||||
	 * is important but for now error so at least
 | 
			
		||||
	 * we are not surprised by the code doing the wrong
 | 
			
		||||
	 * thing.
 | 
			
		||||
	 */
 | 
			
		||||
	if (base & (pagesize -1)) {
 | 
			
		||||
		die("Base address: %x is not page aligned\n", base);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	last = base + memsz -1;
 | 
			
		||||
	if (!valid_memory_range(base, last)) {
 | 
			
		||||
		die("Invalid memory segment %p - %p\n",
 | 
			
		||||
			(void *)base, (void *)last);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	size = (info->nr_segments + 1) * sizeof(info->segment[0]);
 | 
			
		||||
	info->segment = xrealloc(info->segment, size);
 | 
			
		||||
	info->segment[info->nr_segments].buf   = buf;
 | 
			
		||||
	info->segment[info->nr_segments].bufsz = bufsz;
 | 
			
		||||
	info->segment[info->nr_segments].mem   = (void *)base;
 | 
			
		||||
	info->segment[info->nr_segments].memsz = memsz;
 | 
			
		||||
	info->nr_segments++;
 | 
			
		||||
	if (info->nr_segments > KEXEC_MAX_SEGMENTS) {
 | 
			
		||||
		fprintf(stderr, 
 | 
			
		||||
			"Warning: kernel segment limit reached. This will likely fail\n");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned long add_buffer(struct kexec_info *info,
 | 
			
		||||
	const void *buf, unsigned long bufsz, unsigned long memsz,
 | 
			
		||||
	unsigned long buf_align, unsigned long buf_min, unsigned long buf_max,
 | 
			
		||||
	int buf_end)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long base;
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	result = sort_segments(info);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("sort_segments failed\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	base = locate_hole(info, memsz, buf_align, buf_min, buf_max, buf_end);
 | 
			
		||||
	if (base == ULONG_MAX) {
 | 
			
		||||
		die("locate_hole failed\n");
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	add_segment(info, buf, bufsz, base, memsz);
 | 
			
		||||
	return base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *slurp_file(const char *filename, off_t *r_size)
 | 
			
		||||
{
 | 
			
		||||
	int fd;
 | 
			
		||||
	char *buf;
 | 
			
		||||
	off_t size, progress;
 | 
			
		||||
	ssize_t result;
 | 
			
		||||
	struct stat stats;
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	if (!filename) {
 | 
			
		||||
		*r_size = 0;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	fd = open(filename, O_RDONLY);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		die("Cannot open `%s': %s\n",
 | 
			
		||||
			filename, strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
	result = fstat(fd, &stats);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("Cannot stat: %s: %s\n",
 | 
			
		||||
			filename, strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
	size = stats.st_size;
 | 
			
		||||
	*r_size = size;
 | 
			
		||||
	buf = xmalloc(size);
 | 
			
		||||
	progress = 0;
 | 
			
		||||
	while(progress < size) {
 | 
			
		||||
		result = read(fd, buf + progress, size - progress);
 | 
			
		||||
		if (result < 0) {
 | 
			
		||||
			if ((errno == EINTR) ||	(errno == EAGAIN))
 | 
			
		||||
				continue;
 | 
			
		||||
			die("read on %s of %ld bytes failed: %s\n",
 | 
			
		||||
				filename, (size - progress)+ 0UL, strerror(errno));
 | 
			
		||||
		}
 | 
			
		||||
		progress += result;
 | 
			
		||||
	}
 | 
			
		||||
	result = close(fd);
 | 
			
		||||
	if (result < 0) {
 | 
			
		||||
		die("Close of %s failed: %s\n",
 | 
			
		||||
			filename, strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if HAVE_ZLIB_H
 | 
			
		||||
char *slurp_decompress_file(const char *filename, off_t *r_size)
 | 
			
		||||
{
 | 
			
		||||
	gzFile fp;
 | 
			
		||||
	int errnum;
 | 
			
		||||
	const char *msg;
 | 
			
		||||
	char *buf;
 | 
			
		||||
	off_t size, allocated;
 | 
			
		||||
	ssize_t result;
 | 
			
		||||
 | 
			
		||||
	if (!filename) {
 | 
			
		||||
		*r_size = 0;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	fp = gzopen(filename, "rb");
 | 
			
		||||
	if (fp == 0) {
 | 
			
		||||
		msg = gzerror(fp, &errnum);
 | 
			
		||||
		if (errnum == Z_ERRNO) {
 | 
			
		||||
			msg = strerror(errno);
 | 
			
		||||
		}
 | 
			
		||||
		die("Cannot open `%s': %s\n", filename, msg);
 | 
			
		||||
	}
 | 
			
		||||
	size = 0;
 | 
			
		||||
	allocated = 65536;
 | 
			
		||||
	buf = xmalloc(allocated);
 | 
			
		||||
	do {
 | 
			
		||||
		if (size == allocated) {
 | 
			
		||||
			allocated <<= 1;
 | 
			
		||||
			buf = xrealloc(buf, allocated);
 | 
			
		||||
		}
 | 
			
		||||
		result = gzread(fp, buf + size, allocated - size);
 | 
			
		||||
		if (result < 0) {
 | 
			
		||||
			if ((errno == EINTR) || (errno == EAGAIN))
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			msg = gzerror(fp, &errnum);
 | 
			
		||||
			if (errnum == Z_ERRNO) {
 | 
			
		||||
				msg = strerror(errno);
 | 
			
		||||
			}
 | 
			
		||||
			die ("read on %s of %ld bytes failed: %s\n",
 | 
			
		||||
				filename, (allocated - size) + 0UL, msg);
 | 
			
		||||
		}
 | 
			
		||||
		size += result;
 | 
			
		||||
	} while(result > 0);
 | 
			
		||||
	result = gzclose(fp);
 | 
			
		||||
	if (result != Z_OK) {
 | 
			
		||||
		msg = gzerror(fp, &errnum);
 | 
			
		||||
		if (errnum == Z_ERRNO) {
 | 
			
		||||
			msg = strerror(errno);
 | 
			
		||||
		}
 | 
			
		||||
		die ("Close of %s failed: %s\n", filename, msg);
 | 
			
		||||
	}
 | 
			
		||||
	*r_size =  size;
 | 
			
		||||
	return buf;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
char *slurp_decompress_file(const char *filename, off_t *r_size)
 | 
			
		||||
{
 | 
			
		||||
	return slurp_file(filename, r_size);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void update_purgatory(struct kexec_info *info)
 | 
			
		||||
{
 | 
			
		||||
	static const uint8_t null_buf[256];
 | 
			
		||||
	sha256_context ctx;
 | 
			
		||||
	sha256_digest_t digest;
 | 
			
		||||
	struct sha256_region region[SHA256_REGIONS];
 | 
			
		||||
	int i, j;
 | 
			
		||||
	/* Don't do anything if we are not using purgatory */
 | 
			
		||||
	if (!info->rhdr.e_shdr) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	arch_update_purgatory(info);
 | 
			
		||||
	memset(region, 0, sizeof(region));
 | 
			
		||||
	sha256_starts(&ctx);
 | 
			
		||||
	/* Compute a hash of the loaded kernel */
 | 
			
		||||
	for(j = i = 0; i < info->nr_segments; i++) {
 | 
			
		||||
		unsigned long nullsz;
 | 
			
		||||
		/* Don't include purgatory in the checksum.  The stack
 | 
			
		||||
		 * in the bss will definitely change, and the .data section
 | 
			
		||||
		 * will also change when we poke the sha256_digest in there.
 | 
			
		||||
		 * A very clever/careful person could probably improve this.
 | 
			
		||||
		 */
 | 
			
		||||
		if (info->segment[i].mem == (void *)info->rhdr.rel_addr) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		sha256_update(&ctx, info->segment[i].buf, info->segment[i].bufsz);
 | 
			
		||||
		nullsz = info->segment[i].memsz - info->segment[i].bufsz;
 | 
			
		||||
		while(nullsz) {
 | 
			
		||||
			unsigned long bytes = nullsz;
 | 
			
		||||
			if (bytes > sizeof(null_buf)) {
 | 
			
		||||
				bytes = sizeof(null_buf);
 | 
			
		||||
			}
 | 
			
		||||
			sha256_update(&ctx, null_buf, bytes);
 | 
			
		||||
			nullsz -= bytes;
 | 
			
		||||
		}
 | 
			
		||||
		region[j].start = info->segment[i].mem;
 | 
			
		||||
		region[j].len   = info->segment[i].memsz;
 | 
			
		||||
		j++;
 | 
			
		||||
	}
 | 
			
		||||
	sha256_finish(&ctx, digest);
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "sha256_regions", ®ion, sizeof(region));
 | 
			
		||||
	elf_rel_set_symbol(&info->rhdr, "sha256_digest", &digest, sizeof(digest));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	Load the new kernel
 | 
			
		||||
 */
 | 
			
		||||
static int my_load(const char *type, int fileind, int argc, char **argv,
 | 
			
		||||
	unsigned long kexec_flags)
 | 
			
		||||
{
 | 
			
		||||
	char *kernel;
 | 
			
		||||
	char *kernel_buf;
 | 
			
		||||
	off_t kernel_size;
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	int result;
 | 
			
		||||
	struct kexec_info info;
 | 
			
		||||
	int guess_only = 0;
 | 
			
		||||
 | 
			
		||||
	memset(&info, 0, sizeof(info));
 | 
			
		||||
	info.segment = NULL;
 | 
			
		||||
	info.nr_segments = 0;
 | 
			
		||||
	info.entry = NULL;
 | 
			
		||||
 | 
			
		||||
	result = 0;
 | 
			
		||||
	if (argc - fileind <= 0) {
 | 
			
		||||
		fprintf(stderr, "No kernel specified\n");
 | 
			
		||||
		usage();
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	kernel = argv[fileind];
 | 
			
		||||
	/* slurp in the input kernel */
 | 
			
		||||
	kernel_buf = slurp_decompress_file(kernel, &kernel_size);
 | 
			
		||||
#if 0
 | 
			
		||||
	fprintf(stderr, "kernel: %p kernel_size: %lx\n", 
 | 
			
		||||
		kernel_buf, kernel_size);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (get_memory_ranges(&memory_range, &memory_ranges) < 0) {
 | 
			
		||||
		fprintf(stderr, "Could not get memory layout\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* if a kernel type was specified, try to honor it */
 | 
			
		||||
	if (type) {
 | 
			
		||||
		for (i = 0; i < file_types; i++) {
 | 
			
		||||
			if (strcmp(type, file_type[i].name) == 0)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		if (i == file_types) {
 | 
			
		||||
			fprintf(stderr, "Unsupported kernel type %s\n", type);
 | 
			
		||||
			return -1;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* make sure our file is really of that type */
 | 
			
		||||
			if (file_type[i].probe(kernel_buf, kernel_size) < 0)
 | 
			
		||||
				guess_only = 1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (!type || guess_only) {
 | 
			
		||||
		for (i = 0; i < file_types; i++) {
 | 
			
		||||
			if (file_type[i].probe(kernel_buf, kernel_size) >= 0)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		if (i == file_types) {
 | 
			
		||||
			fprintf(stderr, "Cannot determine the file type "
 | 
			
		||||
					"of %s\n", kernel);
 | 
			
		||||
			return -1;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (guess_only) {
 | 
			
		||||
				fprintf(stderr, "Wrong file type %s, "
 | 
			
		||||
					"file matches type %s\n",
 | 
			
		||||
					type, file_type[i].name);
 | 
			
		||||
				return -1;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (file_type[i].load(argc, argv, kernel_buf, kernel_size, &info) < 0) {
 | 
			
		||||
		fprintf(stderr, "Cannot load %s\n", kernel);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* If we are not in native mode setup an appropriate trampoline */
 | 
			
		||||
	if (arch_compat_trampoline(&info, &kexec_flags) < 0) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* Verify all of the segments load to a valid location in memory */
 | 
			
		||||
	for (i = 0; i < info.nr_segments; i++) {
 | 
			
		||||
		if (!valid_memory_segment(info.segment +i)) {
 | 
			
		||||
			fprintf(stderr, "Invalid memory segment %p - %p\n",
 | 
			
		||||
				info.segment[i].mem,
 | 
			
		||||
				((char *)info.segment[i].mem) + 
 | 
			
		||||
				info.segment[i].memsz);
 | 
			
		||||
			return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* Sort the segments and verify we don't have overlaps */
 | 
			
		||||
	if (sort_segments(&info) < 0) {
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	/* if purgatory is loaded update it */
 | 
			
		||||
	update_purgatory(&info);
 | 
			
		||||
#if 0
 | 
			
		||||
	fprintf(stderr, "kexec_load: entry = %p flags = %lx\n", 
 | 
			
		||||
		info.entry, kexec_flags);
 | 
			
		||||
	print_segments(stderr, &info);
 | 
			
		||||
#endif
 | 
			
		||||
	result = kexec_load(
 | 
			
		||||
		info.entry, info.nr_segments, info.segment, kexec_flags);
 | 
			
		||||
	if (result != 0) {
 | 
			
		||||
		/* The load failed, print some debugging information */
 | 
			
		||||
		fprintf(stderr, "kexec_load failed: %s\n", 
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
		fprintf(stderr, "entry       = %p flags = %lx\n", 
 | 
			
		||||
			info.entry, kexec_flags);
 | 
			
		||||
		print_segments(stderr, &info);
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int k_unload (unsigned long kexec_flags)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	result = kexec_load(NULL, 0, NULL, kexec_flags);
 | 
			
		||||
	if (result != 0) {
 | 
			
		||||
		/* The unload failed, print some debugging information */
 | 
			
		||||
		fprintf(stderr, "kexec_load (0 segments) failed: %s\n",
 | 
			
		||||
			strerror(errno));
 | 
			
		||||
	}
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	Start a reboot.
 | 
			
		||||
 */
 | 
			
		||||
static int my_shutdown(void)
 | 
			
		||||
{
 | 
			
		||||
	char *args[8];
 | 
			
		||||
	int i = 0;
 | 
			
		||||
 | 
			
		||||
	args[i++] = "shutdown";
 | 
			
		||||
	args[i++] = "-r";
 | 
			
		||||
	args[i++] = "now";
 | 
			
		||||
	args[i++] = NULL;
 | 
			
		||||
 | 
			
		||||
	execv("/sbin/shutdown", args);
 | 
			
		||||
	execv("/etc/shutdown", args);
 | 
			
		||||
	execv("/bin/shutdown", args);
 | 
			
		||||
 | 
			
		||||
	perror("shutdown");
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *	Exec the new kernel (reboot)
 | 
			
		||||
 */
 | 
			
		||||
static int my_exec(void)
 | 
			
		||||
{
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	result = kexec_reboot();
 | 
			
		||||
	/* I have failed if I make it here */
 | 
			
		||||
	fprintf(stderr, "kexec failed: %s\n", 
 | 
			
		||||
		strerror(errno));
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void version(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("kexec " VERSION " released " RELEASE_DATE "\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usage(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	version();
 | 
			
		||||
	printf(
 | 
			
		||||
		"Usage: kexec [OPTION]... [kernel]\n"
 | 
			
		||||
		"Directly reboot into a new kernel\n"
 | 
			
		||||
		"\n"
 | 
			
		||||
		" -h, --help           Print this help.\n"
 | 
			
		||||
		" -v, --version        Print the version of kexec.\n"
 | 
			
		||||
		" -f, --force          Force an immediate kexec, don't call shutdown.\n"
 | 
			
		||||
		" -x, --no-ifdown      Don't bring down network interfaces.\n"
 | 
			
		||||
		"                      (if used, must be last option specified)\n"
 | 
			
		||||
		" -l, --load           Load the new kernel into the current kernel.\n"
 | 
			
		||||
		" -p, --load-panic     Load the new kernel for use on panic.\n"
 | 
			
		||||
		" -u, --unload         Unload the current kexec target kernel.\n"
 | 
			
		||||
		" -e, --exec           Execute a currently loaded kernel.\n"
 | 
			
		||||
		" -t, --type=TYPE      Specify the new kernel is of this type.\n"
 | 
			
		||||
		"     --mem-min=<addr> Specify the lowest memory addres to load code into.\n"
 | 
			
		||||
		"     --mem-max=<addr> Specify the highest memory addres to load code into.\n"
 | 
			
		||||
		"\n"
 | 
			
		||||
		"Supported kernel file types and options: \n"
 | 
			
		||||
		);
 | 
			
		||||
	for (i = 0; i < file_types; i++) {
 | 
			
		||||
		printf("%s\n", file_type[i].name);
 | 
			
		||||
		file_type[i].usage();
 | 
			
		||||
	}
 | 
			
		||||
	printf(	"Architecture options: \n");
 | 
			
		||||
	arch_usage();
 | 
			
		||||
	printf("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	int do_load = 1;
 | 
			
		||||
	int do_exec = 0;
 | 
			
		||||
	int do_shutdown = 1;
 | 
			
		||||
	int do_sync = 1;
 | 
			
		||||
	int do_ifdown = 0;
 | 
			
		||||
	int do_unload = 0;
 | 
			
		||||
	unsigned long kexec_flags = 0;
 | 
			
		||||
	char *type = 0;
 | 
			
		||||
	char *endptr;
 | 
			
		||||
	int opt;
 | 
			
		||||
	int result = 0;
 | 
			
		||||
	int fileind;
 | 
			
		||||
	static const struct option options[] = {
 | 
			
		||||
		KEXEC_OPTIONS
 | 
			
		||||
		{ 0, 0, 0, 0},
 | 
			
		||||
	};
 | 
			
		||||
	static const char short_options[] = KEXEC_OPT_STR;
 | 
			
		||||
 | 
			
		||||
	opterr = 0; /* Don't complain about unrecognized options here */
 | 
			
		||||
	while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) {
 | 
			
		||||
		switch(opt) {
 | 
			
		||||
		case OPT_HELP:
 | 
			
		||||
			usage();
 | 
			
		||||
			return 0;
 | 
			
		||||
		case OPT_VERSION:
 | 
			
		||||
			version();
 | 
			
		||||
			return 0;
 | 
			
		||||
		case OPT_NOIFDOWN:
 | 
			
		||||
			do_ifdown = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_FORCE:
 | 
			
		||||
			do_load = 1;
 | 
			
		||||
			do_shutdown = 0;
 | 
			
		||||
			do_sync = 1;
 | 
			
		||||
			do_ifdown = 1;
 | 
			
		||||
			do_exec = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_LOAD:
 | 
			
		||||
			do_load = 1;
 | 
			
		||||
			do_exec = 0;
 | 
			
		||||
			do_shutdown = 0;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_UNLOAD:
 | 
			
		||||
			do_load = 0;
 | 
			
		||||
			do_shutdown = 0;
 | 
			
		||||
			do_sync = 0;
 | 
			
		||||
			do_unload = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_EXEC:
 | 
			
		||||
			do_load = 0;
 | 
			
		||||
			do_shutdown = 0;
 | 
			
		||||
			do_sync = 1;
 | 
			
		||||
			do_ifdown = 1;
 | 
			
		||||
			do_exec = 1;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_TYPE:
 | 
			
		||||
			type = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_PANIC:
 | 
			
		||||
			do_load = 1;
 | 
			
		||||
			do_exec = 0;
 | 
			
		||||
			do_shutdown = 0;
 | 
			
		||||
			do_sync = 0;
 | 
			
		||||
			kexec_flags = KEXEC_ON_CRASH;
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_MEM_MIN:
 | 
			
		||||
			mem_min = strtoul(optarg, &endptr, 0);
 | 
			
		||||
			if (*endptr) {
 | 
			
		||||
				fprintf(stderr, "Bad option value in --mem-min=%s\n",
 | 
			
		||||
					optarg);
 | 
			
		||||
				usage();
 | 
			
		||||
				return 1;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case OPT_MEM_MAX:
 | 
			
		||||
			mem_max = strtoul(optarg, &endptr, 0);
 | 
			
		||||
			if (*endptr) {
 | 
			
		||||
				fprintf(stderr, "Bad option value in --mem-max=%s\n",
 | 
			
		||||
					optarg);
 | 
			
		||||
				usage();
 | 
			
		||||
				return 1;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fileind = optind;
 | 
			
		||||
	/* Reset getopt for the next pass; called in other source modules */
 | 
			
		||||
	opterr = 1;
 | 
			
		||||
	optind = 1;
 | 
			
		||||
 | 
			
		||||
	result = arch_process_options(argc, argv);
 | 
			
		||||
 | 
			
		||||
	if (do_unload) {
 | 
			
		||||
		result = k_unload(kexec_flags);
 | 
			
		||||
	}
 | 
			
		||||
	if (do_load && (result == 0)) {
 | 
			
		||||
		result = my_load(type, fileind, argc, argv, kexec_flags);
 | 
			
		||||
	}
 | 
			
		||||
	if ((result == 0) && do_shutdown) {
 | 
			
		||||
		result = my_shutdown();
 | 
			
		||||
	}
 | 
			
		||||
	if ((result == 0) && do_sync) {
 | 
			
		||||
		sync();
 | 
			
		||||
	}
 | 
			
		||||
	if ((result == 0) && do_ifdown) {
 | 
			
		||||
		extern int ifdown(void);
 | 
			
		||||
		(void)ifdown();
 | 
			
		||||
	}
 | 
			
		||||
	if ((result == 0) && do_exec) {
 | 
			
		||||
		result = my_exec();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fflush(stdout);
 | 
			
		||||
	fflush(stderr);
 | 
			
		||||
	return result;
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										194
									
								
								kexec/kexec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								kexec/kexec.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,194 @@
 | 
			
		||||
#ifndef KEXEC_H
 | 
			
		||||
#define KEXEC_H
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#define USE_BSD
 | 
			
		||||
#include <byteswap.h>
 | 
			
		||||
#include <endian.h>
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
 | 
			
		||||
#include "kexec-elf.h"
 | 
			
		||||
 | 
			
		||||
#ifndef BYTE_ORDER
 | 
			
		||||
#error BYTE_ORDER not defined
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef LITTLE_ENDIAN
 | 
			
		||||
#error LITTLE_ENDIAN not defined
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef BIG_ENDIAN
 | 
			
		||||
#error BIG_ENDIAN not defined
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if BYTE_ORDER == LITTLE_ENDIAN
 | 
			
		||||
#define cpu_to_le16(val) (val)
 | 
			
		||||
#define cpu_to_le32(val) (val)
 | 
			
		||||
#define cpu_to_le64(val) (val)
 | 
			
		||||
#define cpu_to_be16(val) bswap_16(val)
 | 
			
		||||
#define cpu_to_be32(val) bswap_32(val)
 | 
			
		||||
#define cpu_to_be64(val) bswap_64(val)
 | 
			
		||||
#define le16_to_cpu(val) (val)
 | 
			
		||||
#define le32_to_cpu(val) (val)
 | 
			
		||||
#define le64_to_cpu(val) (val)
 | 
			
		||||
#define be16_to_cpu(val) bswap_16(val)
 | 
			
		||||
#define be32_to_cpu(val) bswap_32(val)
 | 
			
		||||
#define be64_to_cpu(val) bswap_64(val)
 | 
			
		||||
#elif BYTE_ORDER == BIG_ENDIAN
 | 
			
		||||
#define cpu_to_le16(val) bswap_16(val)
 | 
			
		||||
#define cpu_to_le32(val) bswap_32(val)
 | 
			
		||||
#define cpu_to_le64(val) bswap_64(val)
 | 
			
		||||
#define cpu_to_be16(val) (val)
 | 
			
		||||
#define cpu_to_be32(val) (val)
 | 
			
		||||
#define cpu_to_be64(val) (val)
 | 
			
		||||
#define le16_to_cpu(val) bswap_16(val)
 | 
			
		||||
#define le32_to_cpu(val) bswap_32(val)
 | 
			
		||||
#define le64_to_cpu(val) bswap_64(val)
 | 
			
		||||
#define be16_to_cpu(val) (val)
 | 
			
		||||
#define be32_to_cpu(val) (val)
 | 
			
		||||
#define be64_to_cpu(val) (val)
 | 
			
		||||
#else
 | 
			
		||||
#error unknwon BYTE_ORDER
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
/*
 | 
			
		||||
 * This function doesn't actually exist.  The idea is that when someone uses the macros
 | 
			
		||||
 * below with an unsupported size (datatype), the linker will alert us to the problem via
 | 
			
		||||
 * an unresolved reference error.
 | 
			
		||||
 */
 | 
			
		||||
extern unsigned long bad_unaligned_access_length (void);
 | 
			
		||||
 | 
			
		||||
#define get_unaligned(loc) \
 | 
			
		||||
({ \
 | 
			
		||||
	__typeof__(*(loc)) value; \
 | 
			
		||||
	size_t size = sizeof(*(loc)); \
 | 
			
		||||
	switch(size) {  \
 | 
			
		||||
	case 1: case 2: case 4: case 8: \
 | 
			
		||||
		memcpy(&value, (loc), size); \
 | 
			
		||||
		break; \
 | 
			
		||||
	default: \
 | 
			
		||||
		value = bad_unaligned_access_length(); \
 | 
			
		||||
		break; \
 | 
			
		||||
	} \
 | 
			
		||||
	value; \
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
#define put_unaligned(value, loc) \
 | 
			
		||||
do { \
 | 
			
		||||
	size_t size = sizeof(*(loc)); \
 | 
			
		||||
	__typeof__(*(loc)) val = value; \
 | 
			
		||||
	switch(size) { \
 | 
			
		||||
	case 1: case 2: case 4: case 8: \
 | 
			
		||||
		memcpy((loc), &val, size); \
 | 
			
		||||
		break; \
 | 
			
		||||
	default: \
 | 
			
		||||
		bad_unaligned_access_length(); \
 | 
			
		||||
		break; \
 | 
			
		||||
	} \
 | 
			
		||||
} while(0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct kexec_segment {
 | 
			
		||||
	const void *buf;
 | 
			
		||||
	size_t bufsz;
 | 
			
		||||
	const void *mem;
 | 
			
		||||
	size_t memsz;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct memory_range {
 | 
			
		||||
	unsigned long long start, end;
 | 
			
		||||
	unsigned type;
 | 
			
		||||
#define RANGE_RAM	0
 | 
			
		||||
#define RANGE_RESERVED	1
 | 
			
		||||
#define RANGE_ACPI	2
 | 
			
		||||
#define RANGE_ACPI_NVS	3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct kexec_info {
 | 
			
		||||
	struct kexec_segment *segment;
 | 
			
		||||
	int nr_segments;
 | 
			
		||||
	void *entry;
 | 
			
		||||
	struct mem_ehdr rhdr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void usage(void);
 | 
			
		||||
int get_memory_ranges(struct memory_range **range, int *ranges);
 | 
			
		||||
int valid_memory_range(unsigned long sstart, unsigned long send);
 | 
			
		||||
int valid_memory_segment(struct kexec_segment *segment);
 | 
			
		||||
void print_segments(FILE *file, struct kexec_info *info);
 | 
			
		||||
int sort_segments(struct kexec_info *info);
 | 
			
		||||
unsigned long locate_hole(struct kexec_info *info,
 | 
			
		||||
	unsigned long hole_size, unsigned long hole_align, 
 | 
			
		||||
	unsigned long hole_min, unsigned long hole_max,
 | 
			
		||||
	int hole_end);
 | 
			
		||||
 | 
			
		||||
typedef int (probe_t)(const char *kernel_buf, off_t kernel_size);
 | 
			
		||||
typedef int (load_t )(int argc, char **argv,
 | 
			
		||||
	const char *kernel_buf, off_t kernel_size, 
 | 
			
		||||
	struct kexec_info *info);
 | 
			
		||||
typedef void (usage_t)(void);
 | 
			
		||||
struct file_type {
 | 
			
		||||
	const char *name;
 | 
			
		||||
	probe_t *probe;
 | 
			
		||||
	load_t  *load;
 | 
			
		||||
	usage_t *usage;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern struct file_type file_type[];
 | 
			
		||||
extern int file_types;
 | 
			
		||||
 | 
			
		||||
#define OPT_HELP		'h'
 | 
			
		||||
#define OPT_VERSION		'v'
 | 
			
		||||
#define OPT_DEBUG		'd'
 | 
			
		||||
#define OPT_FORCE		'f'
 | 
			
		||||
#define OPT_NOIFDOWN		'x'
 | 
			
		||||
#define OPT_EXEC		'e'
 | 
			
		||||
#define OPT_LOAD		'l'
 | 
			
		||||
#define OPT_UNLOAD		'u'
 | 
			
		||||
#define OPT_TYPE		't'
 | 
			
		||||
#define OPT_PANIC		'p'
 | 
			
		||||
#define OPT_MEM_MIN             256
 | 
			
		||||
#define OPT_MEM_MAX             257
 | 
			
		||||
#define OPT_MAX			258
 | 
			
		||||
#define KEXEC_OPTIONS \
 | 
			
		||||
	{ "help",		0, 0, OPT_HELP }, \
 | 
			
		||||
	{ "version",		0, 0, OPT_VERSION }, \
 | 
			
		||||
	{ "force",		0, 0, OPT_FORCE }, \
 | 
			
		||||
	{ "no-ifdown",		0, 0, OPT_NOIFDOWN }, \
 | 
			
		||||
	{ "load",		0, 0, OPT_LOAD }, \
 | 
			
		||||
	{ "unload",		0, 0, OPT_UNLOAD }, \
 | 
			
		||||
	{ "exec",		0, 0, OPT_EXEC }, \
 | 
			
		||||
	{ "type",		1, 0, OPT_TYPE }, \
 | 
			
		||||
	{ "load-panic",         0, 0, OPT_PANIC }, \
 | 
			
		||||
	{ "mem-min",		1, 0, OPT_MEM_MIN }, \
 | 
			
		||||
	{ "mem-max",		1, 0, OPT_MEM_MAX }, \
 | 
			
		||||
 | 
			
		||||
#define KEXEC_OPT_STR "hvdfxluet:p"
 | 
			
		||||
 | 
			
		||||
extern void die(char *fmt, ...);
 | 
			
		||||
extern void *xmalloc(size_t size);
 | 
			
		||||
extern void *xrealloc(void *ptr, size_t size);
 | 
			
		||||
extern char *slurp_file(const char *filename, off_t *r_size);
 | 
			
		||||
extern char *slurp_decompress_file(const char *filename, off_t *r_size);
 | 
			
		||||
extern void add_segment(struct kexec_info *info,
 | 
			
		||||
	const void *buf, size_t bufsz, unsigned long base, size_t memsz);
 | 
			
		||||
extern unsigned long add_buffer(struct kexec_info *info,
 | 
			
		||||
	const void *buf, unsigned long bufsz, unsigned long memsz,
 | 
			
		||||
	unsigned long buf_align, unsigned long buf_min, unsigned long buf_max,
 | 
			
		||||
	int buf_end);
 | 
			
		||||
 | 
			
		||||
extern unsigned char purgatory[];
 | 
			
		||||
extern size_t purgatory_size;
 | 
			
		||||
 | 
			
		||||
#define BOOTLOADER "kexec"
 | 
			
		||||
#define BOOTLOADER_VERSION VERSION
 | 
			
		||||
 | 
			
		||||
void arch_usage(void);
 | 
			
		||||
int arch_process_options(int argc, char **argv);
 | 
			
		||||
int arch_compat_trampoline(struct kexec_info *info, unsigned long *flags);
 | 
			
		||||
void arch_update_purgatory(struct kexec_info *info);
 | 
			
		||||
 | 
			
		||||
#endif /* KEXEC_H */
 | 
			
		||||
							
								
								
									
										30
									
								
								kexec_test/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								kexec_test/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
#
 | 
			
		||||
# kexec_test Debugging payload to be certain the infrastructure works
 | 
			
		||||
#
 | 
			
		||||
RELOC:=0x10000
 | 
			
		||||
KEXEC_TEST_S_SRCS:= kexec_test/kexec_test16.S kexec_test/kexec_test.S
 | 
			
		||||
KEXEC_TEST_S_TEMPS:=$(patsubst %.S, $(OBJDIR)/%.s, $(KEXEC_TEST_S_SRCS))
 | 
			
		||||
KEXEC_TEST_S_OBJS:=$(patsubst $(OBJDIR)/%.s, $(OBJDIR)/%.o, $(KEXEC_TEST_S_TEMPS))
 | 
			
		||||
KEXEC_TEST_S_DEPS:=$(patsubst %.S, $(OBJDIR)/%.d, $(KEXEC_TEST_S_SRCS))
 | 
			
		||||
KEXEC_TEST_SRCS:= $(KEXEC_TEST_S_SRCS)
 | 
			
		||||
KEXEC_TEST_OBJS:= $(KEXEC_TEST_S_OBJS)
 | 
			
		||||
KEXEC_TEST_DEPS:= $(KEXEC_TEST_S_DEPS)
 | 
			
		||||
KEXEC_TEST:=$(PKGLIBDIR)/kexec_test
 | 
			
		||||
 | 
			
		||||
include $(KEXEC_TEST_DEPS)
 | 
			
		||||
 | 
			
		||||
$(KEXEC_TEST_S_DEPS): $(OBJDIR)/%.d: %.S
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CC) -m32 $(CFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
 | 
			
		||||
 | 
			
		||||
$(KEXEC_TEST_S_TEMPS): $(OBJDIR)/%.s: %.S 
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(CPP) $(CPPFLAGS) -DRELOC=$(RELOC) $< > $@
 | 
			
		||||
 | 
			
		||||
$(KEXEC_TEST_S_OBJS): $(OBJDIR)/%.o: $(OBJDIR)/%.s 
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(AS) --32 -o $@ $<
 | 
			
		||||
 | 
			
		||||
$(KEXEC_TEST): $(KEXEC_TEST_OBJS) 
 | 
			
		||||
	mkdir -p $(@D)
 | 
			
		||||
	$(LD) -m elf_i386 -e _start -Ttext $(RELOC) $(KEXEC_TEST_OBJS) -o $@
 | 
			
		||||
							
								
								
									
										475
									
								
								kexec_test/kexec_test.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										475
									
								
								kexec_test/kexec_test.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,475 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	.equ	PROT_CODE_SEG, pmcs - gdt
 | 
			
		||||
	.equ	REAL_CODE_SEG, rmcs - gdt
 | 
			
		||||
 	.equ	PROT_DATA_SEG, pmds - gdt
 | 
			
		||||
 	.equ	REAL_DATA_SEG, rmds - gdt
 | 
			
		||||
	.equ	CR0_PE, 1
 | 
			
		||||
	/* Gas thinks the .equs for these are non-absolute so use a define */
 | 
			
		||||
#define	PROT_CODE_SEG 0x08
 | 
			
		||||
#define REAL_CODE_SEG 0x18
 | 
			
		||||
#undef i386
 | 
			
		||||
 | 
			
		||||
	.text
 | 
			
		||||
	.arch	i386
 | 
			
		||||
	.globl _start
 | 
			
		||||
_start:
 | 
			
		||||
	.code32
 | 
			
		||||
	# Disable interrupts 
 | 
			
		||||
	cli
 | 
			
		||||
	
 | 
			
		||||
	# Save the initial registers 
 | 
			
		||||
	movl	%eax, orig_eax
 | 
			
		||||
	movl	%ebx, orig_ebx
 | 
			
		||||
	movl	%ecx, orig_ecx
 | 
			
		||||
	movl	%edx, orig_edx
 | 
			
		||||
	movl	%esi, orig_esi
 | 
			
		||||
	movl	%edi, orig_edi
 | 
			
		||||
	movl	%esp, orig_esp
 | 
			
		||||
	movl	%ebp, orig_ebp
 | 
			
		||||
 | 
			
		||||
	# Setup a stack 
 | 
			
		||||
	movl	$stack_end, %esp
 | 
			
		||||
 | 
			
		||||
	# Display a message to say everything is working so far 
 | 
			
		||||
	pushl	$s_hello
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$4, %esp
 | 
			
		||||
 | 
			
		||||
	# Save the idt and gdt 
 | 
			
		||||
	sidt	orig_idtp
 | 
			
		||||
	sgdt	orig_gdtp
 | 
			
		||||
 | 
			
		||||
	# Display the initial register contents 
 | 
			
		||||
	call	print_orig_regs
 | 
			
		||||
 | 
			
		||||
	pushl	$s_switching_descriptors
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$4, %esp
 | 
			
		||||
 | 
			
		||||
	# Load descriptor pointers 
 | 
			
		||||
	lgdt	gdtp
 | 
			
		||||
	lidt	idtp
 | 
			
		||||
	# Reload the data segments
 | 
			
		||||
	movl	$PROT_DATA_SEG, %eax
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	# Reload %cs 
 | 
			
		||||
	ljmp	$PROT_CODE_SEG, $_start.1
 | 
			
		||||
_start.1:
 | 
			
		||||
 | 
			
		||||
	pushl	$s_descriptors_changed
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$4, %esp
 | 
			
		||||
 | 
			
		||||
	call	setup_legacy_pic
 | 
			
		||||
	pushl	$s_legacy_pic_setup
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$4, %esp
 | 
			
		||||
	
 | 
			
		||||
	call	prot_to_real
 | 
			
		||||
	.code16
 | 
			
		||||
 | 
			
		||||
	callw	test16
 | 
			
		||||
 | 
			
		||||
	/* Return to 32bit mode */
 | 
			
		||||
	data32	call	real_to_prot
 | 
			
		||||
	.code32
 | 
			
		||||
	pushl	$s_in_protected_mode
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$4, %esp
 | 
			
		||||
 | 
			
		||||
	pushl	$s_halting
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$4, %esp
 | 
			
		||||
	jmp	halt
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	/* Go from protected to real mode */
 | 
			
		||||
prot_to_real:
 | 
			
		||||
	.code32
 | 
			
		||||
	/* Load the 16bit idt */
 | 
			
		||||
	lidt	idtp_real
 | 
			
		||||
	
 | 
			
		||||
	popl	%eax
 | 
			
		||||
	subl	$RELOC, %eax		/* Adjust return address */
 | 
			
		||||
	pushl	%eax
 | 
			
		||||
	subl	$RELOC, %esp		/* Adjust stack pointer */
 | 
			
		||||
	ljmp	$REAL_CODE_SEG, $1f - RELOC
 | 
			
		||||
1:
 | 
			
		||||
	.code16
 | 
			
		||||
	/* Reload the segment registers to force a 16bit limit */
 | 
			
		||||
	movw	$REAL_DATA_SEG, %ax
 | 
			
		||||
	movw	%ax, %ds
 | 
			
		||||
	movw	%ax, %es
 | 
			
		||||
	movw	%ax, %ss
 | 
			
		||||
	movw	%ax, %fs
 | 
			
		||||
	movw	%ax, %gs
 | 
			
		||||
	
 | 
			
		||||
	/* Clear the PE bit of CR0 */
 | 
			
		||||
	movl	%cr0, %eax
 | 
			
		||||
	andl	$0!CR0_PE, %eax
 | 
			
		||||
	movl	%eax, %cr0
 | 
			
		||||
 | 
			
		||||
	/* make intersegment jmp to flush the processor pipeline
 | 
			
		||||
	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
 | 
			
		||||
	 */
 | 
			
		||||
	data32 ljmp	$(RELOC)>>4,$2f- RELOC
 | 
			
		||||
2:
 | 
			
		||||
	/* we are in real mode now
 | 
			
		||||
	 * set up the real mode segment registers 
 | 
			
		||||
	 */
 | 
			
		||||
	movw	%cs,%ax
 | 
			
		||||
	movw	%ax,%ds
 | 
			
		||||
	movw	%ax,%es
 | 
			
		||||
	movw	%ax,%ss
 | 
			
		||||
	movw	%ax,%fs
 | 
			
		||||
	movw	%ax,%gs
 | 
			
		||||
	data32	ret
 | 
			
		||||
 | 
			
		||||
real_to_prot:
 | 
			
		||||
	.code16
 | 
			
		||||
	pushl	%ebx
 | 
			
		||||
 | 
			
		||||
	/* Compute the address of gdtp */
 | 
			
		||||
	movw	%cs, %ax
 | 
			
		||||
	shlw	$4, %ax
 | 
			
		||||
	movl	$gdtp, %ebx
 | 
			
		||||
	subw	%ax, %bx
 | 
			
		||||
	
 | 
			
		||||
	data32 lgdt %cs:(%bx)
 | 
			
		||||
	movl	%cr0, %eax
 | 
			
		||||
	orl	$CR0_PE, %eax
 | 
			
		||||
	movl	%eax, %cr0
 | 
			
		||||
 | 
			
		||||
	/* flush prefetch queue and reload %cs:%eip */
 | 
			
		||||
	data32 ljmp	$PROT_CODE_SEG, $1f
 | 
			
		||||
1:
 | 
			
		||||
	.code32
 | 
			
		||||
	/* reload other segment registers */
 | 
			
		||||
	movl	$PROT_DATA_SEG, %eax
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	popl	%ebx		/* Restore %ebx */
 | 
			
		||||
	
 | 
			
		||||
	addl	$RELOC, %esp	/* Fix up stack pointer */
 | 
			
		||||
 | 
			
		||||
	popl	%eax		/* Fix up return address */
 | 
			
		||||
	addl	$RELOC, %eax
 | 
			
		||||
	pushl	%eax
 | 
			
		||||
 | 
			
		||||
	lidt	idtp		/* Load a dummy idt */
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
halt:
 | 
			
		||||
	.code32
 | 
			
		||||
	hlt
 | 
			
		||||
	jmp	halt
 | 
			
		||||
 | 
			
		||||
print_orig_regs:
 | 
			
		||||
	.code32
 | 
			
		||||
	# Display the initial register contents 
 | 
			
		||||
	pushl	$s_eax
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_eax
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
	
 | 
			
		||||
	pushl	$s_ebx
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_ebx
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	pushl	$s_ecx
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_ecx
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	pushl	$s_edx
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_edx
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$crlf
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	pushl	$s_esi
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_esi
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
	
 | 
			
		||||
	pushl	$s_edi
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_edi
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	pushl	$s_esp
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_esp
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	pushl	$s_ebp
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_ebp
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$crlf
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$12, %esp
 | 
			
		||||
 | 
			
		||||
	# display the interrupt descritor table pointer 
 | 
			
		||||
	pushl	$s_idtp
 | 
			
		||||
	call	print_string
 | 
			
		||||
	movzwl	orig_idtp, %eax
 | 
			
		||||
	pushl	%eax
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_idt_base
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$crlf
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$20, %esp
 | 
			
		||||
 | 
			
		||||
	# display the global descritor table pointer 
 | 
			
		||||
	pushl	$s_gdtp
 | 
			
		||||
	call	print_string
 | 
			
		||||
	movzwl	orig_gdtp, %eax
 | 
			
		||||
	pushl	%eax
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$space
 | 
			
		||||
	call	print_string
 | 
			
		||||
	pushl	orig_gdt_base
 | 
			
		||||
	call	print_hex
 | 
			
		||||
	pushl	$crlf
 | 
			
		||||
	call	print_string
 | 
			
		||||
	addl	$20, %esp
 | 
			
		||||
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
print_string:
 | 
			
		||||
	.code32
 | 
			
		||||
	pushl	%ebp
 | 
			
		||||
	movl	%esp, %ebp
 | 
			
		||||
	pushl	%esi
 | 
			
		||||
	movl	8(%ebp), %esi
 | 
			
		||||
	xorl	%eax, %eax
 | 
			
		||||
print_string.1:	
 | 
			
		||||
	lodsb %ds:(%esi), %al
 | 
			
		||||
	testb	$0xff, %al
 | 
			
		||||
	jz	print_string.2
 | 
			
		||||
	call	print_char
 | 
			
		||||
	jmp	print_string.1
 | 
			
		||||
print_string.2:
 | 
			
		||||
	popl	%esi
 | 
			
		||||
	popl	%ebp
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
print_hex:
 | 
			
		||||
	.code32
 | 
			
		||||
	pushl	%ebp
 | 
			
		||||
	movl	%esp, %ebp
 | 
			
		||||
	movb	$32, %cl
 | 
			
		||||
print_hex.1:	
 | 
			
		||||
	movl	8(%ebp), %eax
 | 
			
		||||
	subb	$4, %cl
 | 
			
		||||
	shrl	%cl, %eax
 | 
			
		||||
	andb	$0x0f, %al
 | 
			
		||||
	cmpb	$9, %al
 | 
			
		||||
	ja	print_hex.2
 | 
			
		||||
	addb	$'0', %al
 | 
			
		||||
	jmp	print_hex.3
 | 
			
		||||
print_hex.2:	
 | 
			
		||||
	addb	$'A' - 10, %al
 | 
			
		||||
print_hex.3:
 | 
			
		||||
	pushl	%ecx
 | 
			
		||||
	call	print_char
 | 
			
		||||
	popl	%ecx
 | 
			
		||||
	testb	%cl, %cl
 | 
			
		||||
	jnz	print_hex.1
 | 
			
		||||
 | 
			
		||||
	popl	%ebp
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
print_char:
 | 
			
		||||
	.code32
 | 
			
		||||
	# The character to print is in al 
 | 
			
		||||
	call serial_print_char
 | 
			
		||||
	retl
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define TTYS0_BASE	0x3f8
 | 
			
		||||
#define TTYS0_RBR	(TTYS0_BASE + 0x00)
 | 
			
		||||
#define TTYS0_TBR	(TTYS0_BASE + 0x00)
 | 
			
		||||
#define TTYS0_LSR	(TTYS0_BASE + 0x05)
 | 
			
		||||
serial_print_char:
 | 
			
		||||
	.code32
 | 
			
		||||
	# The character to print is in al 
 | 
			
		||||
	pushl	%eax
 | 
			
		||||
	
 | 
			
		||||
	# Wait until the serial port is ready to receive characters 
 | 
			
		||||
serial_print_char.1:
 | 
			
		||||
	movl	$TTYS0_LSR, %edx
 | 
			
		||||
	inb	%dx, %al
 | 
			
		||||
	testb	$0x20, %al
 | 
			
		||||
	jz	serial_print_char.1
 | 
			
		||||
 | 
			
		||||
	# Output the character 
 | 
			
		||||
	movl	$TTYS0_TBR, %edx
 | 
			
		||||
	movb	0(%esp), %al
 | 
			
		||||
	outb	%al, %dx
 | 
			
		||||
 | 
			
		||||
	# Wait until the serial port has transmitted the character 
 | 
			
		||||
serial_print_char.2:
 | 
			
		||||
	movl	$TTYS0_LSR, %edx
 | 
			
		||||
	inb	%dx, %al
 | 
			
		||||
	testb	$0x40, %al
 | 
			
		||||
	jz	serial_print_char.2
 | 
			
		||||
 | 
			
		||||
	# Restore %eax 
 | 
			
		||||
	popl	%eax
 | 
			
		||||
	# Return to caller 
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
	.code32
 | 
			
		||||
 | 
			
		||||
idtp_real:
 | 
			
		||||
	.word	0x400				# idt limit = 256
 | 
			
		||||
	.word	0, 0
 | 
			
		||||
idtp:
 | 
			
		||||
	.word	0				# idt limit = 0
 | 
			
		||||
	.word	0, 0				# idt base = 0L
 | 
			
		||||
 | 
			
		||||
gdt:
 | 
			
		||||
gdtp:
 | 
			
		||||
	.word	gdt_end - gdt - 1		# gdt limit
 | 
			
		||||
	.long	gdt				# gdt base
 | 
			
		||||
	.word	0				# dummy
 | 
			
		||||
 | 
			
		||||
pmcs:
 | 
			
		||||
	# the 32 bit protected mode code segment 
 | 
			
		||||
	.word	0xffff,0
 | 
			
		||||
	.byte	0,0x9f,0xcf,0
 | 
			
		||||
 | 
			
		||||
pmds:
 | 
			
		||||
	# the 32 bit protected mode data segment 
 | 
			
		||||
	.word	0xffff,0
 | 
			
		||||
	.byte	0,0x93,0xcf,0
 | 
			
		||||
 | 
			
		||||
rmcs:
 | 
			
		||||
	# the 16 bit real mode code segment 
 | 
			
		||||
	.word	0xffff,(RELOC&0xffff)
 | 
			
		||||
	.byte	(RELOC>>16),0x9b,0x00,(RELOC>>24)
 | 
			
		||||
 | 
			
		||||
rmds:
 | 
			
		||||
	# the 16 bit real mode data segment 
 | 
			
		||||
	.word	0xffff,(RELOC&0xffff)
 | 
			
		||||
	.byte	(RELOC>>16),0x93,0x00,(RELOC>>24)
 | 
			
		||||
gdt_end:	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
s_hello:
 | 
			
		||||
	.ascii	"kexec_test "
 | 
			
		||||
	.ascii VERSION
 | 
			
		||||
	.asciz " starting...\r\n"
 | 
			
		||||
s_switching_descriptors:
 | 
			
		||||
	.asciz	"Switching descriptors.\r\n"
 | 
			
		||||
s_descriptors_changed:
 | 
			
		||||
	.asciz	"Descriptors changed.\r\n"
 | 
			
		||||
s_legacy_pic_setup:
 | 
			
		||||
	.asciz	"Legacy pic setup.\r\n"
 | 
			
		||||
s_in_protected_mode:
 | 
			
		||||
	.asciz	"In protected mode.\r\n"
 | 
			
		||||
s_halting:
 | 
			
		||||
	.asciz	"Halting.\r\n"
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
space:	.asciz	" "
 | 
			
		||||
crlf:	.asciz	"\r\n"
 | 
			
		||||
s_eax:	.asciz	"eax: "
 | 
			
		||||
s_ebx:	.asciz	"ebx: "
 | 
			
		||||
s_ecx:	.asciz	"ecx: "
 | 
			
		||||
s_edx:	.asciz	"edx: "
 | 
			
		||||
s_esi:	.asciz	"esi: "
 | 
			
		||||
s_edi:	.asciz	"edi: "
 | 
			
		||||
s_esp:	.asciz	"esp: "
 | 
			
		||||
s_ebp:	.asciz	"ebp: "
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
s_idtp:	.asciz	"idt: "
 | 
			
		||||
s_gdtp:	.asciz	"gdt: "
 | 
			
		||||
 | 
			
		||||
#include "x86-setup-legacy-pic.S"
 | 
			
		||||
 | 
			
		||||
	.bss
 | 
			
		||||
	.balign 4096
 | 
			
		||||
stack:
 | 
			
		||||
	.skip 4096
 | 
			
		||||
stack_end:	
 | 
			
		||||
	
 | 
			
		||||
	.bss
 | 
			
		||||
	.balign 4	
 | 
			
		||||
orig_eax:	.long 0
 | 
			
		||||
orig_ebx:	.long 0
 | 
			
		||||
orig_ecx:	.long 0
 | 
			
		||||
orig_edx:	.long 0
 | 
			
		||||
orig_esi:	.long 0
 | 
			
		||||
orig_edi:	.long 0
 | 
			
		||||
orig_esp:	.long 0
 | 
			
		||||
orig_ebp:	.long 0
 | 
			
		||||
 | 
			
		||||
	.balign 4
 | 
			
		||||
orig_idtp:	.short 0
 | 
			
		||||
orig_idt_base:	.long  0
 | 
			
		||||
orig_gdtp:	.short 0
 | 
			
		||||
orig_gdt_base:	.long  0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1004
									
								
								kexec_test/kexec_test16.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1004
									
								
								kexec_test/kexec_test16.S
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										53
									
								
								kexec_test/x86-setup-legacy-pic.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								kexec_test/x86-setup-legacy-pic.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,53 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	.text
 | 
			
		||||
	.code32
 | 
			
		||||
setup_legacy_pic:
 | 
			
		||||
	/* Load the legacy dos settings into the 8259A pic */
 | 
			
		||||
	movb	$0xff, %al
 | 
			
		||||
	outb	%al, $0x21	/* mask all of 8259A-1 */
 | 
			
		||||
	outb	%al, $0xa1	/* mask all of 8259A-1 */
 | 
			
		||||
 | 
			
		||||
	movb	$0x11, %al
 | 
			
		||||
	outb	%al, $0x20	/* ICW1: select 8259A-1 init */
 | 
			
		||||
	outb	%al, $0x80	/* A short delay */
 | 
			
		||||
	movb	$0x08, %al
 | 
			
		||||
	outb	%al, $0x21	/* ICW2: 8259A-1 IR0-7 mappend to 0x8-0xf */
 | 
			
		||||
	outb	%al, $0x80	/* A short delay */
 | 
			
		||||
	movb	$01, %al
 | 
			
		||||
	outb	%al, $0x21	/* Normal 8086 auto EOI mode */
 | 
			
		||||
	outb	%al, $0x80	/* A short delay */
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	movb	$0x11, %al
 | 
			
		||||
	outb	%al, $0xA0	/* ICW1: select 8259A-2 init */
 | 
			
		||||
	outb	%al, $0x80	/* A short delay */
 | 
			
		||||
	movb	$0x70, %al
 | 
			
		||||
	outb	%al, $0xA1	/* ICW2: 8259A-2 IR0-7 mappend to 0x70-0x77 */
 | 
			
		||||
	outb	%al, $0x80	/* A short delay */
 | 
			
		||||
	movb	$01, %al
 | 
			
		||||
	outb	%al, $0xA1	/* Normal 8086 auto EOI mode */
 | 
			
		||||
	outb	%al, $0x80	/* A short delay */
 | 
			
		||||
	
 | 
			
		||||
	movb	$0, %al
 | 
			
		||||
	outb	%al, $0x21	/* Unmask all of 8259A-1 */
 | 
			
		||||
	outb	%al, $0xa1	/* Unmask all of 8259A-2 */
 | 
			
		||||
 | 
			
		||||
	ret
 | 
			
		||||
							
								
								
									
										68
									
								
								purgatory/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								purgatory/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
#
 | 
			
		||||
# Purgatory (an uncomfortable intermediate state)
 | 
			
		||||
#            In this case the code that runs between kernels
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# There is probably a cleaner way to do this but for now this
 | 
			
		||||
# should keep us from accidentially include unsafe library functions
 | 
			
		||||
# or headers.
 | 
			
		||||
PCFLAGS:=-Wall -Os  \
 | 
			
		||||
	-I$(shell $(CC) -print-file-name=include) \
 | 
			
		||||
	-Ipurgatory/include -Ipurgatory/arch/$(ARCH)/include \
 | 
			
		||||
	$(CPPFLAGS)
 | 
			
		||||
 | 
			
		||||
PCFLAGS += $(call cc-option, -ffreestanding)
 | 
			
		||||
PCFLAGS += $(call cc-option, -fnobuiltin)
 | 
			
		||||
PCFLAGS += $(call cc-option, -fnostdinc)
 | 
			
		||||
PCFLAGS += $(call cc-option, -fno-zero-initialized-in-bss)
 | 
			
		||||
 | 
			
		||||
PURGATORY_C_SRCS:= 
 | 
			
		||||
PURGATORY_C_SRCS += purgatory/purgatory.c
 | 
			
		||||
PURGATORY_C_SRCS += purgatory/printf.c
 | 
			
		||||
PURGATORY_C_SRCS += purgatory/string.c
 | 
			
		||||
PURGATORY_S_OBJS:= 
 | 
			
		||||
 | 
			
		||||
include purgatory/arch/$(ARCH)/Makefile
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PURGATORY_C_OBJS:= $(patsubst %.c, $(OBJDIR)/%.o, $(PURGATORY_C_SRCS))
 | 
			
		||||
PURGATORY_C_DEPS:= $(patsubst %.c, $(OBJDIR)/%.d, $(PURGATORY_C_SRCS))
 | 
			
		||||
PURGATORY_S_OBJS:= $(patsubst %.S, $(OBJDIR)/%.o, $(PURGATORY_S_SRCS))
 | 
			
		||||
PURGATORY_S_DEPS:= $(patsubst %.S, $(OBJDIR)/%.d, $(PURGATORY_S_SRCS))
 | 
			
		||||
PURGATORY_SRCS:= $(PURGATORY_S_SRCS) $(PURGATORY_C_SRCS)
 | 
			
		||||
PURGATORY_OBJS:= $(PURGATORY_S_OBJS) $(PURGATORY_C_OBJS)
 | 
			
		||||
PURGATORY_DEPS:= $(PURGATORY_S_DEPS) $(PURGATORY_C_DEPS)
 | 
			
		||||
PURGATORY:= $(OBJDIR)/purgatory/purgatory.ro
 | 
			
		||||
 | 
			
		||||
include $(PURGATORY_DEPS)
 | 
			
		||||
 | 
			
		||||
$(PURGATORY_C_DEPS): $(OBJDIR)/%.d: %.c
 | 
			
		||||
	$(MKDIR) -p $(@D)
 | 
			
		||||
	$(CC) $(PCFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
 | 
			
		||||
 | 
			
		||||
$(PURGATORY_S_DEPS): $(OBJDIR)/%.d: %.S
 | 
			
		||||
	$(MKDIR) -p $(@D)
 | 
			
		||||
	$(CC) $(PCFLAGS) -M $< | sed -e 's|$(patsubst %.d,%.o,$(@F))|$(patsubst %.d,%.o,$(@))|' > $@
 | 
			
		||||
 | 
			
		||||
$(PURGATORY_C_OBJS): $(OBJDIR)/%.o: %.c $(OBJDIR)/%.d
 | 
			
		||||
	$(MKDIR) -p $(@D)
 | 
			
		||||
	$(CC) $(PCFLAGS) -o $@ -c $<
 | 
			
		||||
 | 
			
		||||
$(PURGATORY_S_OBJS): $(OBJDIR)/%.o: %.S $(OBJDIR)/%.d
 | 
			
		||||
	$(MKDIR) -p $(@D)
 | 
			
		||||
	$(CC) $(PCFLAGS) -o $@ -c $<
 | 
			
		||||
 | 
			
		||||
$(PURGATORY): $(PURGATORY_OBJS) $(UTIL_LIB)
 | 
			
		||||
	$(MKDIR) -p $(@D)
 | 
			
		||||
	$(LD) $(LDFLAGS) --no-undefined -e purgatory_start -r -o $@ $(PURGATORY_OBJS) $(UTIL_LIB)
 | 
			
		||||
 | 
			
		||||
echo::
 | 
			
		||||
	@echo "PURGATORY_C_SRCS $(PURGATORY_C_SRCS)"
 | 
			
		||||
	@echo "PURGATORY_C_DEPS $(PURGATORY_C_DEPS)"
 | 
			
		||||
	@echo "PURGATORY_C_OBJS $(PURGATORY_C_OBJS)"
 | 
			
		||||
	@echo "PURGATORY_S_SRCS $(PURGATORY_S_SRCS)"
 | 
			
		||||
	@echo "PURGATORY_S_DEPS $(PURGATORY_S_DEPS)"
 | 
			
		||||
	@echo "PURGATORY_S_OBJS $(PURGATORY_S_OBJS)"
 | 
			
		||||
	@echo "PURGATORY_SRCS   $(PURGATORY_SRCS)"
 | 
			
		||||
	@echo "PURGATORY_DEPS   $(PURGATORY_DEPS)"
 | 
			
		||||
	@echo "PURGATORY_OBJS   $(PURGATORY_OBJS)"
 | 
			
		||||
							
								
								
									
										7
									
								
								purgatory/arch/alpha/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								purgatory/arch/alpha/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#
 | 
			
		||||
# Purgatory alpha
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
PURGATORY_C_SRCS+=
 | 
			
		||||
PURGATORY_S_SRCS+=
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								purgatory/arch/alpha/include/limits.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								purgatory/arch/alpha/include/limits.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
#ifndef LIMITS_H
 | 
			
		||||
#define LIMITS_H	1
 | 
			
		||||
 | 
			
		||||
/* Number of bits in a `char' */
 | 
			
		||||
#define CHAR_BIT	8
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed char' can hold */
 | 
			
		||||
#define SCHAR_MIN	(-128)
 | 
			
		||||
#define SCHAR_MAX	127
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UCHAR_MAX	255
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `char' can hold */
 | 
			
		||||
#define CHAR_MIN	SCHAR_MIN
 | 
			
		||||
#define CHAR_MAX	SCHAR_MAX
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed short int' can hold */
 | 
			
		||||
#define SHRT_MIN	(-32768)
 | 
			
		||||
#define SHRT_MAX	32767
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
 | 
			
		||||
#define USHRT_MAX	65535
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed int' can hold */
 | 
			
		||||
#define INT_MIN		(-INT_MAX - 1)
 | 
			
		||||
#define INT_MAX		2147483647
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UINT_MAX	4294967295U
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed int' can hold */
 | 
			
		||||
#define INT_MIN		(-INT_MAX - 1)
 | 
			
		||||
#define INT_MAX		2147483647
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UINT_MAX	4294967295U
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed long' can hold */
 | 
			
		||||
#define LONG_MAX	9223372036854775807L
 | 
			
		||||
#define LONG_MIN	(-LONG_MAX - 1L)
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
 | 
			
		||||
#define ULONG_MAX	18446744073709551615UL
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed long long' can hold */
 | 
			
		||||
#define LLONG_MAX	9223372036854775807LL
 | 
			
		||||
#define LLONG_MIN	(-LONG_MAX - 1LL)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
 | 
			
		||||
#define ULLONG_MAX	18446744073709551615ULL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* LIMITS_H */
 | 
			
		||||
							
								
								
									
										16
									
								
								purgatory/arch/alpha/include/stdint.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								purgatory/arch/alpha/include/stdint.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#ifndef STDINT_H
 | 
			
		||||
#define STDINT_H
 | 
			
		||||
 | 
			
		||||
typedef unsigned long      size_t;
 | 
			
		||||
 | 
			
		||||
typedef unsigned char      uint8_t;
 | 
			
		||||
typedef unsigned short     uint16_t;
 | 
			
		||||
typedef unsigned int       uint32_t;
 | 
			
		||||
typedef unsigned long      uint64_t;
 | 
			
		||||
 | 
			
		||||
typedef signed char        int8_t;
 | 
			
		||||
typedef signed short       int16_t;
 | 
			
		||||
typedef signed int         int32_t;
 | 
			
		||||
typedef signed long        int64_t;
 | 
			
		||||
 | 
			
		||||
#endif /* STDINT_H */
 | 
			
		||||
							
								
								
									
										14
									
								
								purgatory/arch/i386/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								purgatory/arch/i386/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#
 | 
			
		||||
# Purgatory i386
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
PURGATORY_S_SRCS+= purgatory/arch/i386/entry32-16.S
 | 
			
		||||
PURGATORY_S_SRCS+= purgatory/arch/i386/entry32-16-debug.S
 | 
			
		||||
PURGATORY_S_SRCS+= purgatory/arch/i386/entry32.S
 | 
			
		||||
PURGATORY_S_SRCS+= purgatory/arch/i386/setup-x86.S
 | 
			
		||||
PURGATORY_S_SRCS+= purgatory/arch/i386/stack.S
 | 
			
		||||
PURGATORY_S_SRCS+= purgatory/arch/i386/compat_x86_64.S
 | 
			
		||||
PURGATORY_C_SRCS+= purgatory/arch/i386/purgatory-x86.c
 | 
			
		||||
PURGATORY_C_SRCS+= purgatory/arch/i386/console-x86.c
 | 
			
		||||
PURGATORY_C_SRCS+= purgatory/arch/i386/vga.c
 | 
			
		||||
PURGATORY_C_SRCS+= purgatory/arch/i386/pic.c
 | 
			
		||||
							
								
								
									
										100
									
								
								purgatory/arch/i386/compat_x86_64.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								purgatory/arch/i386/compat_x86_64.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004,2005  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	.equ	MSR_K6_EFER,   0xC0000080
 | 
			
		||||
	.equ	EFER_LME,      0x00000100
 | 
			
		||||
	.equ	X86_CR4_PAE,   0x00000020
 | 
			
		||||
	.equ	CR0_PG,        0x80000000
 | 
			
		||||
 | 
			
		||||
	.globl compat_x86_64, compat_x86_64_entry32
 | 
			
		||||
	.text
 | 
			
		||||
	.code64
 | 
			
		||||
	.balign 16	
 | 
			
		||||
compat_x86_64:
 | 
			
		||||
	/* Setup a temporary gdt */
 | 
			
		||||
	/* This also acts as a serializing instruction ensuring
 | 
			
		||||
	 * my self modifying code works.
 | 
			
		||||
	 */
 | 
			
		||||
	lgdt	gdt(%rip)
 | 
			
		||||
 | 
			
		||||
	/* Switch to 32bit compatiblity mode */
 | 
			
		||||
	ljmp	*lm_exit_addr(%rip)
 | 
			
		||||
lm_exit:
 | 
			
		||||
	.code32
 | 
			
		||||
 | 
			
		||||
	/* Disable paging */
 | 
			
		||||
	movl	%cr0, %eax
 | 
			
		||||
	andl	$~CR0_PG, %eax
 | 
			
		||||
	movl	%eax, %cr0
 | 
			
		||||
 | 
			
		||||
	/* Disable long mode */
 | 
			
		||||
	movl	$MSR_K6_EFER, %ecx
 | 
			
		||||
	rdmsr
 | 
			
		||||
	andl	$~EFER_LME, %eax
 | 
			
		||||
	wrmsr
 | 
			
		||||
 | 
			
		||||
	/* Disable PAE */
 | 
			
		||||
	xorl	%eax, %eax
 | 
			
		||||
	movl	%eax, %cr4
 | 
			
		||||
 | 
			
		||||
	/* load the data segments */
 | 
			
		||||
	movl	$0x18, %eax	/* data segment */
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	/* set all of the registers to known values */
 | 
			
		||||
	/* leave %esp alone */
 | 
			
		||||
 | 
			
		||||
	xorl	%eax, %eax
 | 
			
		||||
	xorl	%ebx, %ebx
 | 
			
		||||
	xorl    %ecx, %ecx
 | 
			
		||||
	xorl    %edx, %edx
 | 
			
		||||
	xorl    %esi, %esi
 | 
			
		||||
	xorl    %edi, %edi
 | 
			
		||||
	xorl    %ebp, %ebp
 | 
			
		||||
 | 
			
		||||
	jmp	*compat_x86_64_entry32
 | 
			
		||||
 | 
			
		||||
	.section ".rodata"
 | 
			
		||||
	.balign 16
 | 
			
		||||
gdt:	/* 0x00 unusable segment 
 | 
			
		||||
	 * 0x08 unused
 | 
			
		||||
	 * so use them as the gdt ptr
 | 
			
		||||
	 */
 | 
			
		||||
	.word	gdt_end - gdt - 1
 | 
			
		||||
	# A quad word pointer to the gdt with the high 32bits 0
 | 
			
		||||
	.long	gdt, 0  
 | 
			
		||||
	.word	0, 0, 0
 | 
			
		||||
 | 
			
		||||
	/* 0x10 4GB flat code segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x18 4GB flat data segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
gdt_end:
 | 
			
		||||
 | 
			
		||||
lm_exit_addr:
 | 
			
		||||
	.long	lm_exit
 | 
			
		||||
	.long	0x10	
 | 
			
		||||
 | 
			
		||||
compat_x86_64_entry32:
 | 
			
		||||
	.long 0
 | 
			
		||||
.size compat_x86_64_entry32, . - compat_x86_64_entry32	
 | 
			
		||||
							
								
								
									
										134
									
								
								purgatory/arch/i386/console-x86.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								purgatory/arch/i386/console-x86.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
			
		||||
#include <arch/io.h>
 | 
			
		||||
#include <purgatory.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * VGA
 | 
			
		||||
 * =============================================================================
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Simple VGA output */
 | 
			
		||||
 | 
			
		||||
#define VGABASE		((void *)0xb8000)
 | 
			
		||||
 | 
			
		||||
#define MAX_YPOS	25
 | 
			
		||||
#define MAX_XPOS	80
 | 
			
		||||
 | 
			
		||||
static int current_ypos = 1, current_xpos = 0; 
 | 
			
		||||
uint8_t console_vga = 0;
 | 
			
		||||
 | 
			
		||||
static void putchar_vga(int ch)
 | 
			
		||||
{
 | 
			
		||||
	int  i, k, j;
 | 
			
		||||
	if (!console_vga)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (current_ypos >= MAX_YPOS) {
 | 
			
		||||
		/* scroll 1 line up */
 | 
			
		||||
		for (k = 1, j = 0; k < MAX_YPOS; k++, j++) {
 | 
			
		||||
			for (i = 0; i < MAX_XPOS; i++) {
 | 
			
		||||
				writew(readw(VGABASE + 2*(MAX_XPOS*k + i)),
 | 
			
		||||
					VGABASE + 2*(MAX_XPOS*j + i));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for (i = 0; i < MAX_XPOS; i++)
 | 
			
		||||
			writew(0x720, VGABASE + 2*(MAX_XPOS*j + i));
 | 
			
		||||
		current_ypos = MAX_YPOS-1;
 | 
			
		||||
	}
 | 
			
		||||
	if (ch == '\n') {
 | 
			
		||||
		current_xpos = 0;
 | 
			
		||||
		current_ypos++;
 | 
			
		||||
	} else if (ch != '\r')  {
 | 
			
		||||
		writew(((0x7 << 8) | (unsigned short) ch),
 | 
			
		||||
			VGABASE + 2*(MAX_XPOS*current_ypos +
 | 
			
		||||
				current_xpos++));
 | 
			
		||||
		if (current_xpos >= MAX_XPOS) {
 | 
			
		||||
			current_xpos = 0;
 | 
			
		||||
			current_ypos++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Serial
 | 
			
		||||
 * =============================================================================
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Base Address */
 | 
			
		||||
uint8_t console_serial = 0;
 | 
			
		||||
uint16_t serial_base = 0x3f8; /* TTYS0 */
 | 
			
		||||
uint32_t serial_baud = 0;
 | 
			
		||||
 | 
			
		||||
#define XMTRDY          0x20
 | 
			
		||||
 | 
			
		||||
#define DLAB		0x80
 | 
			
		||||
 | 
			
		||||
#define TXR             0       /*  Transmit register (WRITE) */
 | 
			
		||||
#define TBR             0       /*  Transmit register (WRITE) */
 | 
			
		||||
#define RXR             0       /*  Receive register  (READ)  */
 | 
			
		||||
#define IER             1       /*  Interrupt Enable          */
 | 
			
		||||
#define IIR             2       /*  Interrupt ID              */
 | 
			
		||||
#define FCR             2       /*  FIFO control              */
 | 
			
		||||
#define LCR             3       /*  Line control              */
 | 
			
		||||
#define MCR             4       /*  Modem control             */
 | 
			
		||||
#define LSR             5       /*  Line Status               */
 | 
			
		||||
#define MSR             6       /*  Modem Status              */
 | 
			
		||||
#define DLL             0       /*  Divisor Latch Low         */
 | 
			
		||||
#define DLH             1       /*  Divisor latch High        */
 | 
			
		||||
 | 
			
		||||
static void serial_init(void)
 | 
			
		||||
{
 | 
			
		||||
	static int initialized = 0;
 | 
			
		||||
	if (!initialized) {
 | 
			
		||||
		unsigned lcr;
 | 
			
		||||
		outb(0x3, serial_base + LCR);	/* 8n1 */
 | 
			
		||||
		outb(0,   serial_base + IER);	/* no interrupt */
 | 
			
		||||
		outb(0,   serial_base + FCR);	/* no fifo */
 | 
			
		||||
		outb(0x3, serial_base + MCR);	/* DTR + RTS */
 | 
			
		||||
		
 | 
			
		||||
		lcr = inb(serial_base + LCR); 
 | 
			
		||||
		outb(lcr | DLAB, serial_base + LCR); 
 | 
			
		||||
		/* By default don't change the serial port baud rate */
 | 
			
		||||
		if (serial_baud) {
 | 
			
		||||
			unsigned divisor = 115200 / serial_baud; 
 | 
			
		||||
			outb(divisor & 0xff, serial_base + DLL); 
 | 
			
		||||
			outb((divisor >> 8) & 0xff, serial_base + DLH); 
 | 
			
		||||
		}
 | 
			
		||||
		outb(lcr & ~DLAB, serial_base + LCR);
 | 
			
		||||
		initialized = 1;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void serial_tx_byte(unsigned byte)
 | 
			
		||||
{
 | 
			
		||||
	/* Ensure the serial port is initialized */
 | 
			
		||||
	serial_init();
 | 
			
		||||
 | 
			
		||||
	/* Wait until I can send a byte */
 | 
			
		||||
	while((inb(serial_base + LSR) & 0x20) == 0)
 | 
			
		||||
		;
 | 
			
		||||
	outb(byte, serial_base + TBR);
 | 
			
		||||
	/* Wait until the byte is transmitted */
 | 
			
		||||
	while(!(inb(serial_base + LSR) & 0x40))
 | 
			
		||||
		;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void putchar_serial(int ch)
 | 
			
		||||
{
 | 
			
		||||
	if (!console_serial) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if (ch == '\n') {
 | 
			
		||||
		serial_tx_byte('\r');
 | 
			
		||||
	}
 | 
			
		||||
	serial_tx_byte(ch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Generic wrapper function */
 | 
			
		||||
 | 
			
		||||
void putchar(int ch)
 | 
			
		||||
{
 | 
			
		||||
	putchar_vga(ch);
 | 
			
		||||
	putchar_serial(ch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										160
									
								
								purgatory/arch/i386/entry16.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								purgatory/arch/i386/entry16.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#undef i386	
 | 
			
		||||
	.text
 | 
			
		||||
	.globl entry16, entry16_regs
 | 
			
		||||
	.arch i386
 | 
			
		||||
	.balign 16
 | 
			
		||||
entry16:
 | 
			
		||||
	.code32
 | 
			
		||||
	/* Compute where I am running at */
 | 
			
		||||
	movl	$entry16, %ebx	
 | 
			
		||||
 | 
			
		||||
	/* Fixup my real mode segment */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shrl	$4, %eax
 | 
			
		||||
	movw	%ax, 2 + realptr
 | 
			
		||||
 | 
			
		||||
	/* Fixup the gdt */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shll	$16, %eax
 | 
			
		||||
	
 | 
			
		||||
	movl	%ebx, %ecx
 | 
			
		||||
	shrl	$16, %ecx
 | 
			
		||||
	andl	$0xff, %ecx
 | 
			
		||||
	
 | 
			
		||||
	movl	%ebx, %edx
 | 
			
		||||
	andl	$0xff000000, %edx
 | 
			
		||||
	orl	%edx, %ecx
 | 
			
		||||
 | 
			
		||||
	orl	%eax, 0x08 + gdt
 | 
			
		||||
	orl	%ecx, 0x0c + gdt
 | 
			
		||||
	orl	%eax, 0x10 + gdt
 | 
			
		||||
	orl	%ecx, 0x14 + gdt	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	/* Setup the classic BIOS interrupt table at 0x0 */
 | 
			
		||||
	lidt	idtptr
 | 
			
		||||
	
 | 
			
		||||
	/* Provide us with 16bit segments that we can use */
 | 
			
		||||
	lgdt	gdt
 | 
			
		||||
 | 
			
		||||
	/* Note we don't disable the a20 line, (this shouldn't be required)
 | 
			
		||||
	 * The code to do it is in kexec_test and it is a real pain.
 | 
			
		||||
	 * I will worry about that when I need it.
 | 
			
		||||
	 */
 | 
			
		||||
	
 | 
			
		||||
	/* Load 16bit data segments, to ensure the segment limits are set */
 | 
			
		||||
	movl	$0x10, %eax
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	/* switch to 16bit mode */
 | 
			
		||||
	ljmp	$0x08, $1f - entry16
 | 
			
		||||
1:
 | 
			
		||||
	.code16
 | 
			
		||||
	/* Disable Paging and protected mode */
 | 
			
		||||
	/* clear the PG & PE bits of CR0 */
 | 
			
		||||
	movl	%cr0,%eax
 | 
			
		||||
	andl	$~((1 << 31)|(1<<0)),%eax
 | 
			
		||||
	movl	%eax,%cr0
 | 
			
		||||
 | 
			
		||||
	/* make intersegment jmp to flush the processor pipeline
 | 
			
		||||
	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
 | 
			
		||||
	 */
 | 
			
		||||
	ljmp	*(realptr - entry16)
 | 
			
		||||
3:
 | 
			
		||||
	/* we are in real mode now
 | 
			
		||||
	 * set up the real mode segment registers : %ds, $ss, %es
 | 
			
		||||
	 */
 | 
			
		||||
	/* Setup the data segment */
 | 
			
		||||
	movw	%cs, %ax
 | 
			
		||||
	movw	%ax, %ds
 | 
			
		||||
 | 
			
		||||
	/* Load the registers */
 | 
			
		||||
	movl	eax - entry16, %eax
 | 
			
		||||
	movl	ebx - entry16, %ebx
 | 
			
		||||
	movl	ecx - entry16, %ecx
 | 
			
		||||
	movl	edx - entry16, %edx
 | 
			
		||||
	movl	esi - entry16, %esi
 | 
			
		||||
	movl	edi - entry16, %esi
 | 
			
		||||
	movl	esp - entry16, %esp
 | 
			
		||||
	movl	ebp - entry16, %ebp
 | 
			
		||||
	movw	es  - entry16, %es
 | 
			
		||||
	movw	ss  - entry16, %ss
 | 
			
		||||
	movw	fs  - entry16, %fs
 | 
			
		||||
	movw	gs  - entry16, %gs
 | 
			
		||||
	movw	ds  - entry16, %ds
 | 
			
		||||
 | 
			
		||||
	/* Jump to the kernel entrypoint */
 | 
			
		||||
	ljmp	%cs:*(realdest - entry16)
 | 
			
		||||
 | 
			
		||||
	.balign 4
 | 
			
		||||
entry16_regs:	
 | 
			
		||||
eax:	.long	0x00000000
 | 
			
		||||
ebx:	.long	0x00000000
 | 
			
		||||
ecx:	.long	0x00000000
 | 
			
		||||
edx:	.long	0x00000000
 | 
			
		||||
esi:	.long	0x00000000
 | 
			
		||||
edi:	.long	0x00000000
 | 
			
		||||
esp:	.long	0x00000000
 | 
			
		||||
ebp:	.long	0x00000000
 | 
			
		||||
ds:	.word	0x0000
 | 
			
		||||
es:	.word	0x0000
 | 
			
		||||
ss:	.word	0x0000
 | 
			
		||||
fs:	.word	0x0000
 | 
			
		||||
gs:	.word	0x0000
 | 
			
		||||
realdest:
 | 
			
		||||
ip:	.word	0x0000
 | 
			
		||||
cs:	.word	0x0000
 | 
			
		||||
pad:	.word	0x0000
 | 
			
		||||
	.size entry16_regs, . - entry16_regs
 | 
			
		||||
 | 
			
		||||
	.balign 16
 | 
			
		||||
realptr:		
 | 
			
		||||
	.word	3b - entry16
 | 
			
		||||
	.word	0x0000
 | 
			
		||||
	
 | 
			
		||||
	.data
 | 
			
		||||
	.balign 16
 | 
			
		||||
 | 
			
		||||
idtptr:
 | 
			
		||||
	/* 256 entry idt at 0 */
 | 
			
		||||
	.word	0x400 - 1
 | 
			
		||||
	.word	0, 0
 | 
			
		||||
 | 
			
		||||
	.balign 16	
 | 
			
		||||
gdt:
 | 
			
		||||
	/* 0x00 unusable segment so used as the gdt ptr */
 | 
			
		||||
	.word gdt_end - gdt - 1
 | 
			
		||||
	.long gdt
 | 
			
		||||
	.word 0
 | 
			
		||||
 | 
			
		||||
	/* 0x08 16 bit real mode code segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x9b, 0x00, 0x00
 | 
			
		||||
 | 
			
		||||
	/* 0x10 16 bit real mode data segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x93, 0x00, 0x00
 | 
			
		||||
gdt_end:
 | 
			
		||||
							
								
								
									
										195
									
								
								purgatory/arch/i386/entry32-16-debug.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								purgatory/arch/i386/entry32-16-debug.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,195 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "arch/debug.h"	
 | 
			
		||||
 | 
			
		||||
#undef i386	
 | 
			
		||||
	.text
 | 
			
		||||
	.globl entry16_debug, entry16_debug_regs
 | 
			
		||||
	.globl entry16_debug_pre32
 | 
			
		||||
	.globl entry16_debug_first32
 | 
			
		||||
	.globl entry16_debug_old_first32
 | 
			
		||||
	.arch i386
 | 
			
		||||
	.balign 16
 | 
			
		||||
entry16_debug:
 | 
			
		||||
	.code32
 | 
			
		||||
	/* Compute where I am running at */
 | 
			
		||||
	movl	$entry16_debug, %ebx	
 | 
			
		||||
 | 
			
		||||
	/* Fixup my real mode segment */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shrl	$4, %eax
 | 
			
		||||
	movw	%ax, 2 + realptr
 | 
			
		||||
 | 
			
		||||
	/* Fixup the gdt */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shll	$16, %eax
 | 
			
		||||
	
 | 
			
		||||
	movl	%ebx, %ecx
 | 
			
		||||
	shrl	$16, %ecx
 | 
			
		||||
	andl	$0xff, %ecx
 | 
			
		||||
	
 | 
			
		||||
	movl	%ebx, %edx
 | 
			
		||||
	andl	$0xff000000, %edx
 | 
			
		||||
	orl	%edx, %ecx
 | 
			
		||||
 | 
			
		||||
	orl	%eax, 0x08 + gdt
 | 
			
		||||
	orl	%ecx, 0x0c + gdt
 | 
			
		||||
	orl	%eax, 0x10 + gdt
 | 
			
		||||
	orl	%ecx, 0x14 + gdt	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
DEBUG('a')	
 | 
			
		||||
	/* Setup the classic BIOS interrupt table at 0x0 */
 | 
			
		||||
	lidt	idtptr
 | 
			
		||||
 | 
			
		||||
DEBUG('b')		
 | 
			
		||||
	/* Provide us with 16bit segments that we can use */
 | 
			
		||||
	lgdt	gdt
 | 
			
		||||
 | 
			
		||||
DEBUG('c')	
 | 
			
		||||
	/* Note we don't disable the a20 line, (this shouldn't be required)
 | 
			
		||||
	 * The code to do it is in kexec_test and it is a real pain.
 | 
			
		||||
	 * I will worry about that when I need it.
 | 
			
		||||
	 */
 | 
			
		||||
	
 | 
			
		||||
	/* Load 16bit data segments, to ensure the segment limits are set */
 | 
			
		||||
	movl	$0x10, %eax
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
DEBUG('d')
 | 
			
		||||
 | 
			
		||||
	/* switch to 16bit mode */
 | 
			
		||||
	ljmp	$0x08, $1f - entry16_debug
 | 
			
		||||
1:
 | 
			
		||||
	.code16
 | 
			
		||||
DEBUG('e')	
 | 
			
		||||
	/* Disable Paging and protected mode */
 | 
			
		||||
	/* clear the PG & PE bits of CR0 */
 | 
			
		||||
	movl	%cr0,%eax
 | 
			
		||||
	andl	$~((1 << 31)|(1<<0)),%eax
 | 
			
		||||
	movl	%eax,%cr0
 | 
			
		||||
 | 
			
		||||
DEBUG('f')
 | 
			
		||||
	/* make intersegment jmp to flush the processor pipeline
 | 
			
		||||
	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
 | 
			
		||||
	 */
 | 
			
		||||
	ljmp	*(realptr - entry16_debug)
 | 
			
		||||
3:
 | 
			
		||||
DEBUG('g')
 | 
			
		||||
	/* we are in real mode now
 | 
			
		||||
	 * set up the real mode segment registers : %ds, $ss, %es
 | 
			
		||||
	 */
 | 
			
		||||
	/* Setup the data segment */
 | 
			
		||||
	movw	%cs, %ax
 | 
			
		||||
	movw	%ax, %ds
 | 
			
		||||
 | 
			
		||||
DEBUG('h')
 | 
			
		||||
	/* Load the registers */
 | 
			
		||||
	movl	eax - entry16_debug, %eax
 | 
			
		||||
	movl	ebx - entry16_debug, %ebx
 | 
			
		||||
	movl	ecx - entry16_debug, %ecx
 | 
			
		||||
	movl	edx - entry16_debug, %edx
 | 
			
		||||
	movl	esi - entry16_debug, %esi
 | 
			
		||||
	movl	edi - entry16_debug, %esi
 | 
			
		||||
	movl	esp - entry16_debug, %esp
 | 
			
		||||
	movl	ebp - entry16_debug, %ebp
 | 
			
		||||
	movw	es  - entry16_debug, %es
 | 
			
		||||
	movw	ss  - entry16_debug, %ss
 | 
			
		||||
	movw	fs  - entry16_debug, %fs
 | 
			
		||||
	movw	gs  - entry16_debug, %gs
 | 
			
		||||
	movw	ds  - entry16_debug, %ds
 | 
			
		||||
 | 
			
		||||
	/* Jump to the kernel entrypoint */
 | 
			
		||||
	ljmp	%cs:*(realdest - entry16_debug)
 | 
			
		||||
 | 
			
		||||
	.balign 4
 | 
			
		||||
entry16_debug_regs:	
 | 
			
		||||
eax:	.long	0x00000000
 | 
			
		||||
ebx:	.long	0x00000000
 | 
			
		||||
ecx:	.long	0x00000000
 | 
			
		||||
edx:	.long	0x00000000
 | 
			
		||||
esi:	.long	0x00000000
 | 
			
		||||
edi:	.long	0x00000000
 | 
			
		||||
esp:	.long	0x00000000
 | 
			
		||||
ebp:	.long	0x00000000
 | 
			
		||||
ds:	.word	0x0000
 | 
			
		||||
es:	.word	0x0000
 | 
			
		||||
ss:	.word	0x0000
 | 
			
		||||
fs:	.word	0x0000
 | 
			
		||||
gs:	.word	0x0000
 | 
			
		||||
realdest:
 | 
			
		||||
ip:	.word	0x0000
 | 
			
		||||
cs:	.word	0x0000
 | 
			
		||||
pad:	.word	0x0000
 | 
			
		||||
	.size entry16_debug_regs, . - entry16_debug_regs	
 | 
			
		||||
 | 
			
		||||
	.balign 16
 | 
			
		||||
realptr:		
 | 
			
		||||
	.word	3b - entry16_debug
 | 
			
		||||
	.word	0x0000
 | 
			
		||||
	
 | 
			
		||||
	.data
 | 
			
		||||
	.balign 16
 | 
			
		||||
 | 
			
		||||
idtptr:
 | 
			
		||||
	/* 256 entry idt at 0 */
 | 
			
		||||
	.word	0x400 - 1
 | 
			
		||||
	.word	0, 0
 | 
			
		||||
 | 
			
		||||
gdt:
 | 
			
		||||
	/* 0x00 unusable segment so used as the gdt ptr */
 | 
			
		||||
	.word gdt_end - gdt - 1
 | 
			
		||||
	.long gdt
 | 
			
		||||
	.word 0
 | 
			
		||||
 | 
			
		||||
	/* 0x08 16 bit real mode code segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x9b, 0x00, 0x00
 | 
			
		||||
 | 
			
		||||
	/* 0x10 16 bit real mode data segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x93, 0x00, 0x00
 | 
			
		||||
gdt_end:
 | 
			
		||||
	.size gdt, . - gdt
 | 
			
		||||
 | 
			
		||||
	.text	
 | 
			
		||||
entry16_debug_pre32:
 | 
			
		||||
	.code16
 | 
			
		||||
DEBUG('i')
 | 
			
		||||
	cli					# no interrupts allowed !
 | 
			
		||||
	movb	$0x80, %al			# disable NMI for bootup
 | 
			
		||||
						# sequence
 | 
			
		||||
	outb	%al, $0x70
 | 
			
		||||
	lret
 | 
			
		||||
.size entry16_debug_pre32, . - entry16_debug_pre32
 | 
			
		||||
	
 | 
			
		||||
entry16_debug_first32:
 | 
			
		||||
	.code32
 | 
			
		||||
DEBUG('j')
 | 
			
		||||
	.byte	0xb8	/* movl $0x10000, %eax */
 | 
			
		||||
entry16_debug_old_first32:
 | 
			
		||||
	.long 0x100000
 | 
			
		||||
	.size entry16_debug_old_first32, . - entry16_debug_old_first32
 | 
			
		||||
	jmp	%eax
 | 
			
		||||
.size entry16_debug_first32, . - entry16_debug_first32
 | 
			
		||||
							
								
								
									
										160
									
								
								purgatory/arch/i386/entry32-16.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								purgatory/arch/i386/entry32-16.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,160 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#undef i386	
 | 
			
		||||
	.text
 | 
			
		||||
	.globl entry16, entry16_regs
 | 
			
		||||
	.arch i386
 | 
			
		||||
	.balign 16
 | 
			
		||||
entry16:
 | 
			
		||||
	.code32
 | 
			
		||||
	/* Compute where I am running at */
 | 
			
		||||
	movl	$entry16_debug, %ebx	
 | 
			
		||||
 | 
			
		||||
	/* Fixup my real mode segment */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shrl	$4, %eax
 | 
			
		||||
	movw	%ax, 2 + realptr
 | 
			
		||||
 | 
			
		||||
	/* Fixup the gdt */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shll	$16, %eax
 | 
			
		||||
	
 | 
			
		||||
	movl	%ebx, %ecx
 | 
			
		||||
	shrl	$16, %ecx
 | 
			
		||||
	andl	$0xff, %ecx
 | 
			
		||||
	
 | 
			
		||||
	movl	%ebx, %edx
 | 
			
		||||
	andl	$0xff000000, %edx
 | 
			
		||||
	orl	%edx, %ecx
 | 
			
		||||
 | 
			
		||||
	orl	%eax, 0x08 + gdt
 | 
			
		||||
	orl	%ecx, 0x0c + gdt
 | 
			
		||||
	orl	%eax, 0x10 + gdt
 | 
			
		||||
	orl	%ecx, 0x14 + gdt	
 | 
			
		||||
	
 | 
			
		||||
	
 | 
			
		||||
	/* Setup the classic BIOS interrupt table at 0x0 */
 | 
			
		||||
	lidt	idtptr
 | 
			
		||||
	
 | 
			
		||||
	/* Provide us with 16bit segments that we can use */
 | 
			
		||||
	lgdt	gdt
 | 
			
		||||
 | 
			
		||||
	/* Note we don't disable the a20 line, (this shouldn't be required)
 | 
			
		||||
	 * The code to do it is in kexec_test and it is a real pain.
 | 
			
		||||
	 * I will worry about that when I need it.
 | 
			
		||||
	 */
 | 
			
		||||
	
 | 
			
		||||
	/* Load 16bit data segments, to ensure the segment limits are set */
 | 
			
		||||
	movl	$0x10, %eax
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	/* switch to 16bit mode */
 | 
			
		||||
	ljmp	$0x08, $1f - entry16
 | 
			
		||||
1:
 | 
			
		||||
	.code16
 | 
			
		||||
	/* Disable Paging and protected mode */
 | 
			
		||||
	/* clear the PG & PE bits of CR0 */
 | 
			
		||||
	movl	%cr0,%eax
 | 
			
		||||
	andl	$~((1 << 31)|(1<<0)),%eax
 | 
			
		||||
	movl	%eax,%cr0
 | 
			
		||||
 | 
			
		||||
	/* make intersegment jmp to flush the processor pipeline
 | 
			
		||||
	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
 | 
			
		||||
	 */
 | 
			
		||||
	ljmp	*(realptr - entry16)
 | 
			
		||||
3:
 | 
			
		||||
	/* we are in real mode now
 | 
			
		||||
	 * set up the real mode segment registers : %ds, $ss, %es
 | 
			
		||||
	 */
 | 
			
		||||
	/* Setup the data segment */
 | 
			
		||||
	movw	%cs, %ax
 | 
			
		||||
	movw	%ax, %ds
 | 
			
		||||
 | 
			
		||||
	/* Load the registers */
 | 
			
		||||
	movl	eax - entry16, %eax
 | 
			
		||||
	movl	ebx - entry16, %ebx
 | 
			
		||||
	movl	ecx - entry16, %ecx
 | 
			
		||||
	movl	edx - entry16, %edx
 | 
			
		||||
	movl	esi - entry16, %esi
 | 
			
		||||
	movl	edi - entry16, %esi
 | 
			
		||||
	movl	esp - entry16, %esp
 | 
			
		||||
	movl	ebp - entry16, %ebp
 | 
			
		||||
	movw	es  - entry16, %es
 | 
			
		||||
	movw	ss  - entry16, %ss
 | 
			
		||||
	movw	fs  - entry16, %fs
 | 
			
		||||
	movw	gs  - entry16, %gs
 | 
			
		||||
	movw	ds  - entry16, %ds
 | 
			
		||||
 | 
			
		||||
	/* Jump to the kernel entrypoint */
 | 
			
		||||
	ljmp	%cs:*(realdest - entry16)
 | 
			
		||||
 | 
			
		||||
	.balign 4
 | 
			
		||||
entry16_regs:	
 | 
			
		||||
eax:	.long	0x00000000
 | 
			
		||||
ebx:	.long	0x00000000
 | 
			
		||||
ecx:	.long	0x00000000
 | 
			
		||||
edx:	.long	0x00000000
 | 
			
		||||
esi:	.long	0x00000000
 | 
			
		||||
edi:	.long	0x00000000
 | 
			
		||||
esp:	.long	0x00000000
 | 
			
		||||
ebp:	.long	0x00000000
 | 
			
		||||
ds:	.word	0x0000
 | 
			
		||||
es:	.word	0x0000
 | 
			
		||||
ss:	.word	0x0000
 | 
			
		||||
fs:	.word	0x0000
 | 
			
		||||
gs:	.word	0x0000
 | 
			
		||||
realdest:
 | 
			
		||||
ip:	.word	0x0000
 | 
			
		||||
cs:	.word	0x0000
 | 
			
		||||
pad:	.word	0x0000
 | 
			
		||||
	.size entry16_regs, . - entry16_regs
 | 
			
		||||
 | 
			
		||||
	.balign 16
 | 
			
		||||
realptr:		
 | 
			
		||||
	.word	3b - entry16
 | 
			
		||||
	.word	0x0000
 | 
			
		||||
	
 | 
			
		||||
	.data
 | 
			
		||||
	.balign 16
 | 
			
		||||
 | 
			
		||||
idtptr:
 | 
			
		||||
	/* 256 entry idt at 0 */
 | 
			
		||||
	.word	0x400 - 1
 | 
			
		||||
	.word	0, 0
 | 
			
		||||
 | 
			
		||||
	.balign 16	
 | 
			
		||||
gdt:
 | 
			
		||||
	/* 0x00 unusable segment so used as the gdt ptr */
 | 
			
		||||
	.word gdt_end - gdt - 1
 | 
			
		||||
	.long gdt
 | 
			
		||||
	.word 0
 | 
			
		||||
 | 
			
		||||
	/* 0x08 16 bit real mode code segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x9b, 0x00, 0x00
 | 
			
		||||
 | 
			
		||||
	/* 0x10 16 bit real mode data segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x93, 0x00, 0x00
 | 
			
		||||
gdt_end:
 | 
			
		||||
							
								
								
									
										110
									
								
								purgatory/arch/i386/entry32.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								purgatory/arch/i386/entry32.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
/*
 | 
			
		||||
 * purgatory:  setup code
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#undef i386
 | 
			
		||||
 | 
			
		||||
	.text
 | 
			
		||||
	.arch	i386
 | 
			
		||||
	.globl entry32, entry32_regs
 | 
			
		||||
entry32:
 | 
			
		||||
	.code32
 | 
			
		||||
 | 
			
		||||
	/* Setup a gdt that should that is generally usefully */
 | 
			
		||||
	lgdt	%cs:gdt
 | 
			
		||||
 | 
			
		||||
	/* load the data segments */
 | 
			
		||||
	movl	$0x18, %eax	/* data segment */
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	/* load the code segment */
 | 
			
		||||
	ljmp	$0x10,$1f
 | 
			
		||||
1:		
 | 
			
		||||
 | 
			
		||||
	/* Load the registers */
 | 
			
		||||
	movl	eax, %eax
 | 
			
		||||
	movl	ecx, %ecx
 | 
			
		||||
	movl	edx, %edx
 | 
			
		||||
	movl	esi, %esi
 | 
			
		||||
	movl	edi, %edi
 | 
			
		||||
	movl	esp, %esp
 | 
			
		||||
	movl	ebp, %ebp
 | 
			
		||||
	movl	ebx, %ebx
 | 
			
		||||
 | 
			
		||||
	/* Jump to the loaded image */
 | 
			
		||||
	jmpl	*(eip)
 | 
			
		||||
 | 
			
		||||
	.section ".rodata"
 | 
			
		||||
	.balign 16
 | 
			
		||||
gdt:
 | 
			
		||||
	/* 0x00 unusable segment so used as the gdt ptr */
 | 
			
		||||
	.word	gdt_end - gdt - 1
 | 
			
		||||
	.long	gdt
 | 
			
		||||
	.word	0
 | 
			
		||||
 | 
			
		||||
	/* 0x08 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
 | 
			
		||||
	/* Documented linux kernel segments */
 | 
			
		||||
	/* 0x10 4GB flat code segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x18 4GB flat data segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
 | 
			
		||||
	/* 0x20 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	/* 0x28 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	/* 0x30 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	/* 0x38 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	/* 0x40 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	/* 0x48 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	/* 0x50 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	/* 0x58 dummy */
 | 
			
		||||
	.word	0x0000, 0x0000, 0x0000, 0x000
 | 
			
		||||
	
 | 
			
		||||
	/* Segments used by the 2.5.x kernel */
 | 
			
		||||
	/* 0x60 4GB flat code segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x68 4GB flat data segment */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
gdt_end:
 | 
			
		||||
	
 | 
			
		||||
	.data 
 | 
			
		||||
	.balign 4
 | 
			
		||||
entry32_regs:  
 | 
			
		||||
eax:	.long 0x00000000
 | 
			
		||||
ebx:	.long 0x00000000
 | 
			
		||||
ecx:	.long 0x00000000
 | 
			
		||||
edx:	.long 0x00000000
 | 
			
		||||
esi:	.long 0x00000000
 | 
			
		||||
edi:	.long 0x00000000
 | 
			
		||||
esp:	.long 0x00000000
 | 
			
		||||
ebp:	.long 0x00000000
 | 
			
		||||
eip:	.long entry16
 | 
			
		||||
	.size entry32_regs, . - entry32_regs
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										316
									
								
								purgatory/arch/i386/include/arch/debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								purgatory/arch/i386/include/arch/debug.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,316 @@
 | 
			
		||||
/* Base Address */
 | 
			
		||||
#define TTYS0_BASE	0x3f8
 | 
			
		||||
/* Data */
 | 
			
		||||
#define TTYS0_RBR (TTYS0_BASE+0x00)
 | 
			
		||||
#define TTYS0_TBR (TTYS0_BASE+0x00)
 | 
			
		||||
/* Control */
 | 
			
		||||
#define TTYS0_IER (TTYS0_BASE+0x01)
 | 
			
		||||
#define TTYS0_IIR (TTYS0_BASE+0x02)
 | 
			
		||||
#define TTYS0_FCR (TTYS0_BASE+0x02)
 | 
			
		||||
#define TTYS0_LCR (TTYS0_BASE+0x03)
 | 
			
		||||
#define TTYS0_MCR (TTYS0_BASE+0x04)
 | 
			
		||||
 | 
			
		||||
#define TTYS0_DLL (TTYS0_BASE+0x00)
 | 
			
		||||
#define TTYS0_DLM (TTYS0_BASE+0x01)
 | 
			
		||||
/* Status */
 | 
			
		||||
#define TTYS0_LSR (TTYS0_BASE+0x05)
 | 
			
		||||
#define TTYS0_MSR (TTYS0_BASE+0x06)
 | 
			
		||||
#define TTYS0_SCR (TTYS0_BASE+0x07)
 | 
			
		||||
 | 
			
		||||
#define TTYS0_BAUD 9600
 | 
			
		||||
#define TTYS0_DIV  (115200/TTYS0_BAUD)
 | 
			
		||||
#define TTYS0_DIV_LO	(TTYS0_DIV&0xFF)
 | 
			
		||||
#define TTYS0_DIV_HI	((TTYS0_DIV >> 8)&0xFF)
 | 
			
		||||
 | 
			
		||||
#if ((115200%TTYS0_BAUD) != 0)
 | 
			
		||||
#error Bad ttyS0 baud rate
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define TTYS0_INIT	\
 | 
			
		||||
	/* disable interrupts */	\
 | 
			
		||||
	movb	$0x00, %al		; \
 | 
			
		||||
	movw	$TTYS0_IER, %dx		; \
 | 
			
		||||
	outb	%al, %dx		; \
 | 
			
		||||
					; \
 | 
			
		||||
	/* enable fifos */		\
 | 
			
		||||
	movb	$0x01, %al		; \
 | 
			
		||||
	movw	$TTYS0_FCR, %dx		; \
 | 
			
		||||
	outb	%al, %dx		; \
 | 
			
		||||
					; \
 | 
			
		||||
	/* Set Baud Rate Divisor to TTYS0_BAUD */	\
 | 
			
		||||
	movw	$TTYS0_LCR, %dx		; \
 | 
			
		||||
	movb	$0x83, %al		; \
 | 
			
		||||
	outb	%al, %dx		; \
 | 
			
		||||
					; \
 | 
			
		||||
	movw	$TTYS0_DLL, %dx		; \
 | 
			
		||||
	movb	$TTYS0_DIV_LO, %al	; \
 | 
			
		||||
	outb	%al, %dx		; \
 | 
			
		||||
					; \
 | 
			
		||||
	movw	$TTYS0_DLM, %dx		; \
 | 
			
		||||
	movb	$TTYS0_DIV_HI, %al	; \
 | 
			
		||||
	outb	%al, %dx		; \
 | 
			
		||||
					; \
 | 
			
		||||
	movw	$TTYS0_LCR, %dx		; \
 | 
			
		||||
	movb	$0x03, %al		; \
 | 
			
		||||
	outb	%al, %dx
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_AL		\
 | 
			
		||||
	mov	%al, %ah	; \
 | 
			
		||||
9:	mov	$TTYS0_LSR, %dx	; \
 | 
			
		||||
	inb	%dx, %al	; \
 | 
			
		||||
	test	$0x20, %al	; \
 | 
			
		||||
	je	9b		; \
 | 
			
		||||
	mov	$TTYS0_TBR, %dx	; \
 | 
			
		||||
	mov	%ah, %al	; \
 | 
			
		||||
	outb	%al, %dx
 | 
			
		||||
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_CHAR(byte)	\
 | 
			
		||||
	mov	byte, %al	; \
 | 
			
		||||
	TTYS0_TX_AL
 | 
			
		||||
 | 
			
		||||
	/* uses:	eax, dx */
 | 
			
		||||
#define TTYS0_TX_HEX32(lword)	\
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$28, %eax	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$24, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$20, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$16, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$12, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$8, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$4, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL
 | 
			
		||||
 | 
			
		||||
	/* uses:	rax, dx */
 | 
			
		||||
#define TTYS0_TX_HEX64(lword)	\
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$60, %rax	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$56, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$52, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$48, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$44, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$40, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$36, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$32, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$28, %rax	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$24, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$20, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$16, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$12, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$8, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	shr	$4, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %rax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
#define DEBUG(x) TTYS0_TX_CHAR($x) ;  TTYS0_TX_CHAR($'\r') ;  TTYS0_TX_CHAR($'\n')
 | 
			
		||||
#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x); TTYS0_TX_CHAR($'\r') ;  TTYS0_TX_CHAR($'\n')
 | 
			
		||||
#define DEBUG_TX_HEX64(x) TTYS0_TX_HEX64(x); TTYS0_TX_CHAR($'\r') ;  TTYS0_TX_CHAR($'\n')
 | 
			
		||||
							
								
								
									
										98
									
								
								purgatory/arch/i386/include/arch/io.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								purgatory/arch/i386/include/arch/io.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
#ifndef ARCH_IO_H
 | 
			
		||||
#define ARCH_IO_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
/* Helper functions for directly doing I/O */
 | 
			
		||||
 | 
			
		||||
extern inline uint8_t inb(uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t result;
 | 
			
		||||
 | 
			
		||||
	__asm__ __volatile__ (
 | 
			
		||||
		"inb %w1,%0"
 | 
			
		||||
		:"=a" (result)
 | 
			
		||||
		:"Nd" (port));
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern inline uint16_t inw(uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
	uint16_t result;
 | 
			
		||||
 | 
			
		||||
	__asm__ __volatile__ (
 | 
			
		||||
		"inw %w1,%0"
 | 
			
		||||
		:"=a" (result)
 | 
			
		||||
		:"Nd" (port));
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern inline uint32_t inl(uint32_t port)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t result;
 | 
			
		||||
 | 
			
		||||
	__asm__ __volatile__ (
 | 
			
		||||
		"inl %w1,%0"
 | 
			
		||||
		:"=a" (result)
 | 
			
		||||
		:"Nd" (port));
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern inline void outb (uint8_t value, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ __volatile__ (
 | 
			
		||||
		"outb %b0,%w1"
 | 
			
		||||
		:
 | 
			
		||||
		:"a" (value), "Nd" (port));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern inline void outw (uint16_t value, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ __volatile__ (
 | 
			
		||||
		"outw %w0,%w1"
 | 
			
		||||
		:
 | 
			
		||||
		:"a" (value), "Nd" (port));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern inline void outl (uint32_t value, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ __volatile__ (
 | 
			
		||||
		"outl %0,%w1"
 | 
			
		||||
		:
 | 
			
		||||
		:"a" (value), "Nd" (port));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * readX/writeX() are used to access memory mapped devices. On some
 | 
			
		||||
 * architectures the memory mapped IO stuff needs to be accessed
 | 
			
		||||
 * differently. On the x86 architecture, we just read/write the
 | 
			
		||||
 * memory location directly.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static inline unsigned char readb(const volatile void  *addr)
 | 
			
		||||
{
 | 
			
		||||
	return *(volatile unsigned char *) addr;
 | 
			
		||||
}
 | 
			
		||||
static inline unsigned short readw(const volatile void  *addr)
 | 
			
		||||
{
 | 
			
		||||
	return *(volatile unsigned short *) addr;
 | 
			
		||||
}
 | 
			
		||||
static inline unsigned int readl(const volatile void  *addr)
 | 
			
		||||
{
 | 
			
		||||
	return *(volatile unsigned int *) addr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void writeb(unsigned char b, volatile void  *addr)
 | 
			
		||||
{
 | 
			
		||||
	*(volatile unsigned char *) addr = b;
 | 
			
		||||
}
 | 
			
		||||
static inline void writew(unsigned short b, volatile void  *addr)
 | 
			
		||||
{
 | 
			
		||||
	*(volatile unsigned short *) addr = b;
 | 
			
		||||
}
 | 
			
		||||
static inline void writel(unsigned int b, volatile void  *addr)
 | 
			
		||||
{
 | 
			
		||||
	*(volatile unsigned int *) addr = b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* ARCH_IO_H */
 | 
			
		||||
							
								
								
									
										58
									
								
								purgatory/arch/i386/include/limits.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								purgatory/arch/i386/include/limits.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
#ifndef LIMITS_H
 | 
			
		||||
#define LIMITS_H	1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Number of bits in a `char' */
 | 
			
		||||
#define CHAR_BIT	8
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed char' can hold */
 | 
			
		||||
#define SCHAR_MIN	(-128)
 | 
			
		||||
#define SCHAR_MAX	127
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UCHAR_MAX	255
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `char' can hold */
 | 
			
		||||
#define CHAR_MIN	SCHAR_MIN
 | 
			
		||||
#define CHAR_MAX	SCHAR_MAX
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed short int' can hold */
 | 
			
		||||
#define SHRT_MIN	(-32768)
 | 
			
		||||
#define SHRT_MAX	32767
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned short' can hold. (Minimum is 0.) */
 | 
			
		||||
#define USHRT_MAX	65535
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed int' can hold */
 | 
			
		||||
#define INT_MIN		(-INT_MAX - 1)
 | 
			
		||||
#define INT_MAX		2147483647
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UINT_MAX	4294967295U
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed int' can hold */
 | 
			
		||||
#define INT_MIN		(-INT_MAX - 1)
 | 
			
		||||
#define INT_MAX		2147483647
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
 | 
			
		||||
#define UINT_MAX	4294967295U
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed long' can hold */
 | 
			
		||||
#define LONG_MAX	2147483647L
 | 
			
		||||
#define LONG_MIN	(-LONG_MAX - 1L)
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned long' can hold. (Minimum is 0.) */
 | 
			
		||||
#define ULONG_MAX	4294967295UL
 | 
			
		||||
 | 
			
		||||
/* Minimum and maximum values a `signed long long' can hold */
 | 
			
		||||
#define LLONG_MAX	9223372036854775807LL
 | 
			
		||||
#define LLONG_MIN	(-LONG_MAX - 1LL)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Maximum value an `unsigned long long' can hold. (Minimum is 0.) */
 | 
			
		||||
#define ULLONG_MAX	18446744073709551615ULL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* LIMITS_H */
 | 
			
		||||
							
								
								
									
										16
									
								
								purgatory/arch/i386/include/stdint.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								purgatory/arch/i386/include/stdint.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#ifndef STDINT_H
 | 
			
		||||
#define STDINT_H
 | 
			
		||||
 | 
			
		||||
typedef unsigned long      size_t;
 | 
			
		||||
 | 
			
		||||
typedef unsigned char      uint8_t;
 | 
			
		||||
typedef unsigned short     uint16_t;
 | 
			
		||||
typedef unsigned int       uint32_t;
 | 
			
		||||
typedef unsigned long long uint64_t;
 | 
			
		||||
 | 
			
		||||
typedef signed char        int8_t;
 | 
			
		||||
typedef signed short       int16_t;
 | 
			
		||||
typedef signed int         int32_t;
 | 
			
		||||
typedef signed long long   int64_t;
 | 
			
		||||
 | 
			
		||||
#endif /* STDINT_H */
 | 
			
		||||
							
								
								
									
										623
									
								
								purgatory/arch/i386/linux-entry16.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										623
									
								
								purgatory/arch/i386/linux-entry16.S
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,623 @@
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
#define TTYS0_BASE	0x3f8
 | 
			
		||||
#define TTYS0_RBR (TTYS0_BASE+0x00)
 | 
			
		||||
#define TTYS0_TBR TTYS0_RBR
 | 
			
		||||
#define TTYS0_LSR (TTYS0_BASE+0x05)
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_AL		\
 | 
			
		||||
	mov	%al, %ah	; \
 | 
			
		||||
9:	mov	$TTYS0_LSR, %dx	; \
 | 
			
		||||
	inb	%dx, %al	; \
 | 
			
		||||
	test	$0x20, %al	; \
 | 
			
		||||
	je	9b		; \
 | 
			
		||||
	mov	$TTYS0_TBR, %dx	; \
 | 
			
		||||
	mov	%ah, %al	; \
 | 
			
		||||
	outb	%al, %dx	; \
 | 
			
		||||
9:	mov	$TTYS0_LSR, %dx	; \
 | 
			
		||||
	inb	%dx, %al	; \
 | 
			
		||||
	test	$0x40, %al	; \
 | 
			
		||||
	jz	9b
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_CHAR(byte)	\
 | 
			
		||||
	mov	byte, %al	; \
 | 
			
		||||
	TTYS0_TX_AL
 | 
			
		||||
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_HEX32(lword)	\
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$28, %eax	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$24, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$20, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$16, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$12, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$8, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$4, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define DEBUG(x) TTYS0_TX_CHAR($x) ;  TTYS0_TX_CHAR($'\r') ;  TTYS0_TX_CHAR($'\n')
 | 
			
		||||
#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ;  TTYS0_TX_CHAR($'\r') ;  TTYS0_TX_CHAR($'\n')
 | 
			
		||||
#else
 | 
			
		||||
#define DEBUG(x)
 | 
			
		||||
#define DEBUG_TX_HEX32(x)
 | 
			
		||||
#endif
 | 
			
		||||
	
 | 
			
		||||
#undef i386	
 | 
			
		||||
	.text
 | 
			
		||||
	.globl entry16, entry16_regs
 | 
			
		||||
	.arch i386
 | 
			
		||||
	.balign 16
 | 
			
		||||
entry16:
 | 
			
		||||
	.code32
 | 
			
		||||
 | 
			
		||||
DEBUG('a')	
 | 
			
		||||
	/* Setup the classic BIOS interrupt table at 0x0 */
 | 
			
		||||
	lidt	idtptr
 | 
			
		||||
 | 
			
		||||
DEBUG('b')		
 | 
			
		||||
	/* Provide us with 16bit segments that we can use */
 | 
			
		||||
	lgdt	gdt
 | 
			
		||||
 | 
			
		||||
DEBUG('c')	
 | 
			
		||||
	/* Note we don't disable the a20 line, (this shouldn't be required)
 | 
			
		||||
	 * The code to do it is in kexec_test and it is a real pain.
 | 
			
		||||
	 * I will worry about that when I need it.
 | 
			
		||||
	 */
 | 
			
		||||
	
 | 
			
		||||
	/* Load 16bit data segments, to ensure the segment limits are set */
 | 
			
		||||
	movl	$0x10, %eax
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
DEBUG('d')
 | 
			
		||||
 | 
			
		||||
	/* switch to 16bit mode */
 | 
			
		||||
	ljmp	$0x08, $1f - entry16
 | 
			
		||||
1:
 | 
			
		||||
	.code16
 | 
			
		||||
DEBUG('e')	
 | 
			
		||||
	/* Disable Paging and protected mode */
 | 
			
		||||
	/* clear the PG & PE bits of CR0 */
 | 
			
		||||
	movl	%cr0,%eax
 | 
			
		||||
	andl	$~((1 << 31)|(1<<0)),%eax
 | 
			
		||||
	movl	%eax,%cr0
 | 
			
		||||
 | 
			
		||||
DEBUG('f')
 | 
			
		||||
	/* make intersegment jmp to flush the processor pipeline
 | 
			
		||||
	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
 | 
			
		||||
	 */
 | 
			
		||||
	ljmp	*(realptr - entry16)
 | 
			
		||||
3:
 | 
			
		||||
DEBUG('g')
 | 
			
		||||
	/* we are in real mode now
 | 
			
		||||
	 * set up the real mode segment registers : %ds, $ss, %es
 | 
			
		||||
	 */
 | 
			
		||||
	/* Setup the data segment */
 | 
			
		||||
	movw	%cs, %ax
 | 
			
		||||
	movw	%ax, %ds
 | 
			
		||||
 | 
			
		||||
DEBUG('h')
 | 
			
		||||
	/* Load the registers */
 | 
			
		||||
	movl	eax - entry16, %eax
 | 
			
		||||
	movl	ebx - entry16, %ebx
 | 
			
		||||
	movl	ecx - entry16, %ecx
 | 
			
		||||
	movl	edx - entry16, %edx
 | 
			
		||||
	movl	esi - entry16, %esi
 | 
			
		||||
	movl	edi - entry16, %esi
 | 
			
		||||
	movl	esp - entry16, %esp
 | 
			
		||||
	movl	ebp - entry16, %ebp
 | 
			
		||||
	movw	es  - entry16, %es
 | 
			
		||||
	movw	ss  - entry16, %ss
 | 
			
		||||
	movw	fs  - entry16, %fs
 | 
			
		||||
	movw	gs  - entry16, %gs
 | 
			
		||||
	movw	ds  - entry16, %ds
 | 
			
		||||
 | 
			
		||||
	/* Jump to the kernel entrypoint */
 | 
			
		||||
	ljmp	%cs:*(realdest - entry16)
 | 
			
		||||
 | 
			
		||||
	.balign 4
 | 
			
		||||
entry16_regs:	
 | 
			
		||||
eax:	.long	0x00000000
 | 
			
		||||
ebx:	.long	0x00000000
 | 
			
		||||
ecx:	.long	0x00000000
 | 
			
		||||
edx:	.long	0x00000000
 | 
			
		||||
esi:	.long	0x00000000
 | 
			
		||||
edi:	.long	0x00000000
 | 
			
		||||
esp:	.long	0x00000000
 | 
			
		||||
ebp:	.long	0x00000000
 | 
			
		||||
ds:	.word	0x0000
 | 
			
		||||
es:	.word	0x0000
 | 
			
		||||
ss:	.word	0x0000
 | 
			
		||||
fs:	.word	0x0000
 | 
			
		||||
gs:	.word	0x0000
 | 
			
		||||
realdest:
 | 
			
		||||
ip:	.word	0x0000
 | 
			
		||||
cs:	.word	0x0000
 | 
			
		||||
	.size entry16_regs, . - entry16_regs	
 | 
			
		||||
 | 
			
		||||
	.balign 16
 | 
			
		||||
realptr:		
 | 
			
		||||
	.word	3b - entry16
 | 
			
		||||
	.word	0x0000
 | 
			
		||||
	
 | 
			
		||||
	.data
 | 
			
		||||
	.balign 4
 | 
			
		||||
 | 
			
		||||
idtptr:
 | 
			
		||||
	/* 256 entry idt at 0 */
 | 
			
		||||
	.word	0x400 - 1
 | 
			
		||||
	.word	0, 0
 | 
			
		||||
 | 
			
		||||
gdt:
 | 
			
		||||
	/* 0x00 unusable segment so used as the gdt ptr */
 | 
			
		||||
	.word gdt_end - gdt - 1
 | 
			
		||||
	.long gdt
 | 
			
		||||
	.word 0
 | 
			
		||||
 | 
			
		||||
	/* 0x08 16 bit real mode code segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x9b, 0x00, 0x00
 | 
			
		||||
 | 
			
		||||
	/* 0x10 16 bit real mode data segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x93, 0x00, 0x00
 | 
			
		||||
gdt_end:
 | 
			
		||||
/*
 | 
			
		||||
 * kexec: Linux boots Linux
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003,2004  Eric Biederman (ebiederm@xmission.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation (version 2 of the License).
 | 
			
		||||
 *
 | 
			
		||||
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
#define TTYS0_BASE	0x3f8
 | 
			
		||||
#define TTYS0_RBR (TTYS0_BASE+0x00)
 | 
			
		||||
#define TTYS0_TBR TTYS0_RBR
 | 
			
		||||
#define TTYS0_LSR (TTYS0_BASE+0x05)
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_AL		\
 | 
			
		||||
	mov	%al, %ah	; \
 | 
			
		||||
9:	mov	$TTYS0_LSR, %dx	; \
 | 
			
		||||
	inb	%dx, %al	; \
 | 
			
		||||
	test	$0x20, %al	; \
 | 
			
		||||
	je	9b		; \
 | 
			
		||||
	mov	$TTYS0_TBR, %dx	; \
 | 
			
		||||
	mov	%ah, %al	; \
 | 
			
		||||
	outb	%al, %dx	; \
 | 
			
		||||
9:	mov	$TTYS0_LSR, %dx	; \
 | 
			
		||||
	inb	%dx, %al	; \
 | 
			
		||||
	test	$0x40, %al	; \
 | 
			
		||||
	jz	9b
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_CHAR(byte)	\
 | 
			
		||||
	mov	byte, %al	; \
 | 
			
		||||
	TTYS0_TX_AL
 | 
			
		||||
 | 
			
		||||
	/* uses:	ax, dx */
 | 
			
		||||
#define TTYS0_TX_HEX32(lword)	\
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$28, %eax	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$24, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$20, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$16, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$12, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$8, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	shr	$4, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL		; \
 | 
			
		||||
				; \
 | 
			
		||||
	mov	lword, %eax	; \
 | 
			
		||||
	and	$0x0f, %al	; \
 | 
			
		||||
	add	$'0', %al	; \
 | 
			
		||||
	cmp	$'9', %al	; \
 | 
			
		||||
	jle	9f		; \
 | 
			
		||||
	add	$39, %al	; \
 | 
			
		||||
9:				; \
 | 
			
		||||
	TTYS0_TX_AL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define DEBUG(x) TTYS0_TX_CHAR($x) ;  TTYS0_TX_CHAR($'\r') ;  TTYS0_TX_CHAR($'\n')
 | 
			
		||||
#define DEBUG_TX_HEX32(x) TTYS0_TX_HEX32(x) ;  TTYS0_TX_CHAR($'\r') ;  TTYS0_TX_CHAR($'\n')
 | 
			
		||||
#else
 | 
			
		||||
#define DEBUG(x)
 | 
			
		||||
#define DEBUG_TX_HEX32(x)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
.data
 | 
			
		||||
	.globl setup16_debug_start, setup16_debug_end, setup16_debug_size, setup16_debug_align
 | 
			
		||||
	.globl setup16_debug_regs
 | 
			
		||||
	.globl setup16_debug_kernel_pre_protected
 | 
			
		||||
	.globl setup16_debug_first_code32
 | 
			
		||||
	.globl setup16_debug_old_code32
 | 
			
		||||
setup16_debug_start:
 | 
			
		||||
_reloc = .
 | 
			
		||||
	.balign 16
 | 
			
		||||
	.code32
 | 
			
		||||
DEBUG('a')
 | 
			
		||||
	/* Compute where I am running at */
 | 
			
		||||
	call	1f
 | 
			
		||||
1:	popl	%ebx
 | 
			
		||||
	subl	$(1b - _reloc), %ebx
 | 
			
		||||
 | 
			
		||||
	/* Remember where I am running at */
 | 
			
		||||
	movl	%ebx, location - _reloc(%ebx)
 | 
			
		||||
	
 | 
			
		||||
DEBUG('b')
 | 
			
		||||
	/* Fixup my real mode segment */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shrl	$4, %eax
 | 
			
		||||
	movw	%ax, 2 + realptr - _reloc(%ebx)
 | 
			
		||||
 | 
			
		||||
DEBUG('c')
 | 
			
		||||
	/* Fixup the gdt */
 | 
			
		||||
	movl	%ebx, %eax
 | 
			
		||||
	shll	$16, %eax
 | 
			
		||||
	
 | 
			
		||||
	movl	%ebx, %ecx
 | 
			
		||||
	shrl	$16, %ecx
 | 
			
		||||
	andl	$0xff, %ecx
 | 
			
		||||
 | 
			
		||||
	movl	%ebx, %edx
 | 
			
		||||
	andl	$0xff000000, %edx
 | 
			
		||||
	orl	%edx, %ecx
 | 
			
		||||
	
 | 
			
		||||
	addl	%ebx, gdtaddr - _reloc(%ebx)
 | 
			
		||||
	addl	%ebx, debug_gdtaddr - _reloc(%ebx)
 | 
			
		||||
	orl	%eax, 0x08 + gdt - _reloc(%ebx)
 | 
			
		||||
	orl	%ecx, 0x0c + gdt - _reloc(%ebx)
 | 
			
		||||
	orl	%eax, 0x10 + gdt - _reloc(%ebx)
 | 
			
		||||
	orl	%ecx, 0x14 + gdt - _reloc(%ebx)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
DEBUG('d')
 | 
			
		||||
	/* Setup the classic BIOS interrupt table at 0x0 */
 | 
			
		||||
	lidt	idtptr - _reloc(%ebx)
 | 
			
		||||
	
 | 
			
		||||
	/* Provide us with 16bit segments that we can use */
 | 
			
		||||
	lgdt	gdtptr - _reloc(%ebx)
 | 
			
		||||
 | 
			
		||||
	/* Note we don't disable the a20 line, (this shouldn't be required)
 | 
			
		||||
	 * The code to do it is in kexec_test and it is a real pain.
 | 
			
		||||
	 * I will worry about that when I need it.
 | 
			
		||||
	 */
 | 
			
		||||
	
 | 
			
		||||
	/* Load 16bit data segments, to ensure the segment limits are set */
 | 
			
		||||
	movl	$0x10, %eax
 | 
			
		||||
	movl	%eax, %ds
 | 
			
		||||
	movl	%eax, %es
 | 
			
		||||
	movl	%eax, %ss
 | 
			
		||||
	movl	%eax, %fs
 | 
			
		||||
	movl	%eax, %gs
 | 
			
		||||
 | 
			
		||||
	/* switch to 16bit mode */
 | 
			
		||||
	
 | 
			
		||||
	ljmp	$0x08, $2f - _reloc
 | 
			
		||||
2:
 | 
			
		||||
	.code16
 | 
			
		||||
DEBUG('e')
 | 
			
		||||
	/* Disable Paging and protected mode */
 | 
			
		||||
	/* clear the PG & PE bits of CR0 */
 | 
			
		||||
	movl	%cr0,%eax
 | 
			
		||||
	andl	$~((1 << 31)|(1<<0)),%eax
 | 
			
		||||
	movl	%eax,%cr0
 | 
			
		||||
 | 
			
		||||
DEBUG('f')
 | 
			
		||||
	/* make intersegment jmp to flush the processor pipeline
 | 
			
		||||
	 * and reload %cs:%eip (to clear upper 16 bits of %eip).
 | 
			
		||||
	 */
 | 
			
		||||
	ljmp	*(realptr - _reloc)
 | 
			
		||||
3:
 | 
			
		||||
DEBUG('g')
 | 
			
		||||
	/* we are in real mode now
 | 
			
		||||
	 * set up the real mode segment registers : %ds, $ss, %es
 | 
			
		||||
	 */
 | 
			
		||||
	/* Setup the data segment */
 | 
			
		||||
	movw	%cs, %ax
 | 
			
		||||
	movw	%ax, %ds
 | 
			
		||||
 | 
			
		||||
DEBUG('h')
 | 
			
		||||
	/* Load the registers */
 | 
			
		||||
	movl	eax - _reloc, %eax
 | 
			
		||||
	movl	ebx - _reloc, %ebx
 | 
			
		||||
	movl	ecx - _reloc, %ecx
 | 
			
		||||
	movl	edx - _reloc, %edx
 | 
			
		||||
	movl	esi - _reloc, %esi
 | 
			
		||||
	movl	edi - _reloc, %esi
 | 
			
		||||
	movl	esp - _reloc, %esp
 | 
			
		||||
	movl	ebp - _reloc, %ebp
 | 
			
		||||
	movw	es - _reloc, %es
 | 
			
		||||
	movw	ss - _reloc, %ss
 | 
			
		||||
	movw	fs - _reloc, %fs
 | 
			
		||||
	movw	gs - _reloc, %gs
 | 
			
		||||
	movw	ds - _reloc, %ds
 | 
			
		||||
 | 
			
		||||
	/* Jump to the kernel entrypoint */
 | 
			
		||||
	ljmp	%cs:*(realdest - _reloc)
 | 
			
		||||
 | 
			
		||||
setup16_debug_regs:	
 | 
			
		||||
eax:	.long	0x00000000
 | 
			
		||||
ebx:	.long	0x00000000
 | 
			
		||||
ecx:	.long	0x00000000
 | 
			
		||||
edx:	.long	0x00000000
 | 
			
		||||
esi:	.long	0x00000000
 | 
			
		||||
edi:	.long	0x00000000
 | 
			
		||||
esp:	.long	0x00000000
 | 
			
		||||
ebp:	.long	0x00000000
 | 
			
		||||
ds:	.word	0x0000
 | 
			
		||||
es:	.word	0x0000
 | 
			
		||||
ss:	.word	0x0000
 | 
			
		||||
fs:	.word	0x0000
 | 
			
		||||
gs:	.word	0x0000
 | 
			
		||||
realdest:
 | 
			
		||||
ip:	.word	0x0000
 | 
			
		||||
cs:	.word	0x0000
 | 
			
		||||
 | 
			
		||||
	.balign 16
 | 
			
		||||
realptr:		
 | 
			
		||||
	.word	3b - _reloc
 | 
			
		||||
	.word	0x0000
 | 
			
		||||
	
 | 
			
		||||
idtptr:
 | 
			
		||||
	/* 256 entry idt at 0 */
 | 
			
		||||
	.word	0x400 - 1
 | 
			
		||||
	.word	0, 0
 | 
			
		||||
 | 
			
		||||
gdtptr:
 | 
			
		||||
	.word	gdt_end - gdt - 1
 | 
			
		||||
gdtaddr:
 | 
			
		||||
	.long	gdt - _reloc
 | 
			
		||||
 | 
			
		||||
gdt:
 | 
			
		||||
	/* dummy */
 | 
			
		||||
	.word 0, 0, 0, 0
 | 
			
		||||
 | 
			
		||||
	/* 16 bit real mode code segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x9b, 0x00, 0x00
 | 
			
		||||
 | 
			
		||||
	/* 16 bit real mode data segment */
 | 
			
		||||
	.word	0xffff, 0x0000
 | 
			
		||||
	.byte	0x00, 0x93, 0x00, 0x00
 | 
			
		||||
gdt_end:
 | 
			
		||||
 | 
			
		||||
debug_gdt:
 | 
			
		||||
	/* 0x00 */
 | 
			
		||||
	.word	debug_gdt_end - debug_gdt - 1
 | 
			
		||||
debug_gdtaddr:	
 | 
			
		||||
	.long	debug_gdt - _reloc
 | 
			
		||||
	.word 0
 | 
			
		||||
 | 
			
		||||
	/* 0x08 */
 | 
			
		||||
	.word	0, 0, 0, 0	/* Nothing in the first gdt entry */
 | 
			
		||||
 | 
			
		||||
	/* 0x10 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF,	0x00, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x18 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* 0x20 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF,	0x00, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x28 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* 0x30 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF,	0x00, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x38 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* 0x40 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF,	0x00, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x48 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* 0x50 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF,	0x00, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x58 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	/* 0x60 4Gb - (0x100000*0x1000 = 4Gb), base address = 0, code read/exec, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF,	0x00, 0x9A00, 0x00CF
 | 
			
		||||
	/* 0x68 4Gb - (0x100000*0x1000 = 4Gb*), base address = 0, data read/write, granularity = 4096, 386 */
 | 
			
		||||
	.word	0xFFFF, 0x0000, 0x9200, 0x00CF
 | 
			
		||||
debug_gdt_end:
 | 
			
		||||
	
 | 
			
		||||
		
 | 
			
		||||
setup16_debug_kernel_pre_protected:
 | 
			
		||||
	.code16
 | 
			
		||||
	DEBUG('i')
 | 
			
		||||
	cli					# no interrupts allowed !
 | 
			
		||||
	movb	$0x80, %al			# disable NMI for bootup
 | 
			
		||||
						# sequence
 | 
			
		||||
	outb	%al, $0x70
 | 
			
		||||
	lret
 | 
			
		||||
setup16_debug_first_code32:
 | 
			
		||||
	.code32
 | 
			
		||||
	.byte	0xbf	/* movl $0x12345678, %edi */
 | 
			
		||||
location:
 | 
			
		||||
	.long	0x12345678
 | 
			
		||||
	DEBUG('j')
 | 
			
		||||
	.byte	0xb8	/* movl $0x10000, %eax */
 | 
			
		||||
setup16_debug_old_code32:
 | 
			
		||||
	.long	0x10000
 | 
			
		||||
	jmp	%eax
 | 
			
		||||
setup16_debug_end:
 | 
			
		||||
setup16_debug_size:
 | 
			
		||||
	.long setup16_debug_end - setup16_debug_start
 | 
			
		||||
setup16_debug_align:
 | 
			
		||||
	.long 16
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user