kexec-tools-2.0.10/AUTHORS0000644001567400156740000000047311424244110014162 0ustar hormshormsEric Biederman Albert Herranz Jesse Barnes Khalid Aziz Hariprasad Nellitheertha Tim Deegan And others... Currently maintained by P: Simon Horman M: horms@verge.net.au L: kexec@lists.infradead.org kexec-tools-2.0.10/COPYING0000644001567400156740000004313011424244110014142 0ustar hormshorms 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. Copyright (C) 19yy 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. , 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. kexec-tools-2.0.10/INSTALL0000644001567400156740000000403611424244110014142 0ustar hormshormsInstallation ============ Checkout from git ----------------- If you use the tarball, you can just skip that section. If you checked out the kexec-tools from git repository, you have to build the Autoconf-generated file yourself with running ./bootstrap You have to install "autoconf" for that. After that, you should have a file called "configure" in the top-level directory of kexec-tools, and you can continue with the next step. General ------- You should check first if your favourite Linux distribution doesn't offer a package. If that package is recent enough, you should consider using that package instead. However, if you want to install kexec-tools from sources (1) Run ./configure [--prefix=/usr/local] [options]... e.g. ./configure --prefix=/usr/local For a full list of options run ./configure --help (2) Run make make (3) To install kexec-tools After following the above instructions to build-kexec tools, run make install Static compilation ------------------ To compile kexec-tools statically (i.e., independent of libraries that are present on the system), use LDFLAGS=-static ./configure instead. Cross compilation ----------------- Because kexec is also used in the embedded world, cross-compilation is supported. You cannot only set "CC", "LD", "CCFLAGS" and "LDFLAGS" environment variables for the ./configure call as usual, you can also set TARGET_CC -- the C compiler used for files that should run on the target TARGET_CCFLAGS -- compilation flags for $TARGET_CC TARGET_LD -- linker used for files that should run on the target Because the build process also requires files that must be executed during the build, you also need a host compiler, only the target compiler is not enough. BUILD_CC -- the C compiler used for files that should run on the host (the system that builds the kexec-tools) BUILD_CFLAGS -- compilation flags for $BUILD_CC kexec-tools-2.0.10/News0000644001567400156740000000537211424244110013754 0ustar hormshorms* 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 " 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. ### kexec-tools-2.0.10/TODO0000644001567400156740000000102011424244110013567 0ustar hormshorms- x86 handle x86 vmlinux parameter header allocation issues. There is a bug where it can get stomped but the current code does not allow us much flexibility in what we do with it. - 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 - Improve the documentation - Add support for loading a boot sector - Autobuilding of initramfs ### kexec-tools-2.0.10/Makefile.in0000644001567400156740000002155312417126536015177 0ustar hormshorms# Hey Emacs this is a -*- makefile-*- PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_VERSION = @PACKAGE_VERSION@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ libexecdir = @libexecdir@ datadir = @datadir@ datarootdir = @datarootdir@ sysconfdir = @sysconfdir@ sharedstatedir = @sharedstatedir@ localstatedir = @localstatedir@ libdir = @libdir@ infodir = @infodir@ mandir = @mandir@ includedir = @includedir@ # The target architecture ARCH = @ARCH@ SUBARCH = @SUBARCH@ OBJDIR = @OBJDIR@ target = @target@ host = @host@ # Compiler for building kexec CC = @CC@ CPP = @CPP@ LD = @LD@ AS = @AS@ OBJCOPY = @OBJCOPY@ AR = @AR@ # C compiler for binaries to run during the build BUILD_CC = @BUILD_CC@ BUILD_CFLAGS = @BUILD_CFLAGS@ TARGET_CC = @TARGET_CC@ TARGET_LD = @TARGET_LD@ TARGET_CFLAGS = @TARGET_CFLAGS@ # Base compiler flags. These are extended by the subcomponent-Makefiles # where necessary. CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/include -I$(srcdir)/util_lib/include \ -Iinclude/ $($(ARCH)_CPPFLAGS) CFLAGS = @CFLAGS@ -fno-strict-aliasing -Wall -Wstrict-prototypes PURGATORY_EXTRA_CFLAGS = @PURGATORY_EXTRA_CFLAGS@ ASFLAGS = @ASFLAGS@ $($(ARCH)_ASFLAGS) LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ # 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@ STRIP = @STRIP@ pkgdatadir = $(datadir)/$(PACKAGE_NAME) pkglibdir = $(libdir)/$(PACKAGE_NAME) pkgincludedir = $(includedir)/$(PACKAGE_NAME) # 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 = srcdir = @srcdir@ VPATH = .:$(srcdir) # install paths BUILD_PREFIX:=build SBINDIR=$(BUILD_PREFIX)/sbin BINDIR=$(BUILD_PREFIX)/bin LIBEXECDIR=$(BUILD_PREFIX)/libexec DATADIR=$(BUILD_PREFIX)/share SYSCONFDIR=$(BUILD_PREFIX)/etc SHAREDSTATEDIR=$(BUILD_PREFIX)/com LOCALSTATEDIR=$(BUILD_PREFIX)/var LIBDIR=$(BUILD_PREFIX)/lib INFODIR=$(BUILD_PREFIX)/info MANDIR=$(BUILD_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=$(BUILD_PREFIX)/include PKGDATADIR=$(DATADIR)/$(PACKAGE_NAME) PKGLIBDIR=$(LIBDIR)/$(PACKAGE_NAME) PKGINCLUDEIR=$(INCLUDEDIR)/$(PACKAGE_NAME) all: targets # generic build rules %.o: %.c @$(MKDIR) -p $(@D) $(COMPILE.c) -MD -o $@ $< %.o: %.S @$(MKDIR) -p $(@D) $(COMPILE.S) -MD -o $@ $< # collect objects to be removed in 'make clean' clean = dist = AUTHORS COPYING INSTALL News TODO Makefile.in configure.ac configure \ kexec-tools.spec.in config/ # utility function for converting a list of files (with extension) to # file.o (or file.d) format. objify = $(addsuffix .o, $(basename $(1))) depify = $(addsuffix .d, $(basename $(1))) # Documentation # include $(srcdir)/doc/Makefile # Headers # include $(srcdir)/include/Makefile # Utility function library # include $(srcdir)/util_lib/Makefile # # Stand alone utilities # include $(srcdir)/util/Makefile # # purgatory (code between kernels) # include $(srcdir)/purgatory/Makefile # # kexec (linux booting linux) # include $(srcdir)/kexec/Makefile # kdump (read a crashdump from memory) # include $(srcdir)/kdump/Makefile # vmcore-dmesg (read dmesg from a vmcore) # include $(srcdir)/vmcore-dmesg/Makefile # # kexec_test (test program) # include $(srcdir)/kexec_test/Makefile SPEC=$(PACKAGE_NAME).spec GENERATED_SRCS:= $(SPEC) TARBALL=$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar TARBALL.gz=$(TARBALL).gz SRCS:= $(dist) PSRCS:=$(foreach s, $(SRCS), $(PACKAGE_NAME)-$(PACKAGE_VERSION)/$(s)) PGSRCS:=$(foreach s, $(GENERATED_SRCS), $(PACKAGE_NAME)-$(PACKAGE_VERSION)/$(s)) MAN_PAGES:=$(KEXEC_MANPAGE) $(KDUMP_MANPAGE) $(VMCORE_DMESG_MANPAGE) BINARIES_i386:=$(KEXEC_TEST) BINARIES_x86_64:=$(KEXEC_TEST) BINARIES:=$(KEXEC) $(KDUMP) $(VMCORE_DMESG) $(BINARIES_$(ARCH)) TARGETS:=$(BINARIES) $(MAN_PAGES) targets: $(TARGETS) Makefile: Makefile.in config.status ./config.status configure: configure.ac cd $(srcdir) && autoheader && autoconf && rm -rf autom4te.cache tarball: $(TARBALL.gz) $(TARBALL): $(SRCS) $(GENERATED_SRCS) $(RM) -f $(PACKAGE_NAME)-$(PACKAGE_VERSION) $(LN) -s $(srcdir) $(PACKAGE_NAME)-$(PACKAGE_VERSION) $(TAR) -cf $@ $(PSRCS) $(RM) -f $(PACKAGE_NAME)-$(PACKAGE_VERSION) $(LN) -sf . $(PACKAGE_NAME)-$(PACKAGE_VERSION) $(TAR) -rf $@ $(PGSRCS) $(RM) -f $(PACKAGE_NAME)-$(PACKAGE_VERSION) @echo $(dist) $(TARBALL.gz): $(TARBALL) gzip -c < $^ > $@ rpm: $(TARBALL.gz) unset MAKEFLAGS MAKELEVEL; $(RPMBUILD) -ta $(TARBALL.gz) $(SPEC): kexec-tools.spec.in Makefile $(SED) -e 's,^Version: $$,Version: $(PACKAGE_VERSION),' $< > $@ echo:: @echo ARCH=$(ARCH) @echo BINARIES=$(BINARIES) @echo TARGETS=$(TARGETS) @echo CC=$(CC) @echo AR=$(AR) @echo LD=$(LD) @echo STRIP=$(STRIP) clean: $(RM) -f $(clean) $(RM) -rf build $(RM) -f $(TARBALL) $(TARBALL.gz) distclean: dist-clean dist-clean: clean $(RM) -f config.log config.status config.cache Makefile include/config.h $(RM) -f include/config.h.in configure $(SPEC) $(RM) -rf autom4te.cache install: $(TARGETS) for file in $(TARGETS) ; do \ if test `$(DIRNAME) $$file` = "$(SBINDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(sbindir)/; \ $(INSTALL) -m 755 $$file $(DESTDIR)/$(sbindir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(BINDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(bindir)/; \ $(INSTALL) -m 755 $$file $(DESTDIR)/$(bindir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(LIBEXECDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(libexecdir)/; \ $(INSTALL) -m 755 $$file $(DESTDIR)/$(libexecdir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(DATADIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(datadir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(datadir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(SYSCONFDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(sysconfdir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(sysconfdir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(SHAREDSTATEDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(sharedstatedir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(sharedstatedir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(LOCALSTATEDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(localstatedir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(localstatedir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(LIBDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(libdir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(libdir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(INFODIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(infodir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(infodir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN1DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man1; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man1; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN2DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man2; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man2; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN3DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man3/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man3/; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN4DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man4/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man4/; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN5DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man5/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man5/; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN6DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man6/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man6/; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN7DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man7/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man7/; \ fi; \ if test `$(DIRNAME) $$file` = "$(MAN8DIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(mandir)/man8/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(mandir)/man8/; \ fi; \ if test `$(DIRNAME) $$file` = "$(INCLUDEDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(includedir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(includedir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(PKGDATADIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(pkgdatadir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(pkgdatadir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(PKGLIBDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(pkglibdir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(pkglibdir)/; \ fi; \ if test `$(DIRNAME) $$file` = "$(PKGINCLUDEDIR)" ; then \ $(MKDIR) -p $(DESTDIR)/$(pkgincludedir)/; \ $(INSTALL) -m 644 $$file $(DESTDIR)/$(pkgincludedir)/; \ fi; \ done .PHONY: echo install all targets clean dist-clean distclean \ maintainer-clean maintainerclean tarball rpm kexec-tools-2.0.10/configure.ac0000644001567400156740000001334412542751523015416 0ustar hormshormsdnl dnl configure.ac for kexec-tools dnl dnl dnl ---Required AC_INIT(kexec-tools, 2.0.10) AC_CONFIG_AUX_DIR(./config) AC_CONFIG_HEADERS([include/config.h]) AC_LANG(C) AC_PROG_CC AC_DEFINE_UNQUOTED(PACKAGE_DATE, "`date '+%d %B %Y'`", [Define to the release date of this package]) dnl -- Compilation platform configuration dnl -- the host specifices the host machine for the kexec binary, the dnl -- the target specifies the architecture of the kernel to be kexeced. AC_CANONICAL_HOST AC_CANONICAL_TARGET dnl Compute ARCH from target cpu info case $target_cpu in i?86 ) ARCH="i386" ;; powerpc ) ARCH="ppc" ;; powerpc64 ) ARCH="ppc64" SUBARCH="BE" ;; powerpc64le ) ARCH="ppc64" SUBARCH="LE" ;; arm* ) ARCH="arm" ;; s390x|s390 ) ARCH="s390" ;; sh4|sh4a|sh3|sh ) ARCH="sh" ;; mips* ) ARCH="mips" ;; cris|crisv32 ) ARCH="cris" ;; ia64|x86_64|alpha|m68k ) ARCH="$target_cpu" ;; * ) AC_MSG_ERROR([unsupported architecture $target_cpu]) ;; esac dnl ---Options OBJDIR=`pwd`/objdir if test "${host_alias}" ; then OBJDIR="$OBJDIR-${host_alias}" fi if test "x$BUILD_CFLAGS" = "x" ; then BUILD_CFLAGS='-O2 -Wall' fi if test "x$TARGET_CFLAGS" = "x" ; then TARGET_CFLAGS='-O2 -Wall' fi AC_ARG_WITH([objdir], AC_HELP_STRING([--with-objdir=],[select directory for object files]), [ OBJDIR="$withval" ], [ OBJDIR="$OBJDIR" ]) AC_ARG_WITH([gamecube], AC_HELP_STRING([--with-gamecube],[enable gamecube support]), AC_DEFINE(WITH_GAMECUBE, 1, [Define to include gamecube support])) AC_ARG_WITH([zlib], AC_HELP_STRING([--without-zlib],[disable zlib support]), [ with_zlib="$withval"], [ with_zlib=yes ] ) AC_ARG_WITH([lzma], AC_HELP_STRING([--without-lzma],[disable lzma support]), [ with_lzma="$withval"], [ with_lzma=yes ] ) AC_ARG_WITH([xen], AC_HELP_STRING([--without-xen], [disable extended xen support]), [ with_xen="$withval"], [ with_xen=yes ] ) AC_ARG_WITH([booke], AC_HELP_STRING([--with-booke],[build for booke]), AC_DEFINE(CONFIG_BOOKE,1, [Define to build for BookE])) dnl ---Programs dnl To specify a different compiler, just 'export CC=/path/to/compiler' if test "${build}" != "${host}" ; then AC_CHECK_PROGS(BUILD_CC, [${build_alias}-gcc ${build}-gcc 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) AC_CHECK_TOOL([STRIP], strip, "no", $PATH) dnl Find compiler for target if test "${target}" != "${host}" ; then AC_CHECK_PROGS(TARGET_CC, [${target_alias}-gcc ${target}-gcc gcc]) AC_CHECK_PROGS(TARGET_LD, [${target_alias}-ld ${target}-ld ld]) else TARGET_CC="$CC" TARGET_LD="$LD" fi AC_MSG_CHECKING([whether $TARGET_CC accepts -fno-zero-initialized-in-bss]) saved_CFLAGS="$CFLAGS" saved_CC="$CC" CC="$TARGET_CC" CFLAGS="$CFLAGS -fno-zero-initialized-in-bss" AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,,)], PURGATORY_EXTRA_CFLAGS="-fno-zero-initialized-in-bss" AC_MSG_RESULT([Yes]), AC_MSG_RESULT([No])) CFLAGS="$saved_CFLAGS" CC="$saved_CC" AC_SUBST(PURGATORY_EXTRA_CFLAGS, [$PURGATORY_EXTRA_CFLAGS]) 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_MSG_NOTICE([zlib support disabled]))]) fi dnl See if I have a usable copy of lzma available if test "$with_lzma" = yes ; then AC_CHECK_HEADER(lzma.h, [AC_CHECK_LIB(lzma, lzma_code, , AC_MSG_NOTICE([lzma support disabled]))]) fi dnl find Xen control stack libraries if test "$with_xen" = yes ; then AC_CHECK_HEADER(xenctrl.h, [AC_CHECK_LIB(xenctrl, xc_kexec_load, , AC_MSG_NOTICE([Xen support disabled]))]) fi 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 if test "$STRIP" = "no"; then AC_MSG_ERROR([ strip not found]); fi dnl ---Output variables... AC_SUBST([BUILD_CC]) AC_SUBST([BUILD_CFLAGS]) AC_SUBST([TARGET_CC]) AC_SUBST([TARGET_LD]) AC_SUBST([TARGET_CFLAGS]) AC_SUBST([ASFLAGS]) AC_SUBST([ARCH]) AC_SUBST([SUBARCH]) AC_SUBST([OBJDIR]) AC_SUBST([INSTALL]) dnl ---Output AC_OUTPUT([Makefile]) kexec-tools-2.0.10/configure0000755001567400156740000052744512542751553015056 0ustar hormshorms#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for kexec-tools 2.0.10. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='kexec-tools' PACKAGE_TARNAME='kexec-tools' PACKAGE_VERSION='2.0.10' PACKAGE_STRING='kexec-tools 2.0.10' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS INSTALL OBJDIR SUBARCH ARCH ASFLAGS TARGET_CFLAGS BUILD_CFLAGS EGREP GREP DIRNAME XARGS FIND SED RPMBUILD TAR LN CP RM MKDIR INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM PURGATORY_EXTRA_CFLAGS TARGET_LD TARGET_CC STRIP AR OBJCOPY AS LD CPP BUILD_CC target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_objdir with_gamecube with_zlib with_lzma with_xen with_booke ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures kexec-tools 2.0.10 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/kexec-tools] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of kexec-tools 2.0.10:";; esac cat <<\_ACEOF Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-objdir= select directory for object files --with-gamecube enable gamecube support --without-zlib disable zlib support --without-lzma disable lzma support --without-xen disable extended xen support --with-booke build for booke Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF kexec-tools configure 2.0.10 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by kexec-tools $as_me 2.0.10, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in ./config "$srcdir"/./config; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in ./config \"$srcdir\"/./config" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ac_config_headers="$ac_config_headers include/config.h" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat >>confdefs.h <<_ACEOF #define PACKAGE_DATE "`date '+%d %B %Y'`" _ACEOF # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- case $target_cpu in i?86 ) ARCH="i386" ;; powerpc ) ARCH="ppc" ;; powerpc64 ) ARCH="ppc64" SUBARCH="BE" ;; powerpc64le ) ARCH="ppc64" SUBARCH="LE" ;; arm* ) ARCH="arm" ;; s390x|s390 ) ARCH="s390" ;; sh4|sh4a|sh3|sh ) ARCH="sh" ;; mips* ) ARCH="mips" ;; cris|crisv32 ) ARCH="cris" ;; ia64|x86_64|alpha|m68k ) ARCH="$target_cpu" ;; * ) as_fn_error $? "unsupported architecture $target_cpu" "$LINENO" 5 ;; esac OBJDIR=`pwd`/objdir if test "${host_alias}" ; then OBJDIR="$OBJDIR-${host_alias}" fi if test "x$BUILD_CFLAGS" = "x" ; then BUILD_CFLAGS='-O2 -Wall' fi if test "x$TARGET_CFLAGS" = "x" ; then TARGET_CFLAGS='-O2 -Wall' fi # Check whether --with-objdir was given. if test "${with_objdir+set}" = set; then : withval=$with_objdir; OBJDIR="$withval" else OBJDIR="$OBJDIR" fi # Check whether --with-gamecube was given. if test "${with_gamecube+set}" = set; then : withval=$with_gamecube; $as_echo "#define WITH_GAMECUBE 1" >>confdefs.h fi # Check whether --with-zlib was given. if test "${with_zlib+set}" = set; then : withval=$with_zlib; with_zlib="$withval" else with_zlib=yes fi # Check whether --with-lzma was given. if test "${with_lzma+set}" = set; then : withval=$with_lzma; with_lzma="$withval" else with_lzma=yes fi # Check whether --with-xen was given. if test "${with_xen+set}" = set; then : withval=$with_xen; with_xen="$withval" else with_xen=yes fi # Check whether --with-booke was given. if test "${with_booke+set}" = set; then : withval=$with_booke; $as_echo "#define CONFIG_BOOKE 1" >>confdefs.h fi if test "${build}" != "${host}" ; then for ac_prog in ${build_alias}-gcc ${build}-gcc gcc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_BUILD_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$BUILD_CC"; then ac_cv_prog_BUILD_CC="$BUILD_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_BUILD_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi BUILD_CC=$ac_cv_prog_BUILD_CC if test -n "$BUILD_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_CC" >&5 $as_echo "$BUILD_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$BUILD_CC" && break done else BUILD_CC="$CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LD"; then ac_cv_prog_LD="$LD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LD="${ac_tool_prefix}ld" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LD=$ac_cv_prog_LD if test -n "$LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LD"; then ac_ct_LD=$LD # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LD"; then ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LD="ld" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LD=$ac_cv_prog_ac_ct_LD if test -n "$ac_ct_LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LD" >&5 $as_echo "$ac_ct_LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LD" = x; then LD=""no"" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LD=$ac_ct_LD fi else LD="$ac_cv_prog_LD" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AS"; then ac_cv_prog_AS="$AS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AS="${ac_tool_prefix}as" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AS=$ac_cv_prog_AS if test -n "$AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5 $as_echo "$AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AS"; then ac_ct_AS=$AS # Extract the first word of "as", so it can be a program name with args. set dummy as; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AS"; then ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AS="as" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AS=$ac_cv_prog_ac_ct_AS if test -n "$ac_ct_AS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5 $as_echo "$ac_ct_AS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AS" = x; then AS=""no"" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AS=$ac_ct_AS fi else AS="$ac_cv_prog_AS" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objcopy", so it can be a program name with args. set dummy ${ac_tool_prefix}objcopy; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJCOPY+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJCOPY"; then ac_cv_prog_OBJCOPY="$OBJCOPY" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJCOPY="${ac_tool_prefix}objcopy" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJCOPY=$ac_cv_prog_OBJCOPY if test -n "$OBJCOPY"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5 $as_echo "$OBJCOPY" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJCOPY"; then ac_ct_OBJCOPY=$OBJCOPY # Extract the first word of "objcopy", so it can be a program name with args. set dummy objcopy; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJCOPY+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJCOPY"; then ac_cv_prog_ac_ct_OBJCOPY="$ac_ct_OBJCOPY" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJCOPY="objcopy" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJCOPY=$ac_cv_prog_ac_ct_OBJCOPY if test -n "$ac_ct_OBJCOPY"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJCOPY" >&5 $as_echo "$ac_ct_OBJCOPY" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJCOPY" = x; then OBJCOPY=""no"" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJCOPY=$ac_ct_OBJCOPY fi else OBJCOPY="$ac_cv_prog_OBJCOPY" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="""" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=""no"" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi if test "${target}" != "${host}" ; then for ac_prog in ${target_alias}-gcc ${target}-gcc gcc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_TARGET_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TARGET_CC"; then ac_cv_prog_TARGET_CC="$TARGET_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_TARGET_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi TARGET_CC=$ac_cv_prog_TARGET_CC if test -n "$TARGET_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TARGET_CC" >&5 $as_echo "$TARGET_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$TARGET_CC" && break done for ac_prog in ${target_alias}-ld ${target}-ld ld do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_TARGET_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TARGET_LD"; then ac_cv_prog_TARGET_LD="$TARGET_LD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_TARGET_LD="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi TARGET_LD=$ac_cv_prog_TARGET_LD if test -n "$TARGET_LD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TARGET_LD" >&5 $as_echo "$TARGET_LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$TARGET_LD" && break done else TARGET_CC="$CC" TARGET_LD="$LD" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $TARGET_CC accepts -fno-zero-initialized-in-bss" >&5 $as_echo_n "checking whether $TARGET_CC accepts -fno-zero-initialized-in-bss... " >&6; } saved_CFLAGS="$CFLAGS" saved_CC="$CC" CC="$TARGET_CC" CFLAGS="$CFLAGS -fno-zero-initialized-in-bss" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : PURGATORY_EXTRA_CFLAGS="-fno-zero-initialized-in-bss" { $as_echo "$as_me:${as_lineno-$LINENO}: result: Yes" >&5 $as_echo "Yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: No" >&5 $as_echo "No" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$saved_CFLAGS" CC="$saved_CC" PURGATORY_EXTRA_CFLAGS=$PURGATORY_EXTRA_CFLAGS # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "mkdir", so it can be a program name with args. set dummy mkdir; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MKDIR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MKDIR"; then ac_cv_prog_MKDIR="$MKDIR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MKDIR="mkdir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_MKDIR" && ac_cv_prog_MKDIR=""no"" fi fi MKDIR=$ac_cv_prog_MKDIR if test -n "$MKDIR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR" >&5 $as_echo "$MKDIR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RM"; then ac_cv_prog_RM="$RM" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RM="rm" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_RM" && ac_cv_prog_RM=""no"" fi fi RM=$ac_cv_prog_RM if test -n "$RM"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RM" >&5 $as_echo "$RM" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CP"; then ac_cv_prog_CP="$CP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CP="cp" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_CP" && ac_cv_prog_CP=""no"" fi fi CP=$ac_cv_prog_CP if test -n "$CP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CP" >&5 $as_echo "$CP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "ln", so it can be a program name with args. set dummy ln; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LN"; then ac_cv_prog_LN="$LN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LN="ln" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_LN" && ac_cv_prog_LN=""no"" fi fi LN=$ac_cv_prog_LN if test -n "$LN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LN" >&5 $as_echo "$LN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "tar", so it can be a program name with args. set dummy tar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_TAR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TAR"; then ac_cv_prog_TAR="$TAR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_TAR="tar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_TAR" && ac_cv_prog_TAR=""no"" fi fi TAR=$ac_cv_prog_TAR if test -n "$TAR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TAR" >&5 $as_echo "$TAR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rpmbuild", so it can be a program name with args. set dummy rpmbuild; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RPMBUILD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RPMBUILD"; then ac_cv_prog_RPMBUILD="$RPMBUILD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RPMBUILD="rpmbuild" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_RPMBUILD" && ac_cv_prog_RPMBUILD=""no"" fi fi RPMBUILD=$ac_cv_prog_RPMBUILD if test -n "$RPMBUILD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RPMBUILD" >&5 $as_echo "$RPMBUILD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_SED+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$SED"; then ac_cv_prog_SED="$SED" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_SED="sed" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_SED" && ac_cv_prog_SED=""no"" fi fi SED=$ac_cv_prog_SED if test -n "$SED"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5 $as_echo "$SED" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "find", so it can be a program name with args. set dummy find; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_FIND+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$FIND"; then ac_cv_prog_FIND="$FIND" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_FIND="find" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_FIND" && ac_cv_prog_FIND=""no"" fi fi FIND=$ac_cv_prog_FIND if test -n "$FIND"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FIND" >&5 $as_echo "$FIND" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "xargs", so it can be a program name with args. set dummy xargs; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_XARGS+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$XARGS"; then ac_cv_prog_XARGS="$XARGS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_XARGS="xargs" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_XARGS" && ac_cv_prog_XARGS=""no"" fi fi XARGS=$ac_cv_prog_XARGS if test -n "$XARGS"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XARGS" >&5 $as_echo "$XARGS" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "dirname", so it can be a program name with args. set dummy dirname; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DIRNAME+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DIRNAME"; then ac_cv_prog_DIRNAME="$DIRNAME" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DIRNAME="dirname" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_DIRNAME" && ac_cv_prog_DIRNAME=""no"" fi fi DIRNAME=$ac_cv_prog_DIRNAME if test -n "$DIRNAME"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DIRNAME" >&5 $as_echo "$DIRNAME" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "$with_zlib" = yes ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateInit_ in -lz" >&5 $as_echo_n "checking for inflateInit_ in -lz... " >&6; } if ${ac_cv_lib_z_inflateInit_+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inflateInit_ (); int main () { return inflateInit_ (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_z_inflateInit_=yes else ac_cv_lib_z_inflateInit_=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateInit_" >&5 $as_echo "$ac_cv_lib_z_inflateInit_" >&6; } if test "x$ac_cv_lib_z_inflateInit_" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBZ 1 _ACEOF LIBS="-lz $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: zlib support disabled" >&5 $as_echo "$as_me: zlib support disabled" >&6;} fi fi fi if test "$with_lzma" = yes ; then ac_fn_c_check_header_mongrel "$LINENO" "lzma.h" "ac_cv_header_lzma_h" "$ac_includes_default" if test "x$ac_cv_header_lzma_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for lzma_code in -llzma" >&5 $as_echo_n "checking for lzma_code in -llzma... " >&6; } if ${ac_cv_lib_lzma_lzma_code+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-llzma $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char lzma_code (); int main () { return lzma_code (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lzma_lzma_code=yes else ac_cv_lib_lzma_lzma_code=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_lzma_code" >&5 $as_echo "$ac_cv_lib_lzma_lzma_code" >&6; } if test "x$ac_cv_lib_lzma_lzma_code" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBLZMA 1 _ACEOF LIBS="-llzma $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: lzma support disabled" >&5 $as_echo "$as_me: lzma support disabled" >&6;} fi fi fi if test "$with_xen" = yes ; then ac_fn_c_check_header_mongrel "$LINENO" "xenctrl.h" "ac_cv_header_xenctrl_h" "$ac_includes_default" if test "x$ac_cv_header_xenctrl_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for xc_kexec_load in -lxenctrl" >&5 $as_echo_n "checking for xc_kexec_load in -lxenctrl... " >&6; } if ${ac_cv_lib_xenctrl_xc_kexec_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lxenctrl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char xc_kexec_load (); int main () { return xc_kexec_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_xenctrl_xc_kexec_load=yes else ac_cv_lib_xenctrl_xc_kexec_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xenctrl_xc_kexec_load" >&5 $as_echo "$ac_cv_lib_xenctrl_xc_kexec_load" >&6; } if test "x$ac_cv_lib_xenctrl_xc_kexec_load" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBXENCTRL 1 _ACEOF LIBS="-lxenctrl $LIBS" else { $as_echo "$as_me:${as_lineno-$LINENO}: Xen support disabled" >&5 $as_echo "$as_me: Xen support disabled" >&6;} fi fi fi if test "$CC" = "no"; then as_fn_error $? "cc not found" "$LINENO" 5; fi if test "$CPP" = "no"; then as_fn_error $? "cpp not found" "$LINENO" 5; fi if test "$LD" = "no"; then as_fn_error $? "ld not found" "$LINENO" 5; fi if test "$AS" = "no"; then as_fn_error $? "as not found" "$LINENO" 5; fi if test "$OBJCOPY" = "no"; then as_fn_error $? "objcopy not found" "$LINENO" 5; fi if test "$AR" = "no"; then as_fn_error $? "ar not found" "$LINENO" 5; fi if test "$MKDIR" = "no"; then as_fn_error $? " mkdir not found" "$LINENO" 5; fi if test "$RM" = "no"; then as_fn_error $? " rm not found" "$LINENO" 5; fi if test "$CP" = "no"; then as_fn_error $? " cp not found" "$LINENO" 5; fi if test "$LN" = "no"; then as_fn_error $? " ln not found" "$LINENO" 5; fi if test "$TAR" = "no"; then as_fn_error $? " tar not found" "$LINENO" 5; fi if test "$RPM" = "no"; then as_fn_error $? " rpm not found" "$LINENO" 5; fi if test "$SED" = "no"; then as_fn_error $? " sed not found" "$LINENO" 5; fi if test "$FIND" = "no"; then as_fn_error $? " find not found" "$LINENO" 5; fi if test "$XARGS" = "no"; then as_fn_error $? " xargs not found" "$LINENO" 5; fi if test "$DIRNAME" = "no"; then as_fn_error $? " dirname not found" "$LINENO" 5; fi if test "$STRIP" = "no"; then as_fn_error $? " strip not found" "$LINENO" 5; fi ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by kexec-tools $as_me 2.0.10, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ kexec-tools config.status 2.0.10 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "include/config.h") CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi kexec-tools-2.0.10/kexec-tools.spec.in0000644001567400156740000000202511662410557016641 0ustar hormshormsSummary: Load one kernel from another Name: kexec-tools Version: Release: 0 License: GPL Group: Development/Tools Source0:%{name}-%{version}.tar.gz Packager: Eric Biederman BuildRoot: %{_tmppath}/%{name} %description /sbin/kexec is a user space utility 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 %{_sbindir}/kdump %{_sbindir}/vmcore-dmesg %doc News %doc COPYING %doc TODO %{_mandir}/man8/kexec.8.gz %{_mandir}/man8/kdump.8.gz %{_mandir}/man8/vmcore-dmesg.8.gz %changelog * Tue Dec 16 2004 Eric Biederman - kexec-tools initialy packaged as an rpm. kexec-tools-2.0.10/config/0000755001567400156740000000000012417126536014371 5ustar hormshormskexec-tools-2.0.10/config/config.guess0000755001567400156740000012753612417126536016727 0ustar hormshorms#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2013-10-21' # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: kexec-tools-2.0.10/config/install-sh0000755001567400156740000003325612417126536016406 0ustar hormshorms#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # 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. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for `test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # 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 $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: kexec-tools-2.0.10/config/config.sub0000755001567400156740000010532712417126536016364 0ustar hormshorms#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-04-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: kexec-tools-2.0.10/doc/Makefile0000644001567400156740000000017611424244110015317 0ustar hormshormsdist += doc/Makefile \ doc/linux-i386-boot.txt \ doc/linux-i386-zero-page.txt \ doc/multiboot.html \ doc/nbi-spec.txt kexec-tools-2.0.10/doc/linux-i386-boot.txt0000644001567400156740000004034311424244110017207 0ustar hormshorms THE LINUX/I386 BOOT PROTOCOL ---------------------------- H. Peter Anvin 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 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 = ; if ( loading_initrd ) { ramdisk_image = ; ramdisk_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= 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= 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= An initrd should be loaded. The meaning of 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= The boot image which was loaded. Again, the meaning of 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. kexec-tools-2.0.10/doc/linux-i386-zero-page.txt0000644001567400156740000000607011424244110020134 0ustar hormshormsSummary 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 0xd00 - 0xeec EDDBUF (edd.S) for edd data kexec-tools-2.0.10/doc/multiboot.html0000644001567400156740000007163511424244110016573 0ustar hormshorms Multiboot Standard

Multiboot Standard

Version 0.6


Contents


Motivation

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.

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.


Terminology

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.

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.

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.


Scope and Requirements

Architectures

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.

Operating systems

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.

Boot sources

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.

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.

It is hoped that boot loaders will be created that support multiple loading mechanisms, increasing their portability, robustness, and user-friendliness.

Boot-time configuration

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.

Convenience to the OS

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.

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.

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.

Boot modules

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.

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.


Details

There are three main aspects of the boot-loader/OS image interface this standard must specify:

  • The format of the OS image as seen by the boot loader.
  • The state of the machine when the boot loader starts the OS.
  • The format of the information passed by the boot loader to the OS.

OS Image Format

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.

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:

	+-------------------+
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)
	+-------------------+
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.

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.

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.

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.

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.

All of the address fields enabled by flag bit 16 are physical addresses. The meaning of each is as follows:

  • header_addr -- 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.
  • load_addr -- 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.
  • load_end_addr -- 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.
  • bss_end_addr -- 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.
  • entry -- The physical address to which the boot loader should jump in order to start running the OS.
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.

Machine State

When the boot loader invokes the 32-bit operating system, the machine must have the following state:

  • CS must be a 32-bit read/execute code segment with an offset of 0 and a limit of 0xffffffff.
  • 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.
  • 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.).
  • Paging must be turned off.
  • The processor interrupt flag must be turned off.
  • 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).
  • EBX must contain the 32-bit physical address of the multiboot_info structure provided by the boot loader (see below).
All other processor registers and flag bits are undefined. This includes, in particular:

  • ESP: the 32-bit OS must create its own stack as soon as it needs one.
  • 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.
  • IDTR: The OS must leave interrupts disabled until it sets up its own IDT.
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.

Boot Information Format

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.

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.

The format of the multiboot_info structure (as defined so far) follows:

	+-------------------+
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)
	+-------------------+
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.

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.

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:

	+-------+-------+-------+-------+
	| drive | part1 | part2 | part3 |
	+-------+-------+-------+-------+
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.

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.

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.

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.

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:

	+-------------------+
0	| mod_start	    |
4	| mod_end	    |
	+-------------------+
8	| string	    |
	+-------------------+
12	| reserved (0)	    |
	+-------------------+
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.

NOTE: Bits 4 & 5 are mutually exclusive.

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:

	+-------------------+
28	| tabsize	    |
32	| strsize	    |
36	| addr		    |
40	| reserved (0)	    |
	+-------------------+
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.

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:

	+-------------------+
28	| num		    |
32	| size		    |
36	| addr		    |
40	| shndx		    |
	+-------------------+
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.

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):

	+-------------------+
-4	| size		    |
	+-------------------+
0	| BaseAddrLow	    |
4	| BaseAddrHigh	    |
8	| LengthLow	    |
12	| LengthHigh	    |
16	| Type		    |
	+-------------------+
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.

The map provided is guaranteed to list all standard RAM that should be available for normal use.


Authors

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
We would also like to thank the many other people have provided comments, ideas, information, and other forms of support for our work.

Revision History

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

Notes on PCs

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.

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 BIOS Device Mapping Techniques.

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 INT 15h, AX=E820h - Query System Address Map 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.


Example OS Code (from Bryan Ford)

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 Example Bootloader Code section below.

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:

        mach4-i386/include/mach/machine/multiboot.h
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:

        mach4-i386/boot
        mach4-i386/boot/bsd
        mach4-i386/boot/linux
The Mach kernel itself in this distribution contains code that demonstrates how to create a compliant OS. The following files are of primary relevance:

        mach4-i386/kernel/i386at/boothdr.S
        mach4-i386/kernel/i386at/model_dep.c
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.


Example Bootloader Code (from Erich Boleyn)

The GRUB bootloader project will be fully Multiboot-compliant, supporting all required and optional features present in this standard.

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 public release area.


erich@uruk.org

kexec-tools-2.0.10/doc/nbi-spec.txt0000644001567400156740000004605111424244110016122 0ustar hormshorms 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 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 kexec-tools-2.0.10/include/Makefile0000644001567400156740000000051211642166046016204 0ustar hormshormsdist += include/Makefile \ include/config.h \ include/config.h.in \ include/kexec-uImage.h \ include/x86/x86-linux.h \ include/x86/mb_info.h \ include/x86/mb_header.h \ include/elf.h \ include/image.h \ include/unused.h \ include/boot/linuxbios_tables.h \ include/boot/beoboot.h \ include/boot/elf_boot.h kexec-tools-2.0.10/include/config.h0000644001567400156740000000371312542751567016200 0ustar hormshorms/* include/config.h. Generated from config.h.in by configure. */ /* include/config.h.in. Generated from configure.ac by autoheader. */ /* Define to build for BookE */ /* #undef CONFIG_BOOKE */ /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 /* Define to 1 if you have the `lzma' library (-llzma). */ /* #undef HAVE_LIBLZMA */ /* Define to 1 if you have the `xenctrl' library (-lxenctrl). */ /* #undef HAVE_LIBXENCTRL */ /* Define to 1 if you have the `z' library (-lz). */ #define HAVE_LIBZ 1 /* Define to 1 if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "" /* Define to the release date of this package */ #define PACKAGE_DATE "25 June 2015" /* Define to the full name of this package. */ #define PACKAGE_NAME "kexec-tools" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "kexec-tools 2.0.10" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "kexec-tools" /* Define to the home page for this package. */ #define PACKAGE_URL "" /* Define to the version of this package. */ #define PACKAGE_VERSION "2.0.10" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define to include gamecube support */ /* #undef WITH_GAMECUBE */ kexec-tools-2.0.10/include/config.h.in0000644001567400156740000000337112473250726016577 0ustar hormshorms/* include/config.h.in. Generated from configure.ac by autoheader. */ /* Define to build for BookE */ #undef CONFIG_BOOKE /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `lzma' library (-llzma). */ #undef HAVE_LIBLZMA /* Define to 1 if you have the `xenctrl' library (-lxenctrl). */ #undef HAVE_LIBXENCTRL /* Define to 1 if you have the `z' library (-lz). */ #undef HAVE_LIBZ /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the release date of this package */ #undef PACKAGE_DATE /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to include gamecube support */ #undef WITH_GAMECUBE kexec-tools-2.0.10/include/kexec-uImage.h0000644001567400156740000000073712242534555017233 0ustar hormshorms#ifndef __KEXEC_UIMAGE_H__ #define __KEXEC_UIMAGE_H__ struct Image_info { const unsigned char *buf; off_t len; unsigned int base; unsigned int ep; }; int uImage_probe(const unsigned char *buf, off_t len, unsigned int arch); int uImage_probe_kernel(const unsigned char *buf, off_t len, unsigned int arch); int uImage_probe_ramdisk(const unsigned char *buf, off_t len, unsigned int arch); int uImage_load(const unsigned char *buf, off_t len, struct Image_info *info); #endif kexec-tools-2.0.10/include/x86/x86-linux.h0000644001567400156740000002041712417126536017133 0ustar hormshorms#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 E820NR 0x1e8 /* # entries in E820MAP */ #ifndef E820MAX #define E820MAX 128 /* number of entries in E820MAP */ #endif #ifndef ASSEMBLY #ifndef E820_RAM 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 } __attribute__((packed)); #endif /* FIXME expand on drive_info_)struct... */ struct drive_info_struct { uint8_t dummy[32]; }; struct sys_desc_table { uint16_t length; uint8_t table[30]; }; 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 */ }; /* * EDD stuff */ #define EDD_MBR_SIG_MAX 16 #define EDDMAXNR 6 /* number of edd_info structs starting at EDDBUF */ #define EDD_EXT_FIXED_DISK_ACCESS (1 << 0) #define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1) #define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2) #define EDD_EXT_64BIT_EXTENSIONS (1 << 3) #define EDD_DEVICE_PARAM_SIZE 74 struct edd_info { uint8_t device; uint8_t version; uint16_t interface_support; uint16_t legacy_max_cylinder; uint8_t legacy_max_head; uint8_t legacy_sectors_per_track; uint8_t edd_device_params[EDD_DEVICE_PARAM_SIZE]; } __attribute__ ((packed)); 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 ext_ramdisk_image; /* 0xc0 */ uint32_t ext_ramdisk_size; /* 0xc4 */ uint32_t ext_cmd_line_ptr; /* 0xc8 */ uint8_t reserved4_1[0x1c0 - 0xcc]; /* 0xe4 */ uint8_t efi_info[32]; /* 0x1c0 */ uint32_t alt_mem_k; /* 0x1e0 */ uint8_t reserved5[4]; /* 0x1e4 */ uint8_t e820_map_nr; /* 0x1e8 */ uint8_t eddbuf_entries; /* 0x1e9 */ uint8_t edd_mbr_sig_buf_entries; /* 0x1ea */ uint8_t reserved6[6]; /* 0x1eb */ 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_KEXEC 0x0D #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 /* 2.04+ */ uint32_t kernel_alignment; /* 0x230 */ uint8_t relocatable_kernel; /* 0x234 */ uint8_t min_alignment; /* 0x235 */ uint16_t xloadflags; /* 0x236 */ uint32_t cmdline_size; /* 0x238 */ uint32_t hardware_subarch; /* 0x23C */ uint64_t hardware_subarch_data; /* 0x240 */ uint32_t payload_offset; /* 0x248 */ uint32_t payload_length; /* 0x24C */ uint64_t setup_data; /* 0x250 */ uint64_t pref_address; /* 0x258 */ uint32_t init_size; /* 0x260 */ uint32_t handover_offset; /* 0x264 */ uint8_t reserved16[0x290 - 0x268]; /* 0x268 */ uint32_t edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 0x290 */ #endif struct e820entry e820_map[E820MAX]; /* 0x2d0 */ uint8_t _pad8[48]; /* 0xcd0 */ struct edd_info eddbuf[EDDMAXNR]; /* 0xd00 */ /* 0xeec */ #define COMMAND_LINE_SIZE 2048 }; struct x86_linux_faked_param_header { struct x86_linux_param_header hdr; /* 0x00 */ uint8_t command_line[COMMAND_LINE_SIZE]; /* 0x1000 */ // uint8_t reserved18[0x200]; /* 0x1800 - 0x2000 */ }; struct x86_linux_header { uint8_t reserved1[0xc0]; /* 0x000 */ uint32_t ext_ramdisk_image; /* 0x0c0 */ uint32_t ext_ramdisk_size; /* 0x0c4 */ uint32_t ext_cmd_line_ptr; /* 0x0c8 */ uint8_t reserved1_1[0x1f1-0xcc]; /* 0x0cc */ uint8_t setup_sects; /* 0x1f1 */ uint16_t root_flags; /* 0x1f2 */ uint32_t syssize; /* 0x1f4 */ uint16_t ram_size; /* 0x1f8 */ uint16_t vid_mode; /* 0x1fa */ uint16_t root_dev; /* 0x1fc */ uint16_t boot_sector_magic; /* 0x1fe */ /* 2.00+ */ uint16_t jump; /* 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 */ uint32_t bootsect_kludge; /* 0x220 */ /* 2.01+ */ uint16_t heap_end_ptr; /* 0x224 */ uint8_t ext_loader_ver; /* 0x226 */ uint8_t ext_loader_type; /* 0x227 */ /* 2.02+ */ uint32_t cmd_line_ptr; /* 0x228 */ /* 2.03+ */ uint32_t initrd_addr_max; /* 0x22c */ uint32_t kernel_alignment; /* 0x230 */ uint8_t relocatable_kernel; /* 0x234 */ uint8_t min_alignment; /* 0x235 */ uint16_t xloadflags; /* 0x236 */ uint32_t cmdline_size; /* 0x238 */ uint32_t hardware_subarch; /* 0x23C */ uint64_t hardware_subarch_data; /* 0x240 */ uint32_t payload_offset; /* 0x248 */ uint32_t payload_size; /* 0x24C */ uint64_t setup_data; /* 0x250 */ uint64_t pref_address; /* 0x258 */ uint32_t init_size; /* 0x260 */ uint32_t handover_offset; /* 0x264 */ } __attribute__((packed)); #endif /* ASSEMBLY */ #define DEFAULT_INITRD_ADDR_MAX 0x37FFFFFF #define DEFAULT_BZIMAGE_ADDR_MAX 0x37FFFFFF #endif /* X86_LINUX_H */ kexec-tools-2.0.10/include/x86/mb_info.h0000644001567400156740000001116611424244110016745 0ustar hormshorms/* * 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 kexec-tools-2.0.10/include/x86/mb_header.h0000644001567400156740000000524011424244110017236 0ustar hormshorms/* * 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 kexec-tools-2.0.10/include/elf.h0000644001567400156740000027533512417126536015505 0ustar hormshorms /* This file defines standard ELF types, structures, and macros. Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ian Lance Taylor . The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 12 April 2002 Modified by Eric Biederman so it can be used outside of glibc. */ #ifndef ELF_H #define ELF_H /* Standard ELF types. */ #include #include /* Type for a 16-bit quantity. */ typedef uint16_t Elf32_Half; typedef uint16_t Elf64_Half; /* Types for signed and unsigned 32-bit quantities. */ typedef uint32_t Elf32_Word; typedef int32_t Elf32_Sword; typedef uint32_t Elf64_Word; typedef int32_t Elf64_Sword; /* Types for signed and unsigned 64-bit quantities. */ typedef uint64_t Elf32_Xword; typedef int64_t Elf32_Sxword; typedef uint64_t Elf64_Xword; typedef int64_t Elf64_Sxword; /* Type of addresses. */ typedef uint32_t Elf32_Addr; typedef uint64_t Elf64_Addr; /* Type of file offsets. */ typedef uint32_t Elf32_Off; typedef uint64_t Elf64_Off; /* Type for section indices, which are 16-bit quantities. */ typedef uint16_t Elf32_Section; typedef uint16_t Elf64_Section; /* Type of symbol indices. */ typedef uint32_t Elf32_Symndx; typedef uint64_t Elf64_Symndx; /* Type for version symbol information. */ typedef Elf32_Half Elf32_Versym; typedef Elf64_Half Elf64_Versym; /* The ELF file header. This appears at the start of every ELF file. */ #define EI_NIDENT (16) typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr; typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf64_Half e_type; /* Object file type */ Elf64_Half e_machine; /* Architecture */ Elf64_Word e_version; /* Object file version */ Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ Elf64_Word e_flags; /* Processor-specific flags */ Elf64_Half e_ehsize; /* ELF header size in bytes */ Elf64_Half e_phentsize; /* Program header table entry size */ Elf64_Half e_phnum; /* Program header table entry count */ Elf64_Half e_shentsize; /* Section header table entry size */ Elf64_Half e_shnum; /* Section header table entry count */ Elf64_Half e_shstrndx; /* Section header string table index */ } Elf64_Ehdr; /* Fields in the e_ident array. The EI_* macros are indices into the array. The macros under each EI_* macro are the values the byte may have. */ #define EI_MAG0 0 /* File identification byte 0 index */ #define ELFMAG0 0x7f /* Magic number byte 0 */ #define EI_MAG1 1 /* File identification byte 1 index */ #define ELFMAG1 'E' /* Magic number byte 1 */ #define EI_MAG2 2 /* File identification byte 2 index */ #define ELFMAG2 'L' /* Magic number byte 2 */ #define EI_MAG3 3 /* File identification byte 3 index */ #define ELFMAG3 'F' /* Magic number byte 3 */ /* Conglomeration of the identification bytes, for easy testing as a word. */ #define ELFMAG "\177ELF" #define SELFMAG 4 #define EI_CLASS 4 /* File class byte index */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ #define ELFCLASSNUM 3 #define EI_DATA 5 /* Data encoding byte index */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* 2's complement, little endian */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ #define ELFDATANUM 3 #define EI_VERSION 6 /* File version byte index */ /* Value must be EV_CURRENT */ #define EI_OSABI 7 /* OS ABI identification */ #define ELFOSABI_NONE 0 /* UNIX System V ABI */ #define ELFOSABI_SYSV 0 /* Alias. */ #define ELFOSABI_HPUX 1 /* HP-UX */ #define ELFOSABI_NETBSD 2 /* NetBSD. */ #define ELFOSABI_LINUX 3 /* Linux. */ #define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ #define ELFOSABI_AIX 7 /* IBM AIX. */ #define ELFOSABI_IRIX 8 /* SGI Irix. */ #define ELFOSABI_FREEBSD 9 /* FreeBSD. */ #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ #define ELFOSABI_MODESTO 11 /* Novell Modesto. */ #define ELFOSABI_OPENBSD 12 /* OpenBSD. */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ #define EI_ABIVERSION 8 /* ABI version */ #define EI_PAD 9 /* Byte index of padding bytes */ /* Legal values for e_type (object file type). */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* Relocatable file */ #define ET_EXEC 2 /* Executable file */ #define ET_DYN 3 /* Shared object file */ #define ET_CORE 4 /* Core file */ #define ET_NUM 5 /* Number of defined types */ #define ET_LOOS 0xfe00 /* OS-specific range start */ #define ET_HIOS 0xfeff /* OS-specific range end */ #define ET_LOPROC 0xff00 /* Processor-specific range start */ #define ET_HIPROC 0xffff /* Processor-specific range end */ /* Legal values for e_machine (architecture). */ #define EM_NONE 0 /* No machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SUN SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola m68k family */ #define EM_88K 5 /* Motorola m88k family */ #define EM_486 6 /* Intel 80486 */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS R3000 big-endian */ #define EM_S370 9 /* Amdahl */ #define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ #define EM_RS6000 11 /* RS6000 */ #define EM_PARISC 15 /* HPPA */ #define EM_nCUBE 16 /* nCUBE */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* PowerPC 64-bit */ #define EM_S390 22 /* IBM S390 */ #define EM_V800 36 /* NEC V800 series */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* ARM */ #define EM_FAKE_ALPHA 41 /* Digital Alpha */ #define EM_SH 42 /* Hitachi SH */ #define EM_SPARCV9 43 /* SPARC v9 64-bit */ #define EM_TRICORE 44 /* Siemens Tricore */ #define EM_ARC 45 /* Argonaut RISC Core */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel Merced */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola Coldfire */ #define EM_68HC12 53 /* Motorola M68HC12 */ #define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ #define EM_PCP 55 /* Siemens PCP */ #define EM_NCPU 56 /* Sony nCPU embeeded RISC */ #define EM_NDR1 57 /* Denso NDR1 microprocessor */ #define EM_STARCORE 58 /* Motorola Start*Core processor */ #define EM_ME16 59 /* Toyota ME16 processor */ #define EM_ST100 60 /* STMicroelectronic ST100 processor */ #define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ #define EM_X86_64 62 /* AMD x86-64 architecture */ #define EM_PDSP 63 /* Sony DSP Processor */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ #define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ #define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ #define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ #define EM_SVX 73 /* Silicon Graphics SVx */ #define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ #define EM_VAX 75 /* Digital VAX */ #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ #define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ #define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ #define EM_HUANY 81 /* Harvard University machine-independent object files */ #define EM_PRISM 82 /* SiTera Prism */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ #define EM_FR30 84 /* Fujitsu FR30 */ #define EM_D10V 85 /* Mitsubishi D10V */ #define EM_D30V 86 /* Mitsubishi D30V */ #define EM_V850 87 /* NEC v850 */ #define EM_M32R 88 /* Mitsubishi M32R */ #define EM_MN10300 89 /* Matsushita MN10300 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ #define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ #define EM_NUM 95 /* If it is necessary to assign new unofficial EM_* values, please pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision with official or non-GNU unofficial values. */ #define EM_ALPHA 0x9026 /* Legal values for e_version (version). */ #define EV_NONE 0 /* Invalid ELF version */ #define EV_CURRENT 1 /* Current version */ #define EV_NUM 2 /* Section header. */ typedef struct { Elf32_Word sh_name; /* Section name (string tbl index) */ Elf32_Word sh_type; /* Section type */ Elf32_Word sh_flags; /* Section flags */ Elf32_Addr sh_addr; /* Section virtual addr at execution */ Elf32_Off sh_offset; /* Section file offset */ Elf32_Word sh_size; /* Section size in bytes */ Elf32_Word sh_link; /* Link to another section */ Elf32_Word sh_info; /* Additional section information */ Elf32_Word sh_addralign; /* Section alignment */ Elf32_Word sh_entsize; /* Entry size if section holds table */ } Elf32_Shdr; typedef struct { Elf64_Word sh_name; /* Section name (string tbl index) */ Elf64_Word sh_type; /* Section type */ Elf64_Xword sh_flags; /* Section flags */ Elf64_Addr sh_addr; /* Section virtual addr at execution */ Elf64_Off sh_offset; /* Section file offset */ Elf64_Xword sh_size; /* Section size in bytes */ Elf64_Word sh_link; /* Link to another section */ Elf64_Word sh_info; /* Additional section information */ Elf64_Xword sh_addralign; /* Section alignment */ Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; /* Special section indices. */ #define SHN_UNDEF 0 /* Undefined section */ #define SHN_LORESERVE 0xff00 /* Start of reserved indices */ #define SHN_LOPROC 0xff00 /* Start of processor-specific */ #define SHN_HIPROC 0xff1f /* End of processor-specific */ #define SHN_LOOS 0xff20 /* Start of OS-specific */ #define SHN_HIOS 0xff3f /* End of OS-specific */ #define SHN_ABS 0xfff1 /* Associated symbol is absolute */ #define SHN_COMMON 0xfff2 /* Associated symbol is common */ #define SHN_XINDEX 0xffff /* Index is in extra table. */ #define SHN_HIRESERVE 0xffff /* End of reserved indices */ /* Legal values for sh_type (section type). */ #define SHT_NULL 0 /* Section header table entry unused */ #define SHT_PROGBITS 1 /* Program data */ #define SHT_SYMTAB 2 /* Symbol table */ #define SHT_STRTAB 3 /* String table */ #define SHT_RELA 4 /* Relocation entries with addends */ #define SHT_HASH 5 /* Symbol hash table */ #define SHT_DYNAMIC 6 /* Dynamic linking information */ #define SHT_NOTE 7 /* Notes */ #define SHT_NOBITS 8 /* Program space with no data (bss) */ #define SHT_REL 9 /* Relocation entries, no addends */ #define SHT_SHLIB 10 /* Reserved */ #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ #define SHT_INIT_ARRAY 14 /* Array of constructors */ #define SHT_FINI_ARRAY 15 /* Array of destructors */ #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ #define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ #define SHT_SUNW_move 0x6ffffffa #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ #define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ #define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ #define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ #define SHT_HIOS 0x6fffffff /* End OS-specific type */ #define SHT_LOPROC 0x70000000 /* Start of processor-specific */ #define SHT_HIPROC 0x7fffffff /* End of processor-specific */ #define SHT_LOUSER 0x80000000 /* Start of application-specific */ #define SHT_HIUSER 0x8fffffff /* End of application-specific */ /* Legal values for sh_flags (section flags). */ #define SHF_WRITE (1 << 0) /* Writable */ #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ #define SHF_EXECINSTR (1 << 2) /* Executable */ #define SHF_MERGE (1 << 4) /* Might be merged */ #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ #define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ #define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ #define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling required */ #define SHF_GROUP (1 << 9) /* Section is member of a group. */ #define SHF_TLS (1 << 10) /* Section hold thread-local data. */ #define SHF_MASKOS 0x0ff00000 /* OS-specific. */ #define SHF_MASKPROC 0xf0000000 /* Processor-specific */ /* Section group handling. */ #define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ /* Symbol table entry. */ typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* No defined meaning, 0 */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; typedef struct { Elf64_Word st_name; /* Symbol name (string tbl index) */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* No defined meaning, 0 */ Elf64_Section st_shndx; /* Section index */ Elf64_Addr st_value; /* Symbol value */ Elf64_Xword st_size; /* Symbol size */ } Elf64_Sym; /* The syminfo section if available contains additional information about every dynamic symbol. */ typedef struct { Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ Elf32_Half si_flags; /* Per symbol flags */ } Elf32_Syminfo; typedef struct { Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ Elf64_Half si_flags; /* Per symbol flags */ } Elf64_Syminfo; /* Possible values for si_boundto. */ #define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ #define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ #define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ /* Possible bitmasks for si_flags. */ #define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ #define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ #define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ #define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy loaded */ /* Syminfo version values. */ #define SYMINFO_NONE 0 #define SYMINFO_CURRENT 1 #define SYMINFO_NUM 2 /* Special section index. */ #define SHN_UNDEF 0 /* No section, undefined symbol. */ /* How to extract and insert information held in the st_info field. */ #define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) #define ELF32_ST_TYPE(val) ((val) & 0xf) #define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) /* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ #define ELF64_ST_BIND(val) ELF32_ST_BIND (val) #define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) #define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) /* Legal values for ST_BIND subfield of st_info (symbol binding). */ #define STB_LOCAL 0 /* Local symbol */ #define STB_GLOBAL 1 /* Global symbol */ #define STB_WEAK 2 /* Weak symbol */ #define STB_NUM 3 /* Number of defined types. */ #define STB_LOOS 10 /* Start of OS-specific */ #define STB_HIOS 12 /* End of OS-specific */ #define STB_LOPROC 13 /* Start of processor-specific */ #define STB_HIPROC 15 /* End of processor-specific */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_NOTYPE 0 /* Symbol type is unspecified */ #define STT_OBJECT 1 /* Symbol is a data object */ #define STT_FUNC 2 /* Symbol is a code object */ #define STT_SECTION 3 /* Symbol associated with a section */ #define STT_FILE 4 /* Symbol's name is file name */ #define STT_COMMON 5 /* Symbol is a common data object */ #define STT_TLS 6 /* Symbol is thread-local data object*/ #define STT_NUM 7 /* Number of defined types. */ #define STT_LOOS 10 /* Start of OS-specific */ #define STT_HIOS 12 /* End of OS-specific */ #define STT_LOPROC 13 /* Start of processor-specific */ #define STT_HIPROC 15 /* End of processor-specific */ /* Symbol table indices are found in the hash buckets and chain table of a symbol hash table section. This special index value indicates the end of a chain, meaning no further symbols are found in that bucket. */ #define STN_UNDEF 0 /* End of a chain. */ /* How to extract and insert information held in the st_other field. */ #define ELF32_ST_VISIBILITY(o) ((o) & 0x03) /* For ELF64 the definitions are the same. */ #define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) /* Symbol visibility specification encoded in the st_other field. */ #define STV_DEFAULT 0 /* Default symbol visibility rules */ #define STV_INTERNAL 1 /* Processor specific hidden class */ #define STV_HIDDEN 2 /* Sym unavailable in other modules */ #define STV_PROTECTED 3 /* Not preemptible, not exported */ /* Relocation table entry without addend (in section of type SHT_REL). */ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ } Elf32_Rel; /* I have seen two different definitions of the Elf64_Rel and Elf64_Rela structures, so we'll leave them out until Novell (or whoever) gets their act together. */ /* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ typedef struct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ } Elf64_Rel; /* Relocation table entry with addend (in section of type SHT_RELA). */ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ Elf32_Sword r_addend; /* Addend */ } Elf32_Rela; typedef struct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */ } Elf64_Rela; /* How to extract and insert information held in the r_info field. */ #define ELF32_R_SYM(val) ((val) >> 8) #define ELF32_R_TYPE(val) ((val) & 0xff) #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i) & 0xffffffff) #define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) /* Program segment header. */ typedef struct { Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Word p_filesz; /* Segment size in file */ Elf32_Word p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Word p_align; /* Segment alignment */ } Elf32_Phdr; typedef struct { Elf64_Word p_type; /* Segment type */ Elf64_Word p_flags; /* Segment flags */ Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ Elf64_Xword p_filesz; /* Segment size in file */ Elf64_Xword p_memsz; /* Segment size in memory */ Elf64_Xword p_align; /* Segment alignment */ } Elf64_Phdr; /* Legal values for p_type (segment type). */ #define PT_NULL 0 /* Program header table entry unused */ #define PT_LOAD 1 /* Loadable program segment */ #define PT_DYNAMIC 2 /* Dynamic linking information */ #define PT_INTERP 3 /* Program interpreter */ #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved */ #define PT_PHDR 6 /* Entry for header table itself */ #define PT_TLS 7 /* Thread-local storage segment */ #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ #define PT_HISUNW 0x6fffffff #define PT_HIOS 0x6fffffff /* End of OS-specific */ #define PT_LOPROC 0x70000000 /* Start of processor-specific */ #define PT_HIPROC 0x7fffffff /* End of processor-specific */ /* Legal values for p_flags (segment flags). */ #define PF_X (1 << 0) /* Segment is executable */ #define PF_W (1 << 1) /* Segment is writable */ #define PF_R (1 << 2) /* Segment is readable */ #define PF_MASKOS 0x0ff00000 /* OS-specific */ #define PF_MASKPROC 0xf0000000 /* Processor-specific */ /* Legal values for note segment descriptor types for core files. */ #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ #define NT_FPREGSET 2 /* Contains copy of fpregset struct */ #define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ #define NT_PRXREG 4 /* Contains copy of prxregset struct */ #define NT_TASKSTRUCT 4 /* Contains copy of task structure */ #define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ #define NT_AUXV 6 /* Contains copy of auxv array */ #define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ #define NT_ASRS 8 /* Contains copy of asrset struct */ #define NT_PSTATUS 10 /* Contains copy of pstatus struct */ #define NT_PSINFO 13 /* Contains copy of psinfo struct */ #define NT_PRCRED 14 /* Contains copy of prcred struct */ #define NT_UTSNAME 15 /* Contains copy of utsname struct */ #define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ #define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ #define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/ /* Legal values for the note segment descriptor types for object files. */ #define NT_VERSION 1 /* Contains a version string. */ /* Dynamic section entry. */ typedef struct { Elf32_Sword d_tag; /* Dynamic entry type */ union { Elf32_Word d_val; /* Integer value */ Elf32_Addr d_ptr; /* Address value */ } d_un; } Elf32_Dyn; typedef struct { Elf64_Sxword d_tag; /* Dynamic entry type */ union { Elf64_Xword d_val; /* Integer value */ Elf64_Addr d_ptr; /* Address value */ } d_un; } Elf64_Dyn; /* Legal values for d_tag (dynamic entry type). */ #define DT_NULL 0 /* Marks end of dynamic section */ #define DT_NEEDED 1 /* Name of needed library */ #define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ #define DT_PLTGOT 3 /* Processor defined value */ #define DT_HASH 4 /* Address of symbol hash table */ #define DT_STRTAB 5 /* Address of string table */ #define DT_SYMTAB 6 /* Address of symbol table */ #define DT_RELA 7 /* Address of Rela relocs */ #define DT_RELASZ 8 /* Total size of Rela relocs */ #define DT_RELAENT 9 /* Size of one Rela reloc */ #define DT_STRSZ 10 /* Size of string table */ #define DT_SYMENT 11 /* Size of one symbol table entry */ #define DT_INIT 12 /* Address of init function */ #define DT_FINI 13 /* Address of termination function */ #define DT_SONAME 14 /* Name of shared object */ #define DT_RPATH 15 /* Library search path */ #define DT_SYMBOLIC 16 /* Start symbol search here */ #define DT_REL 17 /* Address of Rel relocs */ #define DT_RELSZ 18 /* Total size of Rel relocs */ #define DT_RELENT 19 /* Size of one Rel reloc */ #define DT_PLTREL 20 /* Type of reloc in PLT */ #define DT_DEBUG 21 /* For debugging; unspecified */ #define DT_TEXTREL 22 /* Reloc might modify .text */ #define DT_JMPREL 23 /* Address of PLT relocs */ #define DT_BIND_NOW 24 /* Process relocations of object */ #define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ #define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ #define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ #define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ #define DT_RUNPATH 29 /* Library search path */ #define DT_FLAGS 30 /* Flags for the object being loaded */ #define DT_ENCODING 32 /* Start of encoded range */ #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ #define DT_NUM 34 /* Number used */ #define DT_LOOS 0x60000000 /* Start of OS-specific */ #define DT_HIOS 0x6fffffff /* End of OS-specific */ #define DT_LOPROC 0x70000000 /* Start of processor-specific */ #define DT_HIPROC 0x7fffffff /* End of processor-specific */ #define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's approach. */ #define DT_VALRNGLO 0x6ffffd00 #define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ #define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ #define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ #define DT_CHECKSUM 0x6ffffdf8 #define DT_PLTPADSZ 0x6ffffdf9 #define DT_MOVEENT 0x6ffffdfa #define DT_MOVESZ 0x6ffffdfb #define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ #define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting the following DT_* entry. */ #define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ #define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ #define DT_VALRNGHI 0x6ffffdff #define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ #define DT_VALNUM 12 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the Dyn.d_un.d_ptr field of the Elf*_Dyn structure. If any adjustment is made to the ELF object after it has been built these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 #define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ #define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ #define DT_CONFIG 0x6ffffefa /* Configuration information. */ #define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ #define DT_AUDIT 0x6ffffefc /* Object auditing. */ #define DT_PLTPAD 0x6ffffefd /* PLT padding. */ #define DT_MOVETAB 0x6ffffefe /* Move table. */ #define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ #define DT_ADDRRNGHI 0x6ffffeff #define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ #define DT_ADDRNUM 10 /* The versioning entry types. The next are defined as part of the GNU extension. */ #define DT_VERSYM 0x6ffffff0 #define DT_RELACOUNT 0x6ffffff9 #define DT_RELCOUNT 0x6ffffffa /* These were chosen by Sun. */ #define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ #define DT_VERDEF 0x6ffffffc /* Address of version definition table */ #define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ #define DT_VERNEED 0x6ffffffe /* Address of table with needed versions */ #define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ #define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ #define DT_VERSIONTAGNUM 16 /* Sun added these machine-independent extensions in the "processor-specific" range. Be compatible. */ #define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ #define DT_FILTER 0x7fffffff /* Shared object to get values from */ #define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) #define DT_EXTRANUM 3 /* Values of `d_un.d_val' in the DT_FLAGS entry. */ #define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ #define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ #define DF_TEXTREL 0x00000004 /* Object contains text relocations */ #define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ #define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ /* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry in the dynamic section. */ #define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ #define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ #define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ #define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ #define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ #define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ #define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ #define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ #define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ #define DF_1_TRANS 0x00000200 #define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ #define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ #define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ #define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ #define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ #define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ #define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ /* Flags for the feature selection in DT_FEATURE_1. */ #define DTF_1_PARINIT 0x00000001 #define DTF_1_CONFEXP 0x00000002 /* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ #define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ #define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not generally available. */ /* Version definition sections. */ typedef struct { Elf32_Half vd_version; /* Version revision */ Elf32_Half vd_flags; /* Version information */ Elf32_Half vd_ndx; /* Version Index */ Elf32_Half vd_cnt; /* Number of associated aux entries */ Elf32_Word vd_hash; /* Version name hash value */ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ Elf32_Word vd_next; /* Offset in bytes to next verdef entry */ } Elf32_Verdef; typedef struct { Elf64_Half vd_version; /* Version revision */ Elf64_Half vd_flags; /* Version information */ Elf64_Half vd_ndx; /* Version Index */ Elf64_Half vd_cnt; /* Number of associated aux entries */ Elf64_Word vd_hash; /* Version name hash value */ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ } Elf64_Verdef; /* Legal values for vd_version (version revision). */ #define VER_DEF_NONE 0 /* No version */ #define VER_DEF_CURRENT 1 /* Current version */ #define VER_DEF_NUM 2 /* Given version number */ /* Legal values for vd_flags (version information flags). */ #define VER_FLG_BASE 0x1 /* Version definition of file itself */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ /* Versym symbol index values. */ #define VER_NDX_LOCAL 0 /* Symbol is local. */ #define VER_NDX_GLOBAL 1 /* Symbol is global. */ #define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ #define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ /* Auxialiary version information. */ typedef struct { Elf32_Word vda_name; /* Version or dependency names */ Elf32_Word vda_next; /* Offset in bytes to next verdaux entry */ } Elf32_Verdaux; typedef struct { Elf64_Word vda_name; /* Version or dependency names */ Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ } Elf64_Verdaux; /* Version dependency section. */ typedef struct { Elf32_Half vn_version; /* Version of structure */ Elf32_Half vn_cnt; /* Number of associated aux entries */ Elf32_Word vn_file; /* Offset of filename for this dependency */ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ Elf32_Word vn_next; /* Offset in bytes to next verneed entry */ } Elf32_Verneed; typedef struct { Elf64_Half vn_version; /* Version of structure */ Elf64_Half vn_cnt; /* Number of associated aux entries */ Elf64_Word vn_file; /* Offset of filename for this dependency */ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ Elf64_Word vn_next; /* Offset in bytes to next verneed entry */ } Elf64_Verneed; /* Legal values for vn_version (version revision). */ #define VER_NEED_NONE 0 /* No version */ #define VER_NEED_CURRENT 1 /* Current version */ #define VER_NEED_NUM 2 /* Given version number */ /* Auxiliary needed version information. */ typedef struct { Elf32_Word vna_hash; /* Hash value of dependency name */ Elf32_Half vna_flags; /* Dependency specific information */ Elf32_Half vna_other; /* Unused */ Elf32_Word vna_name; /* Dependency name string offset */ Elf32_Word vna_next; /* Offset in bytes to next vernaux entry */ } Elf32_Vernaux; typedef struct { Elf64_Word vna_hash; /* Hash value of dependency name */ Elf64_Half vna_flags; /* Dependency specific information */ Elf64_Half vna_other; /* Unused */ Elf64_Word vna_name; /* Dependency name string offset */ Elf64_Word vna_next; /* Offset in bytes to next vernaux entry */ } Elf64_Vernaux; /* Legal values for vna_flags. */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ /* Auxiliary vector. */ /* This vector is normally only used by the program interpreter. The usual definition in an ABI supplement uses the name auxv_t. The vector is not usually defined in a standard file, but it can't hurt. We rename it to avoid conflicts. The sizes of these types are an arrangement between the exec server and the program interpreter, so we don't fully specify them here. */ typedef struct { int a_type; /* Entry type */ union { long int a_val; /* Integer value */ void *a_ptr; /* Pointer value */ void (*a_fcn) (void); /* Function pointer value */ } a_un; } Elf32_auxv_t; typedef struct { long int a_type; /* Entry type */ union { long int a_val; /* Integer value */ void *a_ptr; /* Pointer value */ void (*a_fcn) (void); /* Function pointer value */ } a_un; } Elf64_auxv_t; /* Legal values for a_type (entry type). */ #define AT_NULL 0 /* End of vector */ #define AT_IGNORE 1 /* Entry should be ignored */ #define AT_EXECFD 2 /* File descriptor of program */ #define AT_PHDR 3 /* Program headers for program */ #define AT_PHENT 4 /* Size of program header entry */ #define AT_PHNUM 5 /* Number of program headers */ #define AT_PAGESZ 6 /* System page size */ #define AT_BASE 7 /* Base address of interpreter */ #define AT_FLAGS 8 /* Flags */ #define AT_ENTRY 9 /* Entry point of program */ #define AT_NOTELF 10 /* Program is not ELF */ #define AT_UID 11 /* Real uid */ #define AT_EUID 12 /* Effective uid */ #define AT_GID 13 /* Real gid */ #define AT_EGID 14 /* Effective gid */ #define AT_CLKTCK 17 /* Frequency of times() */ /* Some more special a_type values describing the hardware. */ #define AT_PLATFORM 15 /* String identifying platform. */ #define AT_HWCAP 16 /* Machine dependent hints about processor capabilities. */ /* This entry gives some information about the FPU initialization performed by the kernel. */ #define AT_FPUCW 18 /* Used FPU control word. */ /* Cache block sizes. */ #define AT_DCACHEBSIZE 19 /* Data cache block size. */ #define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ #define AT_UCACHEBSIZE 21 /* Unified cache block size. */ /* A special ignored value for PPC, used by the kernel to control the interpretation of the AUXV. Must be > 16. */ #define AT_IGNOREPPC 22 /* Entry should be ignored. */ #define AT_SECURE 23 /* Boolean, was exec setuid-like? */ /* Pointer to the global system page used for system calls and other nice things. */ #define AT_SYSINFO 32 #define AT_SYSINFO_EHDR 33 /* Note section contents. Each entry in the note section begins with a header of a fixed form. */ typedef struct { Elf32_Word n_namesz; /* Length of the note's name. */ Elf32_Word n_descsz; /* Length of the note's descriptor. */ Elf32_Word n_type; /* Type of the note. */ } Elf32_Nhdr; typedef struct { Elf64_Word n_namesz; /* Length of the note's name. */ Elf64_Word n_descsz; /* Length of the note's descriptor. */ Elf64_Word n_type; /* Type of the note. */ } Elf64_Nhdr; /* Known names of notes. */ /* Solaris entries in the note section have this name. */ #define ELF_NOTE_SOLARIS "SUNW Solaris" /* Note entries for GNU systems have this name. */ #define ELF_NOTE_GNU "GNU" /* Defined types of notes for Solaris. */ /* Value of descriptor (one word) is desired pagesize for the binary. */ #define ELF_NOTE_PAGESIZE_HINT 1 /* Defined note types for GNU systems. */ /* ABI information. The descriptor consists of words: word 0: OS descriptor word 1: major version of the ABI word 2: minor version of the ABI word 3: subminor version of the ABI */ #define ELF_NOTE_ABI 1 /* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI note section entry. */ #define ELF_NOTE_OS_LINUX 0 #define ELF_NOTE_OS_GNU 1 #define ELF_NOTE_OS_SOLARIS2 2 #define ELF_NOTE_OS_FREEBSD 3 /* Move records. */ typedef struct { Elf32_Xword m_value; /* Symbol value. */ Elf32_Word m_info; /* Size and index. */ Elf32_Word m_poffset; /* Symbol offset. */ Elf32_Half m_repeat; /* Repeat count. */ Elf32_Half m_stride; /* Stride info. */ } Elf32_Move; typedef struct { Elf64_Xword m_value; /* Symbol value. */ Elf64_Xword m_info; /* Size and index. */ Elf64_Xword m_poffset; /* Symbol offset. */ Elf64_Half m_repeat; /* Repeat count. */ Elf64_Half m_stride; /* Stride info. */ } Elf64_Move; /* Macro to construct move records. */ #define ELF32_M_SYM(info) ((info) >> 8) #define ELF32_M_SIZE(info) ((unsigned char) (info)) #define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) #define ELF64_M_SYM(info) ELF32_M_SYM (info) #define ELF64_M_SIZE(info) ELF32_M_SIZE (info) #define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) /* Motorola 68k specific definitions. */ /* Values for Elf32_Ehdr.e_flags. */ #define EF_CPU32 0x00810000 /* m68k relocs. */ #define R_68K_NONE 0 /* No reloc */ #define R_68K_32 1 /* Direct 32 bit */ #define R_68K_16 2 /* Direct 16 bit */ #define R_68K_8 3 /* Direct 8 bit */ #define R_68K_PC32 4 /* PC relative 32 bit */ #define R_68K_PC16 5 /* PC relative 16 bit */ #define R_68K_PC8 6 /* PC relative 8 bit */ #define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ #define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ #define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ #define R_68K_GOT32O 10 /* 32 bit GOT offset */ #define R_68K_GOT16O 11 /* 16 bit GOT offset */ #define R_68K_GOT8O 12 /* 8 bit GOT offset */ #define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ #define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ #define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ #define R_68K_PLT32O 16 /* 32 bit PLT offset */ #define R_68K_PLT16O 17 /* 16 bit PLT offset */ #define R_68K_PLT8O 18 /* 8 bit PLT offset */ #define R_68K_COPY 19 /* Copy symbol at runtime */ #define R_68K_GLOB_DAT 20 /* Create GOT entry */ #define R_68K_JMP_SLOT 21 /* Create PLT entry */ #define R_68K_RELATIVE 22 /* Adjust by program base */ /* Keep this the last entry. */ #define R_68K_NUM 23 /* Intel 80386 specific definitions. */ /* i386 relocs. */ #define R_386_NONE 0 /* No reloc */ #define R_386_32 1 /* Direct 32 bit */ #define R_386_PC32 2 /* PC relative 32 bit */ #define R_386_GOT32 3 /* 32 bit GOT entry */ #define R_386_PLT32 4 /* 32 bit PLT address */ #define R_386_COPY 5 /* Copy symbol at runtime */ #define R_386_GLOB_DAT 6 /* Create GOT entry */ #define R_386_JMP_SLOT 7 /* Create PLT entry */ #define R_386_RELATIVE 8 /* Adjust by program base */ #define R_386_GOTOFF 9 /* 32 bit offset to GOT */ #define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ #define R_386_32PLT 11 #define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ #define R_386_TLS_IE 15 /* Address of GOT entry for static TLS block offset */ #define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block offset */ #define R_386_TLS_LE 17 /* Offset relative to static TLS block */ #define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of general dynamic thread local data */ #define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of local dynamic thread local data in LE code */ #define R_386_16 20 #define R_386_PC16 21 #define R_386_8 22 #define R_386_PC8 23 #define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic thread local data */ #define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ #define R_386_TLS_GD_CALL 26 /* Relocation for call to __tls_get_addr() */ #define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ #define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic thread local data in LE code */ #define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ #define R_386_TLS_LDM_CALL 30 /* Relocation for call to __tls_get_addr() in LDM code */ #define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ #define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ #define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS block offset */ #define R_386_TLS_LE_32 34 /* Negated offset relative to static TLS block */ #define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ #define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ #define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ /* Keep this the last entry. */ #define R_386_NUM 38 /* SUN SPARC specific definitions. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_REGISTER 13 /* Global register reserved to app. */ /* Values for Elf64_Ehdr.e_flags. */ #define EF_SPARCV9_MM 3 #define EF_SPARCV9_TSO 0 #define EF_SPARCV9_PSO 1 #define EF_SPARCV9_RMO 2 #define EF_SPARC_LEDATA 0x800000 /* little endian data */ #define EF_SPARC_EXT_MASK 0xFFFF00 #define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ #define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ #define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ #define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ /* SPARC relocs. */ #define R_SPARC_NONE 0 /* No reloc */ #define R_SPARC_8 1 /* Direct 8 bit */ #define R_SPARC_16 2 /* Direct 16 bit */ #define R_SPARC_32 3 /* Direct 32 bit */ #define R_SPARC_DISP8 4 /* PC relative 8 bit */ #define R_SPARC_DISP16 5 /* PC relative 16 bit */ #define R_SPARC_DISP32 6 /* PC relative 32 bit */ #define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ #define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ #define R_SPARC_HI22 9 /* High 22 bit */ #define R_SPARC_22 10 /* Direct 22 bit */ #define R_SPARC_13 11 /* Direct 13 bit */ #define R_SPARC_LO10 12 /* Truncated 10 bit */ #define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ #define R_SPARC_GOT13 14 /* 13 bit GOT entry */ #define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ #define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ #define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ #define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ #define R_SPARC_COPY 19 /* Copy symbol at runtime */ #define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ #define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ #define R_SPARC_RELATIVE 22 /* Adjust by program base */ #define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ /* Additional Sparc64 relocs. */ #define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ #define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ #define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ #define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ #define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ #define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ #define R_SPARC_10 30 /* Direct 10 bit */ #define R_SPARC_11 31 /* Direct 11 bit */ #define R_SPARC_64 32 /* Direct 64 bit */ #define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ #define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ #define R_SPARC_HM10 35 /* High middle 10 bits of ... */ #define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ #define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ #define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ #define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ #define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ #define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ #define R_SPARC_7 43 /* Direct 7 bit */ #define R_SPARC_5 44 /* Direct 5 bit */ #define R_SPARC_6 45 /* Direct 6 bit */ #define R_SPARC_DISP64 46 /* PC relative 64 bit */ #define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ #define R_SPARC_HIX22 48 /* High 22 bit complemented */ #define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ #define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ #define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ #define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ #define R_SPARC_REGISTER 53 /* Global register usage */ #define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ #define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ #define R_SPARC_TLS_GD_HI22 56 #define R_SPARC_TLS_GD_LO10 57 #define R_SPARC_TLS_GD_ADD 58 #define R_SPARC_TLS_GD_CALL 59 #define R_SPARC_TLS_LDM_HI22 60 #define R_SPARC_TLS_LDM_LO10 61 #define R_SPARC_TLS_LDM_ADD 62 #define R_SPARC_TLS_LDM_CALL 63 #define R_SPARC_TLS_LDO_HIX22 64 #define R_SPARC_TLS_LDO_LOX10 65 #define R_SPARC_TLS_LDO_ADD 66 #define R_SPARC_TLS_IE_HI22 67 #define R_SPARC_TLS_IE_LO10 68 #define R_SPARC_TLS_IE_LD 69 #define R_SPARC_TLS_IE_LDX 70 #define R_SPARC_TLS_IE_ADD 71 #define R_SPARC_TLS_LE_HIX22 72 #define R_SPARC_TLS_LE_LOX10 73 #define R_SPARC_TLS_DTPMOD32 74 #define R_SPARC_TLS_DTPMOD64 75 #define R_SPARC_TLS_DTPOFF32 76 #define R_SPARC_TLS_DTPOFF64 77 #define R_SPARC_TLS_TPOFF32 78 #define R_SPARC_TLS_TPOFF64 79 /* Keep this the last entry. */ #define R_SPARC_NUM 80 /* For Sparc64, legal values for d_tag of Elf64_Dyn. */ #define DT_SPARC_REGISTER 0x70000001 #define DT_SPARC_NUM 2 /* Bits present in AT_HWCAP, primarily for Sparc32. */ #define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ #define HWCAP_SPARC_STBAR 2 #define HWCAP_SPARC_SWAP 4 #define HWCAP_SPARC_MULDIV 8 #define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ #define HWCAP_SPARC_ULTRA3 32 /* MIPS R3000 specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ #define EF_MIPS_PIC 2 /* Contains PIC code */ #define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ #define EF_MIPS_XGOT 8 #define EF_MIPS_64BIT_WHIRL 16 #define EF_MIPS_ABI2 32 #define EF_MIPS_ABI_ON32 64 #define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ /* Legal values for MIPS architecture level. */ #define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* The following are non-official names and should not be used. */ #define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* Special section indices. */ #define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ #define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ #define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ #define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ #define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ #define SHT_MIPS_MSYM 0x70000001 #define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ #define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ #define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ #define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ #define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ #define SHT_MIPS_PACKAGE 0x70000007 #define SHT_MIPS_PACKSYM 0x70000008 #define SHT_MIPS_RELD 0x70000009 #define SHT_MIPS_IFACE 0x7000000b #define SHT_MIPS_CONTENT 0x7000000c #define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ #define SHT_MIPS_SHDR 0x70000010 #define SHT_MIPS_FDESC 0x70000011 #define SHT_MIPS_EXTSYM 0x70000012 #define SHT_MIPS_DENSE 0x70000013 #define SHT_MIPS_PDESC 0x70000014 #define SHT_MIPS_LOCSYM 0x70000015 #define SHT_MIPS_AUXSYM 0x70000016 #define SHT_MIPS_OPTSYM 0x70000017 #define SHT_MIPS_LOCSTR 0x70000018 #define SHT_MIPS_LINE 0x70000019 #define SHT_MIPS_RFDESC 0x7000001a #define SHT_MIPS_DELTASYM 0x7000001b #define SHT_MIPS_DELTAINST 0x7000001c #define SHT_MIPS_DELTACLASS 0x7000001d #define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ #define SHT_MIPS_DELTADECL 0x7000001f #define SHT_MIPS_SYMBOL_LIB 0x70000020 #define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ #define SHT_MIPS_TRANSLATE 0x70000022 #define SHT_MIPS_PIXIE 0x70000023 #define SHT_MIPS_XLATE 0x70000024 #define SHT_MIPS_XLATE_DEBUG 0x70000025 #define SHT_MIPS_WHIRL 0x70000026 #define SHT_MIPS_EH_REGION 0x70000027 #define SHT_MIPS_XLATE_OLD 0x70000028 #define SHT_MIPS_PDR_EXCEPTION 0x70000029 /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ #define SHF_MIPS_MERGE 0x20000000 #define SHF_MIPS_ADDR 0x40000000 #define SHF_MIPS_STRINGS 0x80000000 #define SHF_MIPS_NOSTRIP 0x08000000 #define SHF_MIPS_LOCAL 0x04000000 #define SHF_MIPS_NAMES 0x02000000 #define SHF_MIPS_NODUPE 0x01000000 /* Symbol tables. */ /* MIPS specific values for `st_other'. */ #define STO_MIPS_DEFAULT 0x0 #define STO_MIPS_INTERNAL 0x1 #define STO_MIPS_HIDDEN 0x2 #define STO_MIPS_PROTECTED 0x3 #define STO_MIPS_SC_ALIGN_UNUSED 0xff /* MIPS specific values for `st_info'. */ #define STB_MIPS_SPLIT_COMMON 13 /* Entries found in sections of type SHT_MIPS_GPTAB. */ typedef union { struct { Elf32_Word gt_current_g_value; /* -G value used for compilation */ Elf32_Word gt_unused; /* Not used */ } gt_header; /* First entry in section */ struct { Elf32_Word gt_g_value; /* If this value were used for -G */ Elf32_Word gt_bytes; /* This many bytes would be used */ } gt_entry; /* Subsequent entries in section */ } Elf32_gptab; /* Entry found in sections of type SHT_MIPS_REGINFO. */ typedef struct { Elf32_Word ri_gprmask; /* General registers used */ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ Elf32_Sword ri_gp_value; /* $gp register value */ } Elf32_RegInfo; /* Entries found in sections of type SHT_MIPS_OPTIONS. */ typedef struct { unsigned char kind; /* Determines interpretation of the variable part of descriptor. */ unsigned char size; /* Size of descriptor, including header. */ Elf32_Section section; /* Section header index of section affected, 0 for global options. */ Elf32_Word info; /* Kind-specific information. */ } Elf_Options; /* Values for `kind' field in Elf_Options. */ #define ODK_NULL 0 /* Undefined. */ #define ODK_REGINFO 1 /* Register usage information. */ #define ODK_EXCEPTIONS 2 /* Exception processing options. */ #define ODK_PAD 3 /* Section padding options. */ #define ODK_HWPATCH 4 /* Hardware workarounds performed */ #define ODK_FILL 5 /* record the fill value used by the linker. */ #define ODK_TAGS 6 /* reserve space for desktop tools to write. */ #define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ #define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ /* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ #define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ #define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ #define OEX_PAGE0 0x10000 /* page zero must be mapped. */ #define OEX_SMM 0x20000 /* Force sequential memory mode? */ #define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ #define OEX_PRECISEFP OEX_FPDBUG #define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ #define OEX_FPU_INVAL 0x10 #define OEX_FPU_DIV0 0x08 #define OEX_FPU_OFLO 0x04 #define OEX_FPU_UFLO 0x02 #define OEX_FPU_INEX 0x01 /* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ #define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ #define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ #define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ #define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ #define OPAD_PREFIX 0x1 #define OPAD_POSTFIX 0x2 #define OPAD_SYMBOL 0x4 /* Entry found in `.options' section. */ typedef struct { Elf32_Word hwp_flags1; /* Extra flags. */ Elf32_Word hwp_flags2; /* Extra flags. */ } Elf_Options_Hw; /* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ #define OHWA0_R4KEOP_CHECKED 0x00000001 #define OHWA1_R4KEOP_CLEAN 0x00000002 /* MIPS relocs. */ #define R_MIPS_NONE 0 /* No reloc */ #define R_MIPS_16 1 /* Direct 16 bit */ #define R_MIPS_32 2 /* Direct 32 bit */ #define R_MIPS_REL32 3 /* PC relative 32 bit */ #define R_MIPS_26 4 /* Direct 26 bit shifted */ #define R_MIPS_HI16 5 /* High 16 bit */ #define R_MIPS_LO16 6 /* Low 16 bit */ #define R_MIPS_GPREL16 7 /* GP relative 16 bit */ #define R_MIPS_LITERAL 8 /* 16 bit literal entry */ #define R_MIPS_GOT16 9 /* 16 bit GOT entry */ #define R_MIPS_PC16 10 /* PC relative 16 bit */ #define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ #define R_MIPS_GPREL32 12 /* GP relative 32 bit */ #define R_MIPS_SHIFT5 16 #define R_MIPS_SHIFT6 17 #define R_MIPS_64 18 #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 #define R_MIPS_GOT_HI16 22 #define R_MIPS_GOT_LO16 23 #define R_MIPS_SUB 24 #define R_MIPS_INSERT_A 25 #define R_MIPS_INSERT_B 26 #define R_MIPS_DELETE 27 #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 #define R_MIPS_CALL_HI16 30 #define R_MIPS_CALL_LO16 31 #define R_MIPS_SCN_DISP 32 #define R_MIPS_REL16 33 #define R_MIPS_ADD_IMMEDIATE 34 #define R_MIPS_PJUMP 35 #define R_MIPS_RELGOT 36 #define R_MIPS_JALR 37 /* Keep this the last entry. */ #define R_MIPS_NUM 38 /* Legal values for p_type field of Elf32_Phdr. */ #define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ #define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ #define PT_MIPS_OPTIONS 0x70000002 /* Special program header types. */ #define PF_MIPS_LOCAL 0x10000000 /* Legal values for d_tag field of Elf32_Dyn. */ #define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ #define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ #define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ #define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ #define DT_MIPS_FLAGS 0x70000005 /* Flags */ #define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ #define DT_MIPS_MSYM 0x70000007 #define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ #define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ #define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ #define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ #define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ #define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ #define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ #define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ #define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ #define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ #define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ #define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in DT_MIPS_DELTA_CLASS. */ #define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ #define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in DT_MIPS_DELTA_INSTANCE. */ #define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ #define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in DT_MIPS_DELTA_RELOC. */ #define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta relocations refer to. */ #define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in DT_MIPS_DELTA_SYM. */ #define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the class declaration. */ #define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in DT_MIPS_DELTA_CLASSSYM. */ #define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ #define DT_MIPS_PIXIE_INIT 0x70000023 #define DT_MIPS_SYMBOL_LIB 0x70000024 #define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 #define DT_MIPS_LOCAL_GOTIDX 0x70000026 #define DT_MIPS_HIDDEN_GOTIDX 0x70000027 #define DT_MIPS_PROTECTED_GOTIDX 0x70000028 #define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ #define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ #define DT_MIPS_DYNSTR_ALIGN 0x7000002b #define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ #define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve function stored in GOT. */ #define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added by rld on dlopen() calls. */ #define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ #define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ #define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ #define DT_MIPS_NUM 0x32 /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ #define RHF_NONE 0 /* No flags */ #define RHF_QUICKSTART (1 << 0) /* Use quickstart */ #define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ #define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ #define RHF_NO_MOVE (1 << 3) #define RHF_SGI_ONLY (1 << 4) #define RHF_GUARANTEE_INIT (1 << 5) #define RHF_DELTA_C_PLUS_PLUS (1 << 6) #define RHF_GUARANTEE_START_INIT (1 << 7) #define RHF_PIXIE (1 << 8) #define RHF_DEFAULT_DELAY_LOAD (1 << 9) #define RHF_REQUICKSTART (1 << 10) #define RHF_REQUICKSTARTED (1 << 11) #define RHF_CORD (1 << 12) #define RHF_NO_UNRES_UNDEF (1 << 13) #define RHF_RLD_ORDER_SAFE (1 << 14) /* Entries found in sections of type SHT_MIPS_LIBLIST. */ typedef struct { Elf32_Word l_name; /* Name (string table index) */ Elf32_Word l_time_stamp; /* Timestamp */ Elf32_Word l_checksum; /* Checksum */ Elf32_Word l_version; /* Interface version */ Elf32_Word l_flags; /* Flags */ } Elf32_Lib; typedef struct { Elf64_Word l_name; /* Name (string table index) */ Elf64_Word l_time_stamp; /* Timestamp */ Elf64_Word l_checksum; /* Checksum */ Elf64_Word l_version; /* Interface version */ Elf64_Word l_flags; /* Flags */ } Elf64_Lib; /* Legal values for l_flags. */ #define LL_NONE 0 #define LL_EXACT_MATCH (1 << 0) /* Require exact match */ #define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ #define LL_REQUIRE_MINOR (1 << 2) #define LL_EXPORTS (1 << 3) #define LL_DELAY_LOAD (1 << 4) #define LL_DELTA (1 << 5) /* Entries found in sections of type SHT_MIPS_CONFLICT. */ typedef Elf32_Addr Elf32_Conflict; /* HPPA specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_PARISC_TRAPNL 1 /* Trap nil pointer dereference. */ #define EF_PARISC_EXT 2 /* Program uses arch. extensions. */ #define EF_PARISC_ARCH 0xffff0000 /* Architecture version. */ /* Defined values are: 0x020b PA-RISC 1.0 big-endian 0x0210 PA-RISC 1.1 big-endian 0x028b PA-RISC 1.0 little-endian 0x0290 PA-RISC 1.1 little-endian */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_PARISC_GOT 0x70000000 /* GOT for external data. */ #define SHT_PARISC_ARCH 0x70000001 /* Architecture extensions. */ #define SHT_PARISC_GLOBAL 0x70000002 /* Definition of $global$. */ #define SHT_PARISC_MILLI 0x70000003 /* Millicode routines. */ #define SHT_PARISC_UNWIND 0x70000004 /* Unwind information. */ #define SHT_PARISC_PLT 0x70000005 /* Procedure linkage table. */ #define SHT_PARISC_SDATA 0x70000006 /* Short initialized data. */ #define SHT_PARISC_SBSS 0x70000007 /* Short uninitialized data. */ #define SHT_PARISC_SYMEXTN 0x70000008 /* Argument/relocation info. */ #define SHT_PARISC_STUBS 0x70000009 /* Linker stubs. */ /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_PARISC_GLOBAL 0x10000000 /* Section defines dp. */ #define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ #define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ #define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ #define STT_HP_OPAQUE (STT_LOOS + 0x1) #define STT_HP_STUB (STT_LOOS + 0x2) /* HPPA relocs. */ #define R_PARISC_NONE 0 /* No reloc. */ #define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ #define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ #define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ #define R_PARISC_DIR14R 4 /* Right 14 bits of eff. address. */ #define R_PARISC_PCREL21L 5 /* PC-relative, left 21 bits. */ #define R_PARISC_PCREL14R 6 /* PC-relative, right 14 bits. */ #define R_PARISC_PCREL17C 7 /* Conditional PC-relative, ignore if displacement > 17bits. */ #define R_PARISC_PCREL17F 8 /* Conditional PC-relative, must fit in 17bits. */ #define R_PARISC_DPREL21L 9 /* DP-relative, left 21 bits. */ #define R_PARISC_DPREL14R 10 /* DP-relative, right 14 bits. */ #define R_PARISC_DPREL14F 11 /* DP-relative, must bit in 14 bits. */ #define R_PARISC_DLTREL21L 12 /* DLT-relative, left 21 bits. */ #define R_PARISC_DLTREL14R 13 /* DLT-relative, right 14 bits. */ #define R_PARISC_DLTREL14F 14 /* DLT-relative, must fit in 14 bits.*/ #define R_PARISC_DLTIND21L 15 /* DLT-relative indirect, left 21 bits. */ #define R_PARISC_DLTIND14R 16 /* DLT-relative indirect, right 14 bits. */ #define R_PARISC_DLTIND14F 17 /* DLT-relative indirect, must fit int 14 bits. */ #define R_PARISC_PLABEL32 18 /* Direct 32-bit reference to proc. */ /* Alpha specific definitions. */ /* Legal values for e_flags field of Elf64_Ehdr. */ #define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ #define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ /* Legal values for sh_type field of Elf64_Shdr. */ /* These two are primerily concerned with ECOFF debugging info. */ #define SHT_ALPHA_DEBUG 0x70000001 #define SHT_ALPHA_REGINFO 0x70000002 /* Legal values for sh_flags field of Elf64_Shdr. */ #define SHF_ALPHA_GPREL 0x10000000 /* Legal values for st_other field of Elf64_Sym. */ #define STO_ALPHA_NOPV 0x80 /* No PV required. */ #define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ /* Alpha relocs. */ #define R_ALPHA_NONE 0 /* No reloc */ #define R_ALPHA_REFLONG 1 /* Direct 32 bit */ #define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ #define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ #define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ #define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ #define R_ALPHA_GPDISP 6 /* Add displacement to GP */ #define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ #define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ #define R_ALPHA_SREL16 9 /* PC relative 16 bit */ #define R_ALPHA_SREL32 10 /* PC relative 32 bit */ #define R_ALPHA_SREL64 11 /* PC relative 64 bit */ #define R_ALPHA_OP_PUSH 12 /* OP stack push */ #define R_ALPHA_OP_STORE 13 /* OP stack pop and store */ #define R_ALPHA_OP_PSUB 14 /* OP stack subtract */ #define R_ALPHA_OP_PRSHIFT 15 /* OP stack right shift */ #define R_ALPHA_GPVALUE 16 #define R_ALPHA_GPRELHIGH 17 #define R_ALPHA_GPRELLOW 18 #define R_ALPHA_IMMED_GP_16 19 #define R_ALPHA_IMMED_GP_HI32 20 #define R_ALPHA_IMMED_SCN_HI32 21 #define R_ALPHA_IMMED_BR_HI32 22 #define R_ALPHA_IMMED_LO32 23 #define R_ALPHA_COPY 24 /* Copy symbol at runtime */ #define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_RELATIVE 27 /* Adjust by program base */ #define R_ALPHA_TLS_GD_HI 28 #define R_ALPHA_TLSGD 29 #define R_ALPHA_TLS_LDM 30 #define R_ALPHA_DTPMOD64 31 #define R_ALPHA_GOTDTPREL 32 #define R_ALPHA_DTPREL64 33 #define R_ALPHA_DTPRELHI 34 #define R_ALPHA_DTPRELLO 35 #define R_ALPHA_DTPREL16 36 #define R_ALPHA_GOTTPREL 37 #define R_ALPHA_TPREL64 38 #define R_ALPHA_TPRELHI 39 #define R_ALPHA_TPRELLO 40 #define R_ALPHA_TPREL16 41 /* Keep this the last entry. */ #define R_ALPHA_NUM 46 /* Magic values of the LITUSE relocation addend. */ #define LITUSE_ALPHA_ADDR 0 #define LITUSE_ALPHA_BASE 1 #define LITUSE_ALPHA_BYTOFF 2 #define LITUSE_ALPHA_JSR 3 #define LITUSE_ALPHA_TLS_GD 4 #define LITUSE_ALPHA_TLS_LDM 5 /* PowerPC specific declarations */ /* Values for Elf32/64_Ehdr.e_flags. */ #define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ /* Cygnus local bits below */ #define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ #define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */ /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 #define R_PPC_ADDR32 1 /* 32bit absolute address */ #define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ #define R_PPC_ADDR16 3 /* 16bit absolute address */ #define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ #define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ #define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ #define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 /* PC relative 26 bit */ #define R_PPC_REL14 11 /* PC relative 16 bit */ #define R_PPC_REL14_BRTAKEN 12 #define R_PPC_REL14_BRNTAKEN 13 #define R_PPC_GOT16 14 #define R_PPC_GOT16_LO 15 #define R_PPC_GOT16_HI 16 #define R_PPC_GOT16_HA 17 #define R_PPC_PLTREL24 18 #define R_PPC_COPY 19 #define R_PPC_GLOB_DAT 20 #define R_PPC_JMP_SLOT 21 #define R_PPC_RELATIVE 22 #define R_PPC_LOCAL24PC 23 #define R_PPC_UADDR32 24 #define R_PPC_UADDR16 25 #define R_PPC_REL32 26 #define R_PPC_PLT32 27 #define R_PPC_PLTREL32 28 #define R_PPC_PLT16_LO 29 #define R_PPC_PLT16_HI 30 #define R_PPC_PLT16_HA 31 #define R_PPC_SDAREL16 32 #define R_PPC_SECTOFF 33 #define R_PPC_SECTOFF_LO 34 #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* PowerPC relocations defined for the TLS access ABI. */ #define R_PPC_TLS 67 /* none (sym+add)@tls */ #define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ #define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ #define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ #define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ #define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ #define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ #define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ #define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ #define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ /* Keep this the last entry. */ #define R_PPC_NUM 95 /* The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 #define R_PPC_EMB_NADDR16 102 #define R_PPC_EMB_NADDR16_LO 103 #define R_PPC_EMB_NADDR16_HI 104 #define R_PPC_EMB_NADDR16_HA 105 #define R_PPC_EMB_SDAI16 106 #define R_PPC_EMB_SDA2I16 107 #define R_PPC_EMB_SDA2REL 108 #define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ #define R_PPC_EMB_MRKREF 110 #define R_PPC_EMB_RELSEC16 111 #define R_PPC_EMB_RELST_LO 112 #define R_PPC_EMB_RELST_HI 113 #define R_PPC_EMB_RELST_HA 114 #define R_PPC_EMB_BIT_FLD 115 #define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ /* Diab tool relocations. */ #define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ #define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ #define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ #define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ #define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ #define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ /* This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. */ #define R_PPC_TOC16 255 /* PowerPC64 relocations defined by the ABIs */ #define R_PPC64_NONE R_PPC_NONE #define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ #define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ #define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ #define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ #define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ #define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ #define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ #define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN #define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN #define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ #define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ #define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN #define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN #define R_PPC64_GOT16 R_PPC_GOT16 #define R_PPC64_GOT16_LO R_PPC_GOT16_LO #define R_PPC64_GOT16_HI R_PPC_GOT16_HI #define R_PPC64_GOT16_HA R_PPC_GOT16_HA #define R_PPC64_COPY R_PPC_COPY #define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT #define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT #define R_PPC64_RELATIVE R_PPC_RELATIVE #define R_PPC64_UADDR32 R_PPC_UADDR32 #define R_PPC64_UADDR16 R_PPC_UADDR16 #define R_PPC64_REL32 R_PPC_REL32 #define R_PPC64_PLT32 R_PPC_PLT32 #define R_PPC64_PLTREL32 R_PPC_PLTREL32 #define R_PPC64_PLT16_LO R_PPC_PLT16_LO #define R_PPC64_PLT16_HI R_PPC_PLT16_HI #define R_PPC64_PLT16_HA R_PPC_PLT16_HA #define R_PPC64_SECTOFF R_PPC_SECTOFF #define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO #define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI #define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA #define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ #define R_PPC64_ADDR64 38 /* doubleword64 S + A */ #define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ #define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ #define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ #define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ #define R_PPC64_UADDR64 43 /* doubleword64 S + A */ #define R_PPC64_REL64 44 /* doubleword64 S + A - P */ #define R_PPC64_PLT64 45 /* doubleword64 L + A */ #define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ #define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ #define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ #define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ #define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ #define R_PPC64_TOC 51 /* doubleword64 .TOC */ #define R_PPC64_PLTGOT16 52 /* half16* M + A */ #define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ #define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ #define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ #define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ #define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ #define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ #define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ #define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ #define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ #define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ #define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ #define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ #define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ #define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ /* PowerPC64 relocations defined for the TLS access ABI. */ #define R_PPC64_TLS 67 /* none (sym+add)@tls */ #define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ #define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ #define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ #define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ #define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ #define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ #define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ #define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ #define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ #define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ #define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ #define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ #define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ #define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ #define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ #define R_PPC64_REL16 249 /* half16 (sym+add-.) */ #define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ #define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ #define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ /* Keep this the last entry. */ #define R_PPC64_NUM 107 /* PowerPC64 specific values for the Dyn d_tag field. */ #define DT_PPC64_GLINK (DT_LOPROC + 0) #define DT_PPC64_NUM 1 /* ARM specific declarations */ /* Processor specific flags for the ELF header e_flags field. */ #define EF_ARM_RELEXEC 0x01 #define EF_ARM_HASENTRY 0x02 #define EF_ARM_INTERWORK 0x04 #define EF_ARM_APCS_26 0x08 #define EF_ARM_APCS_FLOAT 0x10 #define EF_ARM_PIC 0x20 #define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ #define EF_ARM_NEW_ABI 0x80 #define EF_ARM_OLD_ABI 0x100 /* Other constants defined in the ARM ELF spec. version B-01. */ /* NB. These conflict with values defined above. */ #define EF_ARM_SYMSARESORTED 0x04 #define EF_ARM_DYNSYMSUSESEGIDX 0x08 #define EF_ARM_MAPSYMSFIRST 0x10 #define EF_ARM_EABIMASK 0XFF000000 #define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) #define EF_ARM_EABI_UNKNOWN 0x00000000 #define EF_ARM_EABI_VER1 0x01000000 #define EF_ARM_EABI_VER2 0x02000000 /* Additional symbol types for Thumb */ #define STT_ARM_TFUNC 0xd /* ARM-specific values for sh_flags */ #define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ #define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined in the input to a link step */ /* ARM-specific program header flags */ #define PF_ARM_SB 0x10000000 /* Segment contains the location addressed by the static base */ /* ARM relocs. */ #define R_ARM_NONE 0 /* No reloc */ #define R_ARM_PC24 1 /* PC relative 26 bit branch */ #define R_ARM_ABS32 2 /* Direct 32 bit */ #define R_ARM_REL32 3 /* PC relative 32 bit */ #define R_ARM_PC13 4 #define R_ARM_ABS16 5 /* Direct 16 bit */ #define R_ARM_ABS12 6 /* Direct 12 bit */ #define R_ARM_THM_ABS5 7 #define R_ARM_ABS8 8 /* Direct 8 bit */ #define R_ARM_SBREL32 9 #define R_ARM_THM_PC22 10 #define R_ARM_THM_PC8 11 #define R_ARM_AMP_VCALL9 12 #define R_ARM_SWI24 13 #define R_ARM_THM_SWI8 14 #define R_ARM_XPC25 15 #define R_ARM_THM_XPC22 16 #define R_ARM_COPY 20 /* Copy symbol at runtime */ #define R_ARM_GLOB_DAT 21 /* Create GOT entry */ #define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ #define R_ARM_RELATIVE 23 /* Adjust by program base */ #define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ #define R_ARM_GOT32 26 /* 32 bit GOT entry */ #define R_ARM_PLT32 27 /* 32 bit PLT address */ #define R_ARM_ALU_PCREL_7_0 32 #define R_ARM_ALU_PCREL_15_8 33 #define R_ARM_ALU_PCREL_23_15 34 #define R_ARM_LDR_SBREL_11_0 35 #define R_ARM_ALU_SBREL_19_12 36 #define R_ARM_ALU_SBREL_27_20 37 #define R_ARM_GNU_VTENTRY 100 #define R_ARM_GNU_VTINHERIT 101 #define R_ARM_THM_PC11 102 /* thumb unconditional branch */ #define R_ARM_THM_PC9 103 /* thumb conditional branch */ #define R_ARM_RXPC25 249 #define R_ARM_RSBREL32 250 #define R_ARM_THM_RPC22 251 #define R_ARM_RREL32 252 #define R_ARM_RABS22 253 #define R_ARM_RPC24 254 #define R_ARM_RBASE 255 /* Keep this the last entry. */ #define R_ARM_NUM 256 /* IA-64 specific declarations. */ /* Processor specific flags for the Ehdr e_flags field. */ #define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ #define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ #define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ /* Processor specific values for the Phdr p_type field. */ #define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ #define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ /* Processor specific flags for the Phdr p_flags field. */ #define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ /* Processor specific values for the Shdr sh_type field. */ #define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ #define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ /* Processor specific flags for the Shdr sh_flags field. */ #define SHF_IA_64_SHORT 0x10000000 /* section near gp */ #define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ /* Processor specific values for the Dyn d_tag field. */ #define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) #define DT_IA_64_NUM 1 /* IA-64 relocations. */ #define R_IA64_NONE 0x00 /* none */ #define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ #define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ #define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ #define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ #define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ #define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ #define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ #define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ #define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ #define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ #define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ #define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ #define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ #define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ #define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ #define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ #define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ #define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ #define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ #define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ #define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ #define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ #define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ #define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ #define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ #define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ #define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ #define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ #define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ #define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ #define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ #define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ #define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ #define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ #define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ #define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ #define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ #define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ #define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ #define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ #define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ #define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ #define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ #define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ #define R_IA64_REL32MSB 0x6c /* data 4 + REL */ #define R_IA64_REL32LSB 0x6d /* data 4 + REL */ #define R_IA64_REL64MSB 0x6e /* data 8 + REL */ #define R_IA64_REL64LSB 0x6f /* data 8 + REL */ #define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ #define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ #define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ #define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ #define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ #define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ #define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ #define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ #define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ #define R_IA64_COPY 0x84 /* copy relocation */ #define R_IA64_SUB 0x85 /* Addend and symbol difference */ #define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ #define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ #define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ #define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ #define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ #define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ #define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ #define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ #define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ #define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ #define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ #define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ #define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ #define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ #define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ #define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ /* SH specific declarations */ /* SH relocs. */ #define R_SH_NONE 0 #define R_SH_DIR32 1 #define R_SH_REL32 2 #define R_SH_DIR8WPN 3 #define R_SH_IND12W 4 #define R_SH_DIR8WPL 5 #define R_SH_DIR8WPZ 6 #define R_SH_DIR8BP 7 #define R_SH_DIR8W 8 #define R_SH_DIR8L 9 #define R_SH_SWITCH16 25 #define R_SH_SWITCH32 26 #define R_SH_USES 27 #define R_SH_COUNT 28 #define R_SH_ALIGN 29 #define R_SH_CODE 30 #define R_SH_DATA 31 #define R_SH_LABEL 32 #define R_SH_SWITCH8 33 #define R_SH_GNU_VTINHERIT 34 #define R_SH_GNU_VTENTRY 35 #define R_SH_TLS_GD_32 144 #define R_SH_TLS_LD_32 145 #define R_SH_TLS_LDO_32 146 #define R_SH_TLS_IE_32 147 #define R_SH_TLS_LE_32 148 #define R_SH_TLS_DTPMOD32 149 #define R_SH_TLS_DTPOFF32 150 #define R_SH_TLS_TPOFF32 151 #define R_SH_GOT32 160 #define R_SH_PLT32 161 #define R_SH_COPY 162 #define R_SH_GLOB_DAT 163 #define R_SH_JMP_SLOT 164 #define R_SH_RELATIVE 165 #define R_SH_GOTOFF 166 #define R_SH_GOTPC 167 /* Keep this the last entry. */ #define R_SH_NUM 256 /* Additional s390 relocs */ #define R_390_NONE 0 /* No reloc. */ #define R_390_8 1 /* Direct 8 bit. */ #define R_390_12 2 /* Direct 12 bit. */ #define R_390_16 3 /* Direct 16 bit. */ #define R_390_32 4 /* Direct 32 bit. */ #define R_390_PC32 5 /* PC relative 32 bit. */ #define R_390_GOT12 6 /* 12 bit GOT offset. */ #define R_390_GOT32 7 /* 32 bit GOT offset. */ #define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ #define R_390_COPY 9 /* Copy symbol at runtime. */ #define R_390_GLOB_DAT 10 /* Create GOT entry. */ #define R_390_JMP_SLOT 11 /* Create PLT entry. */ #define R_390_RELATIVE 12 /* Adjust by program base. */ #define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ #define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ #define R_390_GOT16 15 /* 16 bit GOT offset. */ #define R_390_PC16 16 /* PC relative 16 bit. */ #define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ #define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ #define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ #define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ #define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ #define R_390_64 22 /* Direct 64 bit. */ #define R_390_PC64 23 /* PC relative 64 bit. */ #define R_390_GOT64 24 /* 64 bit GOT offset. */ #define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ #define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ #define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ #define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ #define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ #define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ #define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ #define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ #define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ #define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ #define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ #define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ #define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ #define R_390_TLS_GDCALL 38 /* Tag for function call in general dynamic TLS code. */ #define R_390_TLS_LDCALL 39 /* Tag for function call in local dynamic TLS code. */ #define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic thread local data. */ #define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic thread local data. */ #define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS block offset. */ #define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS block offset. */ #define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS block offset. */ #define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic thread local data in LE code. */ #define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic thread local data in LE code. */ #define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for negated static TLS block offset. */ #define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for negated static TLS block offset. */ #define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for negated static TLS block offset. */ #define R_390_TLS_LE32 50 /* 32 bit negated offset relative to static TLS block. */ #define R_390_TLS_LE64 51 /* 64 bit negated offset relative to static TLS block. */ #define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS block. */ #define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS block. */ #define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ #define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ #define R_390_TLS_TPOFF 56 /* Negated offset in static TLS block. */ #define R_390_20 57 /* Direct 20 bit. */ #define R_390_GOT20 58 /* 20 bit GOT offset. */ #define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ #define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS block offset. */ /* Keep this the last entry. */ #define R_390_NUM 61 /* CRIS relocations. */ #define R_CRIS_NONE 0 #define R_CRIS_8 1 #define R_CRIS_16 2 #define R_CRIS_32 3 #define R_CRIS_8_PCREL 4 #define R_CRIS_16_PCREL 5 #define R_CRIS_32_PCREL 6 #define R_CRIS_GNU_VTINHERIT 7 #define R_CRIS_GNU_VTENTRY 8 #define R_CRIS_COPY 9 #define R_CRIS_GLOB_DAT 10 #define R_CRIS_JUMP_SLOT 11 #define R_CRIS_RELATIVE 12 #define R_CRIS_16_GOT 13 #define R_CRIS_32_GOT 14 #define R_CRIS_16_GOTPLT 15 #define R_CRIS_32_GOTPLT 16 #define R_CRIS_32_GOTREL 17 #define R_CRIS_32_PLT_GOTREL 18 #define R_CRIS_32_PLT_PCREL 19 #define R_CRIS_NUM 20 /* AMD x86-64 relocations. */ #define R_X86_64_NONE 0 /* No reloc */ #define R_X86_64_64 1 /* Direct 64 bit */ #define R_X86_64_PC32 2 /* PC relative 32 bit signed */ #define R_X86_64_GOT32 3 /* 32 bit GOT entry */ #define R_X86_64_PLT32 4 /* 32 bit PLT address */ #define R_X86_64_COPY 5 /* Copy symbol at runtime */ #define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ #define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ #define R_X86_64_RELATIVE 8 /* Adjust by program base */ #define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative offset to GOT */ #define R_X86_64_32 10 /* Direct 32 bit zero extended */ #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ #define R_X86_64_16 12 /* Direct 16 bit zero extended */ #define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ #define R_X86_64_8 14 /* Direct 8 bit sign extended */ #define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ #define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ #define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ #define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ #define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset to two GOT entries for GD symbol */ #define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset to two GOT entries for LD symbol */ #define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ #define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset to GOT entry for IE symbol */ #define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ #define R_X86_64_NUM 24 #endif /* elf.h */ kexec-tools-2.0.10/include/image.h0000644001567400156740000001453412242534555016011 0ustar hormshorms/* * (C) Copyright 2000-2005 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this * project. * * 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 * ******************************************************************** * NOTE: This header file defines an interface to U-Boot. Including * this (unmodified) header file in another file is considered normal * use of U-Boot, and does *not* fall under the heading of "derived * work". ******************************************************************** */ #ifndef __IMAGE_H__ #define __IMAGE_H__ /* * Operating System Codes */ #define IH_OS_INVALID 0 /* Invalid OS */ #define IH_OS_OPENBSD 1 /* OpenBSD */ #define IH_OS_NETBSD 2 /* NetBSD */ #define IH_OS_FREEBSD 3 /* FreeBSD */ #define IH_OS_4_4BSD 4 /* 4.4BSD */ #define IH_OS_LINUX 5 /* Linux */ #define IH_OS_SVR4 6 /* SVR4 */ #define IH_OS_ESIX 7 /* Esix */ #define IH_OS_SOLARIS 8 /* Solaris */ #define IH_OS_IRIX 9 /* Irix */ #define IH_OS_SCO 10 /* SCO */ #define IH_OS_DELL 11 /* Dell */ #define IH_OS_NCR 12 /* NCR */ #define IH_OS_LYNXOS 13 /* LynxOS */ #define IH_OS_VXWORKS 14 /* VxWorks */ #define IH_OS_PSOS 15 /* pSOS */ #define IH_OS_QNX 16 /* QNX */ #define IH_OS_U_BOOT 17 /* Firmware */ #define IH_OS_RTEMS 18 /* RTEMS */ #define IH_OS_ARTOS 19 /* ARTOS */ #define IH_OS_UNITY 20 /* Unity OS */ #define IH_OS_INTEGRITY 21 /* INTEGRITY */ /* * CPU Architecture Codes (supported by Linux) */ #define IH_ARCH_INVALID 0 /* Invalid CPU */ #define IH_ARCH_ALPHA 1 /* Alpha */ #define IH_ARCH_ARM 2 /* ARM */ #define IH_ARCH_I386 3 /* Intel x86 */ #define IH_ARCH_IA64 4 /* IA64 */ #define IH_ARCH_MIPS 5 /* MIPS */ #define IH_ARCH_MIPS64 6 /* MIPS 64 Bit */ #define IH_ARCH_PPC 7 /* PowerPC */ #define IH_ARCH_S390 8 /* IBM S390 */ #define IH_ARCH_SH 9 /* SuperH */ #define IH_ARCH_SPARC 10 /* Sparc */ #define IH_ARCH_SPARC64 11 /* Sparc 64 Bit */ #define IH_ARCH_M68K 12 /* M68K */ #define IH_ARCH_NIOS 13 /* Nios-32 */ #define IH_ARCH_MICROBLAZE 14 /* MicroBlaze */ #define IH_ARCH_NIOS2 15 /* Nios-II */ #define IH_ARCH_BLACKFIN 16 /* Blackfin */ #define IH_ARCH_AVR32 17 /* AVR32 */ #define IH_ARCH_ST200 18 /* STMicroelectronics ST200 */ /* * Image Types * * "Standalone Programs" are directly runnable in the environment * provided by U-Boot; it is expected that (if they behave * well) you can continue to work in U-Boot after return from * the Standalone Program. * "OS Kernel Images" are usually images of some Embedded OS which * will take over control completely. Usually these programs * will install their own set of exception handlers, device * drivers, set up the MMU, etc. - this means, that you cannot * expect to re-enter U-Boot except by resetting the CPU. * "RAMDisk Images" are more or less just data blocks, and their * parameters (address, size) are passed to an OS kernel that is * being started. * "Multi-File Images" contain several images, typically an OS * (Linux) kernel image and one or more data images like * RAMDisks. This construct is useful for instance when you want * to boot over the network using BOOTP etc., where the boot * server provides just a single image file, but you want to get * for instance an OS kernel and a RAMDisk image. * * "Multi-File Images" start with a list of image sizes, each * image size (in bytes) specified by an "uint32_t" in network * byte order. This list is terminated by an "(uint32_t)0". * Immediately after the terminating 0 follow the images, one by * one, all aligned on "uint32_t" boundaries (size rounded up to * a multiple of 4 bytes - except for the last file). * * "Firmware Images" are binary images containing firmware (like * U-Boot or FPGA images) which usually will be programmed to * flash memory. * * "Script files" are command sequences that will be executed by * U-Boot's command interpreter; this feature is especially * useful when you configure U-Boot to use a real shell (hush) * as command interpreter (=> Shell Scripts). */ #define IH_TYPE_INVALID 0 /* Invalid Image */ #define IH_TYPE_STANDALONE 1 /* Standalone Program */ #define IH_TYPE_KERNEL 2 /* OS Kernel Image */ #define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ #define IH_TYPE_MULTI 4 /* Multi-File Image */ #define IH_TYPE_FIRMWARE 5 /* Firmware Image */ #define IH_TYPE_SCRIPT 6 /* Script file */ #define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ #define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ #define IH_TYPE_KWBIMAGE 9 /* Kirkwood Boot Image */ #define IH_TYPE_KERNEL_NOLOAD 14 /* OS Kernel Image, can run */ /* from any load address */ /* * Compression Types */ #define IH_COMP_NONE 0 /* No Compression Used */ #define IH_COMP_GZIP 1 /* gzip Compression Used */ #define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ #define IH_COMP_LZMA 3 /* lzma Compression Used */ #define IH_COMP_LZO 4 /* lzo Compression Used */ #define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ /* * all data in network byte order (aka natural aka bigendian) */ typedef struct image_header { uint32_t ih_magic; /* Image Header Magic Number */ uint32_t ih_hcrc; /* Image Header CRC Checksum */ uint32_t ih_time; /* Image Creation Timestamp */ uint32_t ih_size; /* Image Data Size */ uint32_t ih_load; /* Data Load Address */ uint32_t ih_ep; /* Entry Point Address */ uint32_t ih_dcrc; /* Image Data CRC Checksum */ uint8_t ih_os; /* Operating System */ uint8_t ih_arch; /* CPU architecture */ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t; #endif /* __IMAGE_H__ */ kexec-tools-2.0.10/include/unused.h0000644001567400156740000000045411642166046016225 0ustar hormshorms#ifndef UNUSED_H #define UNUSED_H /* http://sourcefrog.net/weblog/software/languages/C/unused.html */ #ifdef UNUSED #elif defined(__GNUC__) # define UNUSED(x) UNUSED_ ## x __attribute__((unused)) #elif defined(__LCLINT__) # define UNUSED(x) /*@unused@*/ x #else # define UNUSED(x) x #endif #endif kexec-tools-2.0.10/include/boot/linuxbios_tables.h0000644001567400156740000000474011424244110021220 0ustar hormshorms#ifndef LINUXBIOS_TABLES_H #define LINUXBIOS_TABLES_H #include /* 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 */ kexec-tools-2.0.10/include/boot/beoboot.h0000644001567400156740000000237111424244110017301 0ustar hormshorms /*--- 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 /*------------------------------------------------------------------*/ kexec-tools-2.0.10/include/boot/elf_boot.h0000644001567400156740000000605111424244110017440 0ustar hormshorms#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 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 */ kexec-tools-2.0.10/util_lib/Makefile0000644001567400156740000000111011424244110016342 0ustar hormshorms# # Utility function library # UTIL_LIB_SRCS += UTIL_LIB_SRCS += util_lib/compute_ip_checksum.c UTIL_LIB_SRCS += util_lib/sha256.c UTIL_LIB_OBJS =$(call objify, $(UTIL_LIB_SRCS)) UTIL_LIB_DEPS =$(call depify, $(UTIL_LIB_OBJS)) UTIL_LIB = libutil.a -include $(UTIL_LIB_DEPS) dist += util_lib/Makefile $(UTIL_LIB_SRCS) \ util_lib/include/sha256.h util_lib/include/ip_checksum.h clean += $(UTIL_LIB_OBJS) $(UTIL_LIB_DEPS) $(UTIL_LIB) $(UTIL_LIB): CPPFLAGS += -I$(srcdir)/util_lib/include $(UTIL_LIB): $(UTIL_LIB_OBJS) @$(MKDIR) -p $(@D) $(AR) rs $(UTIL_LIB) $(UTIL_LIB_OBJS) kexec-tools-2.0.10/util_lib/compute_ip_checksum.c0000644001567400156740000000471111424244110021106 0ustar hormshorms/* * 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 #include #include unsigned long compute_ip_checksum(void *addr, unsigned long length) { uint16_t *ptr; unsigned long sum; unsigned long len; unsigned long laddr; /* compute an ip style checksum */ laddr = (unsigned long )addr; sum = 0; if (laddr & 1) { uint16_t buffer; unsigned char *ptr; /* copy the first byte into a 2 byte buffer. * This way automatically handles the endian question * of which byte (low or high) the last byte goes in. */ buffer = 0; ptr = addr; memcpy(&buffer, ptr, 1); sum += buffer; if (sum > 0xFFFF) sum -= 0xFFFF; length -= 1; addr = ptr +1; } len = length >> 1; ptr = addr; while (len--) { sum += *(ptr++); if (sum > 0xFFFF) sum -= 0xFFFF; } addr = ptr; if (length & 1) { uint16_t buffer; unsigned char *ptr; /* copy the last byte into a 2 byte buffer. * This way automatically handles the endian question * of which byte (low or high) the last byte goes in. */ buffer = 0; ptr = addr; memcpy(&buffer, ptr, 1); sum += buffer; if (sum > 0xFFFF) sum -= 0xFFFF; } return (~sum) & 0xFFFF; } unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new) { unsigned long checksum; sum = ~sum & 0xFFFF; new = ~new & 0xFFFF; if (offset & 1) { /* byte swap the sum if it came from an odd offset * since the computation is endian independant this * works. */ new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); } checksum = sum + new; if (checksum > 0xFFFF) { checksum -= 0xFFFF; } return (~checksum) & 0xFFFF; } unsigned long negate_ip_checksum(unsigned long sum) { sum = ~sum & 0xFFFF; sum = 0xFFFF - sum; return ~sum & 0xFFFF; } kexec-tools-2.0.10/util_lib/sha256.c0000644001567400156740000002350611424244110016073 0ustar hormshorms/* * FIPS-180-2 compliant SHA-256 implementation * * Copyright (C) 2001-2003 Christophe Devine * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "sha256.h" #define GET_UINT32(n,b,i) \ { \ (n) = ( (uint32_t) (b)[(i) ] << 24 ) | \ ( (uint32_t) (b)[(i) + 1] << 16 ) | \ ( (uint32_t) (b)[(i) + 2] << 8 ) | \ ( (uint32_t) (b)[(i) + 3] ); \ } #define PUT_UINT32(n,b,i) \ { \ (b)[(i) ] = (uint8_t) ( (n) >> 24 ); \ (b)[(i) + 1] = (uint8_t) ( (n) >> 16 ); \ (b)[(i) + 2] = (uint8_t) ( (n) >> 8 ); \ (b)[(i) + 3] = (uint8_t) ( (n) ); \ } void sha256_starts( sha256_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x6A09E667; ctx->state[1] = 0xBB67AE85; ctx->state[2] = 0x3C6EF372; ctx->state[3] = 0xA54FF53A; ctx->state[4] = 0x510E527F; ctx->state[5] = 0x9B05688C; ctx->state[6] = 0x1F83D9AB; ctx->state[7] = 0x5BE0CD19; } void sha256_process( sha256_context *ctx, const uint8_t data[64] ) { uint32_t temp1, temp2, W[64]; uint32_t A, B, C, D, E, F, G, H; GET_UINT32( W[0], data, 0 ); GET_UINT32( W[1], data, 4 ); GET_UINT32( W[2], data, 8 ); GET_UINT32( W[3], data, 12 ); GET_UINT32( W[4], data, 16 ); GET_UINT32( W[5], data, 20 ); GET_UINT32( W[6], data, 24 ); GET_UINT32( W[7], data, 28 ); GET_UINT32( W[8], data, 32 ); GET_UINT32( W[9], data, 36 ); GET_UINT32( W[10], data, 40 ); GET_UINT32( W[11], data, 44 ); GET_UINT32( W[12], data, 48 ); GET_UINT32( W[13], data, 52 ); GET_UINT32( W[14], data, 56 ); GET_UINT32( W[15], data, 60 ); #define SHR(x,n) ((x & 0xFFFFFFFF) >> n) #define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) #define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) #define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) #define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) #define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) #define F0(x,y,z) ((x & y) | (z & (x | y))) #define F1(x,y,z) (z ^ (x & (y ^ z))) #define R(t) \ ( \ W[t] = S1(W[t - 2]) + W[t - 7] + \ S0(W[t - 15]) + W[t - 16] \ ) #define P(a,b,c,d,e,f,g,h,x,K) \ { \ temp1 = h + S3(e) + F1(e,f,g) + K + x; \ temp2 = S2(a) + F0(a,b,c); \ d += temp1; h = temp1 + temp2; \ } A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; E = ctx->state[4]; F = ctx->state[5]; G = ctx->state[6]; H = ctx->state[7]; P( A, B, C, D, E, F, G, H, W[ 0], 0x428A2F98 ); P( H, A, B, C, D, E, F, G, W[ 1], 0x71374491 ); P( G, H, A, B, C, D, E, F, W[ 2], 0xB5C0FBCF ); P( F, G, H, A, B, C, D, E, W[ 3], 0xE9B5DBA5 ); P( E, F, G, H, A, B, C, D, W[ 4], 0x3956C25B ); P( D, E, F, G, H, A, B, C, W[ 5], 0x59F111F1 ); P( C, D, E, F, G, H, A, B, W[ 6], 0x923F82A4 ); P( B, C, D, E, F, G, H, A, W[ 7], 0xAB1C5ED5 ); P( A, B, C, D, E, F, G, H, W[ 8], 0xD807AA98 ); P( H, A, B, C, D, E, F, G, W[ 9], 0x12835B01 ); P( G, H, A, B, C, D, E, F, W[10], 0x243185BE ); P( F, G, H, A, B, C, D, E, W[11], 0x550C7DC3 ); P( E, F, G, H, A, B, C, D, W[12], 0x72BE5D74 ); P( D, E, F, G, H, A, B, C, W[13], 0x80DEB1FE ); P( C, D, E, F, G, H, A, B, W[14], 0x9BDC06A7 ); P( B, C, D, E, F, G, H, A, W[15], 0xC19BF174 ); P( A, B, C, D, E, F, G, H, R(16), 0xE49B69C1 ); P( H, A, B, C, D, E, F, G, R(17), 0xEFBE4786 ); P( G, H, A, B, C, D, E, F, R(18), 0x0FC19DC6 ); P( F, G, H, A, B, C, D, E, R(19), 0x240CA1CC ); P( E, F, G, H, A, B, C, D, R(20), 0x2DE92C6F ); P( D, E, F, G, H, A, B, C, R(21), 0x4A7484AA ); P( C, D, E, F, G, H, A, B, R(22), 0x5CB0A9DC ); P( B, C, D, E, F, G, H, A, R(23), 0x76F988DA ); P( A, B, C, D, E, F, G, H, R(24), 0x983E5152 ); P( H, A, B, C, D, E, F, G, R(25), 0xA831C66D ); P( G, H, A, B, C, D, E, F, R(26), 0xB00327C8 ); P( F, G, H, A, B, C, D, E, R(27), 0xBF597FC7 ); P( E, F, G, H, A, B, C, D, R(28), 0xC6E00BF3 ); P( D, E, F, G, H, A, B, C, R(29), 0xD5A79147 ); P( C, D, E, F, G, H, A, B, R(30), 0x06CA6351 ); P( B, C, D, E, F, G, H, A, R(31), 0x14292967 ); P( A, B, C, D, E, F, G, H, R(32), 0x27B70A85 ); P( H, A, B, C, D, E, F, G, R(33), 0x2E1B2138 ); P( G, H, A, B, C, D, E, F, R(34), 0x4D2C6DFC ); P( F, G, H, A, B, C, D, E, R(35), 0x53380D13 ); P( E, F, G, H, A, B, C, D, R(36), 0x650A7354 ); P( D, E, F, G, H, A, B, C, R(37), 0x766A0ABB ); P( C, D, E, F, G, H, A, B, R(38), 0x81C2C92E ); P( B, C, D, E, F, G, H, A, R(39), 0x92722C85 ); P( A, B, C, D, E, F, G, H, R(40), 0xA2BFE8A1 ); P( H, A, B, C, D, E, F, G, R(41), 0xA81A664B ); P( G, H, A, B, C, D, E, F, R(42), 0xC24B8B70 ); P( F, G, H, A, B, C, D, E, R(43), 0xC76C51A3 ); P( E, F, G, H, A, B, C, D, R(44), 0xD192E819 ); P( D, E, F, G, H, A, B, C, R(45), 0xD6990624 ); P( C, D, E, F, G, H, A, B, R(46), 0xF40E3585 ); P( B, C, D, E, F, G, H, A, R(47), 0x106AA070 ); P( A, B, C, D, E, F, G, H, R(48), 0x19A4C116 ); P( H, A, B, C, D, E, F, G, R(49), 0x1E376C08 ); P( G, H, A, B, C, D, E, F, R(50), 0x2748774C ); P( F, G, H, A, B, C, D, E, R(51), 0x34B0BCB5 ); P( E, F, G, H, A, B, C, D, R(52), 0x391C0CB3 ); P( D, E, F, G, H, A, B, C, R(53), 0x4ED8AA4A ); P( C, D, E, F, G, H, A, B, R(54), 0x5B9CCA4F ); P( B, C, D, E, F, G, H, A, R(55), 0x682E6FF3 ); P( A, B, C, D, E, F, G, H, R(56), 0x748F82EE ); P( H, A, B, C, D, E, F, G, R(57), 0x78A5636F ); P( G, H, A, B, C, D, E, F, R(58), 0x84C87814 ); P( F, G, H, A, B, C, D, E, R(59), 0x8CC70208 ); P( E, F, G, H, A, B, C, D, R(60), 0x90BEFFFA ); P( D, E, F, G, H, A, B, C, R(61), 0xA4506CEB ); P( C, D, E, F, G, H, A, B, R(62), 0xBEF9A3F7 ); P( B, C, D, E, F, G, H, A, R(63), 0xC67178F2 ); ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; ctx->state[4] += E; ctx->state[5] += F; ctx->state[6] += G; ctx->state[7] += H; } void sha256_update( sha256_context *ctx, const uint8_t *input, size_t length ) { size_t left, fill; if( ! length ) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += length; ctx->total[0] &= 0xFFFFFFFF; if( ctx->total[0] < length ) ctx->total[1]++; if( left && length >= fill ) { memcpy( ctx->buffer + left, input, fill ); sha256_process( ctx, ctx->buffer ); length -= fill; input += fill; left = 0; } while( length >= 64 ) { sha256_process( ctx, input ); length -= 64; input += 64; } if( length ) { memcpy(ctx->buffer + left, input, length); } } static uint8_t sha256_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; void sha256_finish( sha256_context *ctx, sha256_digest_t digest ) { uint32_t last, padn; uint32_t high, low; uint8_t msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_UINT32( high, msglen, 0 ); PUT_UINT32( low, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); sha256_update( ctx, sha256_padding, padn ); sha256_update( ctx, msglen, 8 ); PUT_UINT32( ctx->state[0], digest, 0 ); PUT_UINT32( ctx->state[1], digest, 4 ); PUT_UINT32( ctx->state[2], digest, 8 ); PUT_UINT32( ctx->state[3], digest, 12 ); PUT_UINT32( ctx->state[4], digest, 16 ); PUT_UINT32( ctx->state[5], digest, 20 ); PUT_UINT32( ctx->state[6], digest, 24 ); PUT_UINT32( ctx->state[7], digest, 28 ); } #ifdef TEST #include #include /* * those are the standard FIPS-180-2 test vectors */ static char *msg[] = { "abc", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", NULL }; static char *val[] = { "ba7816bf8f01cfea414140de5dae2223" \ "b00361a396177a9cb410ff61f20015ad", "248d6a61d20638b8e5c026930c3e6039" \ "a33ce45964ff2167f6ecedd419db06c1", "cdc76e5c9914fb9281a1c7e284d73e67" \ "f1809a48a497200e046d39ccc7112cd0" }; int main( int argc, char *argv[] ) { FILE *f; int i, j; char output[65]; sha256_context ctx; unsigned char buf[1000]; unsigned char sha256sum[32]; if( argc < 2 ) { printf( "\n SHA-256 Validation Tests:\n\n" ); for( i = 0; i < 3; i++ ) { printf( " Test %d ", i + 1 ); sha256_starts( &ctx ); if( i < 2 ) { sha256_update( &ctx, (uint8_t *) msg[i], strlen( msg[i] ) ); } else { memset( buf, 'a', 1000 ); for( j = 0; j < 1000; j++ ) { sha256_update( &ctx, (uint8_t *) buf, 1000 ); } } sha256_finish( &ctx, sha256sum ); for( j = 0; j < 32; j++ ) { sprintf( output + j * 2, "%02x", sha256sum[j] ); } if( memcmp( output, val[i], 64 ) ) { printf( "failed!\n" ); return( 1 ); } printf( "passed.\n" ); } printf( "\n" ); } else { if( ! ( f = fopen( argv[1], "rb" ) ) ) { perror( "fopen" ); return( 1 ); } sha256_starts( &ctx ); while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) { sha256_update( &ctx, buf, i ); } sha256_finish( &ctx, sha256sum ); for( j = 0; j < 32; j++ ) { printf( "%02x", sha256sum[j] ); } printf( " %s\n", argv[1] ); } return( 0 ); } #endif kexec-tools-2.0.10/util_lib/include/sha256.h0000644001567400156740000000065311424244110017521 0ustar hormshorms#ifndef SHA256_H #define SHA256_H #include #include typedef struct { size_t total[2]; uint32_t state[8]; uint8_t buffer[64]; } sha256_context; typedef uint8_t sha256_digest_t[32]; void sha256_starts( sha256_context *ctx ); void sha256_update( sha256_context *ctx, const uint8_t *input, size_t length ); void sha256_finish( sha256_context *ctx, sha256_digest_t digest ); #endif /* SHA256_H */ kexec-tools-2.0.10/util_lib/include/ip_checksum.h0000644001567400156740000000043711424244110021003 0ustar hormshorms#ifndef IP_CHECKSUM_H #define IP_CHECKSUM_H unsigned long compute_ip_checksum(void *addr, unsigned long length); unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new); unsigned long negate_ip_checksum(unsigned long sum); #endif /* IP_CHECKSUM_H */ kexec-tools-2.0.10/util/Makefile0000644001567400156740000000045111424244110015523 0ustar hormshormsBIN_TO_HEX:= bin/bin-to-hex $(BIN_TO_HEX): $(srcdir)/util/bin-to-hex.c @$(MKDIR) -p $(@D) $(LINK.o) $(CFLAGS) -o $@ $^ $(BIN_TO_HEX): CC=$(BUILD_CC) $(BIN_TO_HEX): CFLAGS=$(BUILD_CFLAGS) $(BIN_TO_HEX): LDFLAGS= dist += util/Makefile util/bin-to-hex.c clean += util/bin-to-hex.o $(BIN_TO_HEX) kexec-tools-2.0.10/util/bin-to-hex.c0000644001567400156740000000066511642166046016225 0ustar hormshorms#include int main(int argc, char **argv) { int c; int i; const char *name = argv[1]; printf("#include \n"); printf("const char %s[] = {\n", name); i = 0; while((c = getchar()) != EOF) { if ((i % 16) != 0) { putchar(' '); } printf("0x%02x,", c); i++; if ((i %16) == 0) { putchar('\n'); } } putchar('\n'); printf("};\n"); printf("size_t %s_size = sizeof(%s);\n", name, name); return 0; } kexec-tools-2.0.10/purgatory/Makefile0000644001567400156740000000503012520334015016602 0ustar hormshorms# # 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. PURGATORY = purgatory/purgatory.ro PURGATORY_SRCS = PURGATORY_SRCS += purgatory/purgatory.c PURGATORY_SRCS += purgatory/printf.c PURGATORY_SRCS += purgatory/string.c PURGATORY_MAP = purgatory/purgatory.map dist += purgatory/Makefile $(PURGATORY_SRCS) \ purgatory/include/purgatory.h purgatory/include/string.h include $(srcdir)/purgatory/arch/alpha/Makefile include $(srcdir)/purgatory/arch/arm/Makefile include $(srcdir)/purgatory/arch/i386/Makefile include $(srcdir)/purgatory/arch/ia64/Makefile include $(srcdir)/purgatory/arch/mips/Makefile include $(srcdir)/purgatory/arch/ppc/Makefile include $(srcdir)/purgatory/arch/ppc64/Makefile include $(srcdir)/purgatory/arch/s390/Makefile include $(srcdir)/purgatory/arch/sh/Makefile include $(srcdir)/purgatory/arch/x86_64/Makefile PURGATORY_SRCS+=$($(ARCH)_PURGATORY_SRCS) PURGATORY_OBJS = $(call objify, $(PURGATORY_SRCS)) purgatory/sha256.o PURGATORY_DEPS = $(call depify, $(PURGATORY_OBJS)) clean += $(PURGATORY_OBJS) $(PURGATORY_DEPS) $(PURGATORY) -include $(PURGATORY_DEPS) # sha256.c needs to be compiled without optimization, else # purgatory fails to execute on ia64. purgatory/sha256.o: CFLAGS += -O0 purgatory/sha256.o: $(srcdir)/util_lib/sha256.c mkdir -p $(@D) $(COMPILE.c) -o $@ $^ $(PURGATORY): CC=$(TARGET_CC) $(PURGATORY): CFLAGS+=$(PURGATORY_EXTRA_CFLAGS) \ $($(ARCH)_PURGATORY_EXTRA_CFLAGS) \ -Os -fno-builtin -ffreestanding \ -fno-zero-initialized-in-bss \ -fno-PIC -fno-PIE -fno-stack-protector $(PURGATORY): CPPFLAGS=$($(ARCH)_PURGATORY_EXTRA_CFLAGS) \ -I$(srcdir)/purgatory/include \ -I$(srcdir)/purgatory/arch/$(ARCH)/include \ -I$(srcdir)/util_lib/include \ -I$(srcdir)/include \ -Iinclude \ -I$(shell $(CC) -print-file-name=include) $(PURGATORY): LDFLAGS=$($(ARCH)_PURGATORY_EXTRA_CFLAGS)\ -Wl,--no-undefined -nostartfiles -nostdlib \ -nodefaultlibs -e purgatory_start -r \ -Wl,-Map=$(PURGATORY_MAP) $(PURGATORY): $(PURGATORY_OBJS) $(MKDIR) -p $(@D) $(CC) $(CFLAGS) $(LDFLAGS) -o $@.sym $^ # $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) --no-undefined -e purgatory_start -r -o $@ $(PURGATORY_OBJS) $(UTIL_LIB) $(STRIP) --strip-debug -o $@ $@.sym echo:: @echo "PURGATORY_SRCS $(PURGATORY_SRCS)" @echo "PURGATORY_DEPS $(PURGATORY_DEPS)" @echo "PURGATORY_OBJS $(PURGATORY_OBJS)" kexec-tools-2.0.10/purgatory/purgatory.c0000644001567400156740000000223212326111375017351 0ustar hormshorms #include #include #include #include #include #include "../kexec/kexec-sha256.h" struct sha256_region sha256_regions[SHA256_REGIONS] = {}; sha256_digest_t sha256_digest = { }; int verify_sha256_digest(void) { struct sha256_region *ptr, *end; sha256_digest_t digest; size_t i; sha256_context ctx; sha256_starts(&ctx); end = &sha256_regions[sizeof(sha256_regions)/sizeof(sha256_regions[0])]; for(ptr = sha256_regions; ptr < end; ptr++) { sha256_update(&ctx, (uint8_t *)((uintptr_t)ptr->start), ptr->len); } sha256_finish(&ctx, digest); if (memcmp(digest, sha256_digest, sizeof(digest)) != 0) { printf("sha256 digests do not match :(\n"); printf(" digest: "); for(i = 0; i < sizeof(digest); i++) { printf("%hhx ", digest[i]); } printf("\n"); printf("sha256_digest: "); for(i = 0; i < sizeof(sha256_digest); i++) { printf("%hhx ", sha256_digest[i]); } printf("\n"); return 1; } return 0; } void purgatory(void) { printf("I'm in purgatory\n"); setup_arch(); if (verify_sha256_digest()) { for(;;) { /* loop forever */ } } post_verification_setup_arch(); } kexec-tools-2.0.10/purgatory/printf.c0000644001567400156740000000675211424244110016622 0ustar hormshorms#include #include #include #include #include /* * Output * ============================================================================= */ #define LONG_LONG_SHIFT ((int)((sizeof(unsigned long long)*CHAR_BIT) - 4)) #define LONG_SHIFT ((int)((sizeof(unsigned long)*CHAR_BIT) - 4)) #define INT_SHIFT ((int)((sizeof(unsigned int)*CHAR_BIT) - 4)) #define SHRT_SHIFT ((int)((sizeof(unsigned short)*CHAR_BIT) - 4)) #define CHAR_SHIFT ((int)((sizeof(unsigned char)*CHAR_BIT) - 4)) /************************************************************************** PRINTF and friends Formats: %x - 4 bytes int (8 hex digits, lower case) %X - 4 bytes int (8 hex digits, upper case) %lx - 8 bytes long (16 hex digits, lower case) %lX - 8 bytes long (16 hex digits, upper case) %hx - 2 bytes int (4 hex digits, lower case) %hX - 2 bytes int (4 hex digits, upper case) %hhx - 1 byte int (2 hex digits, lower case) %hhX - 1 byte int (2 hex digits, upper case) - optional # prefixes 0x or 0X %d - decimal int %c - char %s - string Note: width specification not supported **************************************************************************/ void vsprintf(char *buffer, const char *fmt, va_list args) { char *p; for ( ; *fmt != '\0'; ++fmt) { if (*fmt != '%') { if (buffer) *buffer++ = *fmt; else putchar(*fmt); continue; } if (*++fmt == 's') { for(p = va_arg(args, char *); *p != '\0'; p++) if (buffer) *buffer++ = *p; else putchar(*p); } else { /* Length of item is bounded */ char tmp[40], *q = tmp; int shift = INT_SHIFT; if (*fmt == 'L') { shift = LONG_LONG_SHIFT; fmt++; } else if (*fmt == 'l') { shift = LONG_SHIFT; fmt++; } else if (*fmt == 'h') { shift = SHRT_SHIFT; fmt++; if (*fmt == 'h') { shift = CHAR_SHIFT; fmt++; } } /* * Before each format q points to tmp buffer * After each format q points past end of item */ if ((*fmt | 0x20) == 'x') { /* With x86 gcc, sizeof(long) == sizeof(int) */ unsigned long long h; int ncase; if (shift > LONG_SHIFT) { h = va_arg(args, unsigned long long); } else if (shift > INT_SHIFT) { h = va_arg(args, unsigned long); } else { h = va_arg(args, unsigned int); } ncase = (*fmt & 0x20); for ( ; shift >= 0; shift -= 4) *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase; } else if (*fmt == 'd') { char *r; long i; if (shift > LONG_SHIFT) { i = va_arg(args, long long); } else if (shift > INT_SHIFT) { i = va_arg(args, long); } else { i = va_arg(args, int); } if (i < 0) { *q++ = '-'; i = -i; } p = q; /* save beginning of digits */ do { *q++ = '0' + (i % 10); i /= 10; } while (i); /* reverse digits, stop in middle */ r = q; /* don't alter q */ while (--r > p) { i = *r; *r = *p; *p++ = i; } } else if (*fmt == 'c') *q++ = va_arg(args, int); else *q++ = *fmt; /* now output the saved string */ for (p = tmp; p < q; ++p) if (buffer) *buffer++ = *p; else putchar(*p); } } if (buffer) *buffer = '\0'; } void sprintf(char *buffer, const char *fmt, ...) { va_list args; va_start(args, fmt); vsprintf(buffer, fmt, args); va_end(args); } void printf(const char *fmt, ...) { va_list args; va_start(args, fmt); vsprintf(0, fmt, args); va_end(args); } kexec-tools-2.0.10/purgatory/string.c0000644001567400156740000000126512516074277016642 0ustar hormshorms#include #include size_t strnlen(const char *s, size_t max) { size_t len = 0; while(len < max && *s) { len++; s++; } return len; } void* memset(void* s, int c, size_t n) { size_t i; char *ss = (char*)s; for (i=0;i #include #include #include "purgatory-x86_64.h" uint8_t reset_vga = 0; uint8_t legacy_pic = 0; uint8_t panic_kernel = 0; unsigned long jump_back_entry = 0; char *cmdline_end = NULL; void setup_arch(void) { if (reset_vga) x86_reset_vga(); if (legacy_pic) x86_setup_legacy_pic(); } void x86_setup_jump_back_entry(void) { if (cmdline_end) sprintf(cmdline_end, " kexec_jump_back_entry=0x%lx", jump_back_entry); } /* This function can be used to execute after the SHA256 verification. */ void post_verification_setup_arch(void) { if (panic_kernel) crashdump_backup_memory(); if (jump_back_entry) x86_setup_jump_back_entry(); } kexec-tools-2.0.10/purgatory/arch/i386/entry32-16.S0000644001567400156740000000731612242534555020453 0ustar hormshorms/* * 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 (assumes esp valid) */ call 1f 1: popl %ebx subl $(1b - entry16), %ebx /* Fixup my real mode segment */ movl %ebx, %eax shrl $4, %eax movw %ax, (2 + realptr - entry16)(%ebx) /* Fixup the gdt */ leal (gdt - entry16)(%ebx), %eax movl %eax, (0x02 + gdt - entry16)(%ebx) 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 - entry16)(%ebx) orl %ecx, (0x0c + gdt - entry16)(%ebx) orl %eax, (0x10 + gdt - entry16)(%ebx) orl %ecx, (0x14 + gdt - entry16)(%ebx) /* Setup the classic BIOS interrupt table at 0x0 */ lidt (idtptr - entry16)(%ebx) /* Provide us with 16bit segments that we can use */ lgdt (gdt - entry16)(%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, $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 0 /* 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-tools-2.0.10/purgatory/arch/i386/entry32-16-debug.S0000644001567400156740000001117012242534555021530 0ustar hormshorms/* * 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 (assumes esp valid) */ call 1f 1: popl %ebx subl $(1b - entry16_debug), %ebx /* Fixup my real mode segment */ movl %ebx, %eax shrl $4, %eax movw %ax, (2 + realptr - entry16_debug)(%ebx) /* Fixup the gdt */ leal (gdt - entry16_debug)(%ebx), %eax movl %eax, (0x02 + gdt - entry16_debug)(%ebx) 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 - entry16_debug)(%ebx) orl %ecx, (0x0c + gdt - entry16_debug)(%ebx) orl %eax, (0x10 + gdt - entry16_debug)(%ebx) orl %ecx, (0x14 + gdt - entry16_debug)(%ebx) DEBUG_CHAR('a') /* Setup the classic BIOS interrupt table at 0x0 */ lidt (idtptr - entry16_debug)(%ebx) DEBUG_CHAR('b') /* Provide us with 16bit segments that we can use */ lgdt (gdt - entry16_debug)(%ebx) DEBUG_CHAR('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_CHAR('d') /* switch to 16bit mode */ ljmp $0x08, $1f - entry16_debug 1: .code16 DEBUG_CHAR('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_CHAR('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_CHAR('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_CHAR('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 0 /* 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_CHAR('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_CHAR('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 kexec-tools-2.0.10/purgatory/arch/i386/crashdump_backup.c0000644001567400156740000000300711642166046022244 0ustar hormshorms/* * kexec: Linux boots Linux * * Created by: Vivek goyal (vgoyal@in.ibm.com) * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include /* Backup region start gets set after /proc/iomem has been parsed. */ /* We reuse the same code for x86_64 also so changing backup_start to unsigned long */ unsigned long backup_start = 0; unsigned long backup_src_start = 0; unsigned long backup_src_size = 0; /* Backup first 640K of memory to backup region as reserved by kexec. * Assuming first 640K has to be present on i386 machines and no address * validity checks have to be performed. */ void crashdump_backup_memory(void) { void *dest, *src; size_t size; src = (void *) backup_src_start; size = (size_t) backup_src_size; if (!size) return; if (backup_start) { dest = (void *)(backup_start); memcpy(dest, src, size); } } kexec-tools-2.0.10/purgatory/arch/i386/console-x86.c0000644001567400156740000000633211424244110021005 0ustar hormshorms#include #include #include /* * 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); } kexec-tools-2.0.10/purgatory/arch/i386/vga.c0000644001567400156740000000531611424244110017476 0ustar hormshorms#include #include #include "purgatory-x86.h" /* Crudely reset a VGA card to text mode 3, by writing plausible default */ /* values into its registers. */ /* Tim Deegan (tjd21 at cl.cam.ac.uk), March 2003 */ /* Based on Keir Fraser's start-of-day reset code from the Xen hypervisor */ /* Converted from Assembly 20 December 2004 -- Eric Biederman */ void x86_reset_vga(void) { /* Hello */ inb(0x3da); outb(0, 0x3c0); /* Sequencer registers */ outw(0x0300, 0x3c4); outw(0x0001, 0x3c4); outw(0x0302, 0x3c4); outw(0x0003, 0x3c4); outw(0x0204, 0x3c4); /* Ensure CRTC regs 0-7 are unlocked by clearing bit 7 of CRTC[17] */ outw(0x0e11, 0x3d4); /* CRTC registers */ outw(0x5f00, 0x3d4); outw(0x4f01, 0x3d4); outw(0x5002, 0x3d4); outw(0x8203, 0x3d4); outw(0x5504, 0x3d4); outw(0x8105, 0x3d4); outw(0xbf06, 0x3d4); outw(0x1f07, 0x3d4); outw(0x0008, 0x3d4); outw(0x4f09, 0x3d4); outw(0x200a, 0x3d4); outw(0x0e0b, 0x3d4); outw(0x000c, 0x3d4); outw(0x000d, 0x3d4); outw(0x010e, 0x3d4); outw(0xe00f, 0x3d4); outw(0x9c10, 0x3d4); outw(0x8e11, 0x3d4); outw(0x8f12, 0x3d4); outw(0x2813, 0x3d4); outw(0x1f14, 0x3d4); outw(0x9615, 0x3d4); outw(0xb916, 0x3d4); outw(0xa317, 0x3d4); outw(0xff18, 0x3d4); /* Graphic registers */ outw(0x0000, 0x3ce); outw(0x0001, 0x3ce); outw(0x0002, 0x3ce); outw(0x0003, 0x3ce); outw(0x0004, 0x3ce); outw(0x1005, 0x3ce); outw(0x0e06, 0x3ce); outw(0x0007, 0x3ce); outw(0xff08, 0x3ce); /* Attribute registers */ inb(0x3da); outb(0x00, 0x3c0); outb(0x00, 0x3c0); inb(0x3da); outb(0x01, 0x3c0); outb(0x01, 0x3c0); inb(0x3da); outb(0x02, 0x3c0); outb(0x02, 0x3c0); inb(0x3da); outb(0x03, 0x3c0); outb(0x03, 0x3c0); inb(0x3da); outb(0x04, 0x3c0); outb(0x04, 0x3c0); inb(0x3da); outb(0x05, 0x3c0); outb(0x05, 0x3c0); inb(0x3da); outb(0x06, 0x3c0); outb(0x14, 0x3c0); inb(0x3da); outb(0x07, 0x3c0); outb(0x07, 0x3c0); inb(0x3da); outb(0x08, 0x3c0); outb(0x38, 0x3c0); inb(0x3da); outb(0x09, 0x3c0); outb(0x39, 0x3c0); inb(0x3da); outb(0x0a, 0x3c0); outb(0x3a, 0x3c0); inb(0x3da); outb(0x0b, 0x3c0); outb(0x3b, 0x3c0); inb(0x3da); outb(0x0c, 0x3c0); outb(0x3c, 0x3c0); inb(0x3da); outb(0x0d, 0x3c0); outb(0x3d, 0x3c0); inb(0x3da); outb(0x0e, 0x3c0); outb(0x3e, 0x3c0); inb(0x3da); outb(0x0f, 0x3c0); outb(0x3f, 0x3c0); inb(0x3da); outb(0x10, 0x3c0); outb(0x0c, 0x3c0); inb(0x3da); outb(0x11, 0x3c0); outb(0x00, 0x3c0); inb(0x3da); outb(0x12, 0x3c0); outb(0x0f, 0x3c0); inb(0x3da); outb(0x13, 0x3c0); outb(0x08, 0x3c0); inb(0x3da); outb(0x14, 0x3c0); outb(0x00, 0x3c0); /* Goodbye */ inb(0x3da); outb(0x20, 0x3c0); } kexec-tools-2.0.10/purgatory/arch/i386/pic.c0000644001567400156740000000322011424244110017464 0ustar hormshorms/* * 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 #include #include "purgatory-x86.h" void x86_setup_legacy_pic(void) { /* Load the legacy dos settings into the 8259A pic */ outb(0xff, 0x21); /* mask all of 8259A-1 */ outb(0xff, 0xa1); /* mask all of 8259A-2 */ outb(0x11, 0x20); /* ICW1: select 8259A-1 init */ outb(0x11, 0x80); /* A short delay */ outb(0x08, 0x21); /* ICW2: 8259A-1 IR0-7 mappend to 0x8-0xf */ outb(0x08, 0x80); /* A short delay */ outb(0x01, 0x21); /* Normal 8086 auto EOI mode */ outb(0x01, 0x80); /* A short delay */ outb(0x11, 0xa0); /* ICW1: select 8259A-2 init */ outb(0x11, 0x80); /* A short delay */ outb(0x70, 0xa1); /* ICW2: 8259A-2 IR0-7 mappend to 0x70-0x77 */ outb(0x70, 0x80); /* A short delay */ outb(0x01, 0xa1); /* Normal 8086 auto EOI mode */ outb(0x01, 0x80); /* A short delay */ outb(0x00, 0x21); /* Unmask all of 8259A-1 */ outb(0x00, 0xa1); /* Unmask all of 8259A-2 */ } kexec-tools-2.0.10/purgatory/include/purgatory.h0000644001567400156740000000047712502430766021016 0ustar hormshorms#ifndef PURGATORY_H #define PURGATORY_H void putchar(int ch); void sprintf(char *buffer, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); void printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); void setup_arch(void); void post_verification_setup_arch(void); #endif /* PURGATORY_H */ kexec-tools-2.0.10/purgatory/include/string.h0000644001567400156740000000041211424244110020241 0ustar hormshorms#ifndef STRING_H #define STRING_H #include size_t strnlen(const char *s, size_t max); void* memset(void* s, int c, size_t n); void* memcpy(void *dest, const void *src, size_t len); int memcmp(void *src1, void *src2, size_t len); #endif /* STRING_H */ kexec-tools-2.0.10/purgatory/arch/alpha/Makefile0000644001567400156740000000015611424244110020606 0ustar hormshorms# # Purgatory alpha # alpha_PURGATORY_SRCS = dist += purgatory/arch/alpha/Makefile $(alpha_PURGATORY_SRCS) kexec-tools-2.0.10/purgatory/arch/arm/Makefile0000644001567400156740000000014711424244110020300 0ustar hormshorms# # Purgatory arm # arm_PURGATORY_SRCS = dist += purgatory/arch/arm/Makefile $(arm_PURGATORY_SRCS) kexec-tools-2.0.10/purgatory/arch/i386/Makefile0000644001567400156740000000147011424244110020212 0ustar hormshorms# # Purgatory i386 # i386_PURGATORY_SRCS = purgatory/arch/i386/entry32-16.S i386_PURGATORY_SRCS += purgatory/arch/i386/entry32-16-debug.S i386_PURGATORY_SRCS += purgatory/arch/i386/entry32.S i386_PURGATORY_SRCS += purgatory/arch/i386/setup-x86.S i386_PURGATORY_SRCS += purgatory/arch/i386/stack.S i386_PURGATORY_SRCS += purgatory/arch/i386/compat_x86_64.S i386_PURGATORY_SRCS += purgatory/arch/i386/purgatory-x86.c i386_PURGATORY_SRCS += purgatory/arch/i386/console-x86.c i386_PURGATORY_SRCS += purgatory/arch/i386/vga.c i386_PURGATORY_SRCS += purgatory/arch/i386/pic.c i386_PURGATORY_SRCS += purgatory/arch/i386/crashdump_backup.c dist += purgatory/arch/i386/Makefile $(i386_PURGATORY_SRCS) \ purgatory/arch/i386/purgatory-x86.h \ purgatory/arch/i386/include/arch/io.h \ purgatory/arch/i386/include/arch/debug.h kexec-tools-2.0.10/purgatory/arch/i386/entry32-16.S0000644001567400156740000000000012242534555030722 1kexec-tools-2.0.10/purgatory/arch/i386/entry32-16.Sustar hormshormskexec-tools-2.0.10/purgatory/arch/i386/entry32-16-debug.S0000644001567400156740000000000012242534555033072 1kexec-tools-2.0.10/purgatory/arch/i386/entry32-16-debug.Sustar hormshormskexec-tools-2.0.10/purgatory/arch/i386/entry32.S0000644001567400156740000000504111424244110020202 0ustar hormshorms/* * 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 kexec-tools-2.0.10/purgatory/arch/i386/setup-x86.S0000644001567400156740000000316111424244110020460 0ustar hormshorms/* * 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 purgatory_start purgatory_start: .code32 /* Load a gdt so I know what the segment registers are */ lgdt %cs:gdt /* load the data segments */ movl $0x08, %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: movl 0(%esp), %eax movl %eax, jump_back_entry /* Setup a stack */ movl $lstack_end, %esp /* Call the C code */ call purgatory jmp entry32 .section ".rodata" .balign 16 gdt: /* 0x00 unusable segment so used as the gdt ptr */ .word gdt_end - gdt - 1 .long gdt .word 0 /* 0x8 4GB flat data segment */ .word 0xFFFF, 0x0000, 0x9200, 0x00CF /* 0x10 4GB flat code segment */ .word 0xFFFF, 0x0000, 0x9A00, 0x00CF gdt_end: /* A stack for the purgatory code */ .bss .balign 4096 lstack: .skip 4096 lstack_end: kexec-tools-2.0.10/purgatory/arch/i386/stack.S0000644001567400156740000000266211424244110020007 0ustar hormshorms/* * purgatory: stack * * 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. */ /* A stack for the loaded kernel. * Seperate and in the data section so it can be prepopulated. */ .data .globl stack, stack_end .globl stack_arg32_1, stack_arg32_2, stack_arg32_3 ,stack_arg32_4 .globl stack_arg32_5, stack_arg32_6, stack_arg32_7 ,stack_arg32_8 .balign 4096 stack: .skip 4096 - (8*4) stack_arg32_8: .long 0 ; .size stack_arg32_8, 4 stack_arg32_7: .long 0 ; .size stack_arg32_7, 4 stack_arg32_6: .long 0 ; .size stack_arg32_6, 4 stack_arg32_5: .long 0 ; .size stack_arg32_5, 4 stack_arg32_4: .long 0 ; .size stack_arg32_4, 4 stack_arg32_3: .long 0 ; .size stack_arg32_3, 4 stack_arg32_2: .long 0 ; .size stack_arg32_2, 4 stack_arg32_1: .long 0 ; .size stack_arg32_1, 4 stack_end: kexec-tools-2.0.10/purgatory/arch/i386/compat_x86_64.S0000644001567400156740000000443011424244110021176 0ustar hormshorms/* * 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 kexec-tools-2.0.10/purgatory/arch/i386/purgatory-x86.c0000644001567400156740000000257411424244110021403 0ustar hormshorms#include #include #include "purgatory-x86.h" /* * CPU * ============================================================================= */ void x86_setup_cpu(void) { #if 0 /* This code is only needed for old versions of the kexec kernel patch. * While it is still a good idea doing this unconditionally breaks * on older cpus that did not implemented cr4. * So this code is disabled for now. If this is revisited * I first need to detect cpuid support and then use cpuid * to conditionally change newer cpu registers. */ /* clear special bits in %cr4 */ asm volatile( "movl %0, %%eax\n\t" "movl %%eax, %%cr4\n\t" : /* outputs */ : "r" (0) ); #endif } uint8_t reset_vga = 0; uint8_t legacy_timer = 0; uint8_t legacy_pic = 0; uint8_t panic_kernel = 0; unsigned long jump_back_entry = 0; char *cmdline_end = 0; void setup_arch(void) { x86_setup_cpu(); if (reset_vga) x86_reset_vga(); if (legacy_pic) x86_setup_legacy_pic(); /* if (legacy_timer) x86_setup_legacy_timer(); */ } static void x86_setup_jump_back_entry(void) { if (cmdline_end) sprintf(cmdline_end, " kexec_jump_back_entry=0x%x", jump_back_entry); } /* This function can be used to execute after the SHA256 verification. */ void post_verification_setup_arch(void) { if (panic_kernel) crashdump_backup_memory(); if (jump_back_entry) x86_setup_jump_back_entry(); } kexec-tools-2.0.10/purgatory/arch/i386/console-x86.c0000644001567400156740000000000011424244110031632 1kexec-tools-2.0.10/purgatory/arch/i386/console-x86.custar hormshormskexec-tools-2.0.10/purgatory/arch/i386/vga.c0000644001567400156740000000000011424244110027012 1kexec-tools-2.0.10/purgatory/arch/i386/vga.custar hormshormskexec-tools-2.0.10/purgatory/arch/i386/pic.c0000644001567400156740000000000011424244110027006 1kexec-tools-2.0.10/purgatory/arch/i386/pic.custar hormshormskexec-tools-2.0.10/purgatory/arch/i386/crashdump_backup.c0000644001567400156740000000000011642166046034323 1kexec-tools-2.0.10/purgatory/arch/i386/crashdump_backup.custar hormshormskexec-tools-2.0.10/purgatory/arch/i386/purgatory-x86.h0000644001567400156740000000032111424244110021374 0ustar hormshorms#ifndef PURGATORY_X86_H #define PURGATORY_X86_H void x86_reset_vga(void); void x86_setup_legacy_pic(void); void x86_setup_legacy_timer(void); void crashdump_backup_memory(void); #endif /* PURGATORY_X86_H */ kexec-tools-2.0.10/purgatory/arch/i386/include/arch/io.h0000644001567400156740000000441411424244110021673 0ustar hormshorms#ifndef ARCH_I386_IO_H #define ARCH_I386_IO_H #include /* Helper functions for directly doing I/O */ static inline __attribute__((__always_inline__)) uint8_t inb(uint16_t port) { uint8_t result; __asm__ __volatile__ ( "inb %w1,%0" :"=a" (result) :"Nd" (port)); return result; } static inline __attribute__((__always_inline__)) uint16_t inw(uint16_t port) { uint16_t result; __asm__ __volatile__ ( "inw %w1,%0" :"=a" (result) :"Nd" (port)); return result; } static inline __attribute__((__always_inline__)) uint32_t inl(uint32_t port) { uint32_t result; __asm__ __volatile__ ( "inl %w1,%0" :"=a" (result) :"Nd" (port)); return result; } static inline __attribute__((__always_inline__)) void outb (uint8_t value, uint16_t port) { __asm__ __volatile__ ( "outb %b0,%w1" : :"a" (value), "Nd" (port)); } static inline __attribute__((__always_inline__)) void outw (uint16_t value, uint16_t port) { __asm__ __volatile__ ( "outw %w0,%w1" : :"a" (value), "Nd" (port)); } static inline __attribute__((__always_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 __attribute__((__always_inline__)) unsigned char readb(const volatile void *addr) { return *(volatile unsigned char *) addr; } static inline __attribute__((__always_inline__)) unsigned short readw(const volatile void *addr) { return *(volatile unsigned short *) addr; } static inline __attribute__((__always_inline__)) unsigned int readl(const volatile void *addr) { return *(volatile unsigned int *) addr; } static inline __attribute__((__always_inline__)) void writeb(unsigned char b, volatile void *addr) { *(volatile unsigned char *) addr = b; } static inline __attribute__((__always_inline__)) void writew(unsigned short b, volatile void *addr) { *(volatile unsigned short *) addr = b; } static inline __attribute__((__always_inline__)) void writel(unsigned int b, volatile void *addr) { *(volatile unsigned int *) addr = b; } #endif /* ARCH_I386_IO_H */ kexec-tools-2.0.10/purgatory/arch/i386/include/arch/debug.h0000644001567400156740000001326011424244110022351 0ustar hormshorms/* 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_CHAR(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') kexec-tools-2.0.10/purgatory/arch/ia64/Makefile0000644001567400156740000000063111424244110020262 0ustar hormshorms# # Purgatory ia64 # ia64_PURGATORY_SRCS += purgatory/arch/ia64/entry.S ia64_PURGATORY_SRCS += purgatory/arch/ia64/purgatory-ia64.c ia64_PURGATORY_SRCS += purgatory/arch/ia64/console-ia64.c ia64_PURGATORY_SRCS += purgatory/arch/ia64/vga.c ia64_PURGATORY_EXTRA_CFLAGS = -ffixed-r28 dist += purgatory/arch/ia64/Makefile $(ia64_PURGATORY_SRCS) \ purgatory/arch/ia64/io.h purgatory/arch/ia64/purgatory-ia64.h kexec-tools-2.0.10/purgatory/arch/ia64/entry.S0000644001567400156740000000362311424244110020113 0ustar hormshorms/* * purgatory: setup code * * Copyright (C) 2005-2006 Zou Nan hai (nanhai.zou@intel.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 DECLARE_DATA8(name) \ .global name; \ .size name, 8; \ name: data8 0x0 .global __dummy_efi_function .align 32 .proc __dummy_efi_function __dummy_efi_function: mov r8=r0;; br.ret.sptk.many rp;; .global __dummy_efi_function_end __dummy_efi_function_end: .endp __dummy_efi_function .global purgatory_start .align 32 .proc purgatory_start purgatory_start: movl r2=__gp_value;; ld8 gp=[r2];; br.call.sptk.many b0=purgatory ;; alloc r2 = ar.pfs, 0, 0, 2, 0 ;; mov out0=r28 movl out1=__vmcode_base; br.call.sptk.many b0=ia64_env_setup movl r10=__kernel_entry;; ld8 r14=[r10];; movl r10=__boot_param_base;; ld8 r28=[r10];; mov b6=r14;; mov ar.lc=r0 mov ar.ec=r0 cover;; invala;; br.call.sptk.many b0=b6 .endp purgatory_start DECLARE_DATA8(__kernel_entry) DECLARE_DATA8(__vmcode_base) DECLARE_DATA8(__vmcode_size) DECLARE_DATA8(__ramdisk_base) DECLARE_DATA8(__ramdisk_size) DECLARE_DATA8(__command_line) DECLARE_DATA8(__command_line_len) DECLARE_DATA8(__efi_memmap_base) DECLARE_DATA8(__efi_memmap_size) DECLARE_DATA8(__boot_param_base) DECLARE_DATA8(__loaded_segments) DECLARE_DATA8(__loaded_segments_num) DECLARE_DATA8(__gp_value) DECLARE_DATA8(__noio) kexec-tools-2.0.10/purgatory/arch/ia64/purgatory-ia64.c0000644001567400156740000002377011642166046021611 0ustar hormshorms/* * purgatory: setup code * * Copyright (C) 2005-2006 Zou Nan hai (nanhai.zou@intel.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 #include #include #include "purgatory-ia64.h" #define PAGE_OFFSET 0xe000000000000000UL #define EFI_PAGE_SHIFT 12 #define EFI_PAGE_SIZE (1UL<efi_memmap_base; void *src = (void *)boot_param->efi_memmap; uint64_t orig_type; efi_memory_desc_t *src_md, *dst_md; void *src_end = src + boot_param->efi_memmap_size; unsigned long i; for (; src < src_end; src += boot_param->efi_memdesc_size, dest += boot_param->efi_memdesc_size) { unsigned long mstart, mend; src_md = src; dst_md = dest; if (src_md->num_pages == 0) continue; mstart = src_md->phys_addr; mend = src_md->phys_addr + (src_md->num_pages << EFI_PAGE_SHIFT); *dst_md = *src_md; if (src_md->type == EFI_LOADER_DATA) dst_md->type = EFI_CONVENTIONAL_MEMORY; /* segments are already sorted and aligned to 4K */ orig_type = dst_md->type; for (i = 0; i < params->loaded_segments_num; i++) { struct loaded_segment *seg; unsigned long start_pages, mid_pages, end_pages; seg = ¶ms->loaded_segments[i]; if (seg->start < mstart || seg->start >= mend) continue; while (seg->end > mend && src < src_end) { src += boot_param->efi_memdesc_size; src_md = src; /* TODO check contig and attribute here */ mend = src_md->phys_addr + (src_md->num_pages << EFI_PAGE_SHIFT); } if (seg->end < mend && src < src_end) { void *src_next; efi_memory_desc_t *src_next_md; src_next = src + boot_param->efi_memdesc_size; src_next_md = src_next; if (src_next_md->type == EFI_CONVENTIONAL_MEMORY) { /* TODO check contig and attribute */ src += boot_param->efi_memdesc_size; src_md = src; mend = src_md->phys_addr + (src_md->num_pages << EFI_PAGE_SHIFT); } } start_pages = (seg->start - mstart) >> EFI_PAGE_SHIFT; mid_pages = (seg->end - seg->start) >> EFI_PAGE_SHIFT; end_pages = (mend - seg->end) >> EFI_PAGE_SHIFT; if (start_pages) { dst_md->num_pages = start_pages; dest += boot_param->efi_memdesc_size; dst_md = dest; *dst_md = *src_md; } dst_md->phys_addr = seg->start; dst_md->num_pages = mid_pages; dst_md->type = EFI_LOADER_DATA; if (!end_pages) break; dest += boot_param->efi_memdesc_size; dst_md = dest; *dst_md = *src_md; dst_md->phys_addr = seg->end; dst_md->num_pages = end_pages; dst_md->type = orig_type; mstart = seg->end; } } boot_param->efi_memmap_size = dest - (void *)params->efi_memmap_base; } void flush_icache_range(char *start, unsigned long len) { unsigned long i, addr; addr = (unsigned long)start & ~31UL; len += (unsigned long)start - addr; for (i = 0;i < len; i += 32) asm volatile("fc.i %0"::"r"(start + i):"memory"); asm volatile (";;sync.i;;":::"memory"); asm volatile ("srlz.i":::"memory"); } extern char __dummy_efi_function[], __dummy_efi_function_end[]; void ia64_env_setup(struct ia64_boot_param *boot_param, struct kexec_boot_params *params) { unsigned long len; efi_system_table_t *systab; efi_runtime_services_t *runtime; unsigned long *set_virtual_address_map; char *command_line = (char *)params->command_line; uint64_t command_line_len = params->command_line_len; struct ia64_boot_param *new_boot_param = (struct ia64_boot_param *) params->boot_param_base; memcpy(new_boot_param, boot_param, 4096); /* * patch efi_runtime->set_virtual_address_map to a dummy function * * The EFI specification mandates that set_virtual_address_map only * takes effect the first time that it is called, and that * subsequent calls will return error. By replacing it with a * dummy function the new OS can think it is calling it again * without either the OS or any buggy EFI implementations getting * upset. * * Note: as the EFI specification says that set_virtual_address_map * will only take affect the first time it is called, the mapping * can't be updated, and thus mapping of the old and new OS really * needs to be the same. */ len = __dummy_efi_function_end - __dummy_efi_function; memcpy(command_line + command_line_len, __dummy_efi_function, len); systab = (efi_system_table_t *)new_boot_param->efi_systab; runtime = (efi_runtime_services_t *)PA(systab->runtime); set_virtual_address_map = (unsigned long *)PA(runtime->set_virtual_address_map); *(set_virtual_address_map) = (unsigned long)(command_line + command_line_len); flush_icache_range(command_line + command_line_len, len); patch_efi_memmap(params, new_boot_param); new_boot_param->efi_memmap = params->efi_memmap_base; new_boot_param->command_line = params->command_line; new_boot_param->console_info.orig_x = 0; new_boot_param->console_info.orig_y = 0; new_boot_param->initrd_start = params->ramdisk_base; new_boot_param->initrd_size = params->ramdisk_size; new_boot_param->vmcode_start = params->vmcode_base; new_boot_param->vmcode_size = params->vmcode_size; } /* This function can be used to execute after the SHA256 verification. */ void post_verification_setup_arch(void) { /* Nothing for now */ } kexec-tools-2.0.10/purgatory/arch/ia64/console-ia64.c0000644001567400156740000000171511424244110021175 0ustar hormshorms#include #include "io.h" #define VGABASE UNCACHED(0xb8000) /* code based on i386 console code * TODO add serial support */ #define MAX_YPOS 25 #define MAX_XPOS 80 unsigned long current_ypos = 1, current_xpos = 0; static void putchar_vga(int ch) { int i, k, j; 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++; } } } void putchar(int ch) { putchar_vga(ch); } kexec-tools-2.0.10/purgatory/arch/ia64/vga.c0000644001567400156740000000442211424244110017545 0ustar hormshorms#include "io.h" void reset_vga(void) { /* Hello */ inb(0x3da); outb(0, 0x3c0); /* Sequencer registers */ outw(0x0300, 0x3c4); outw(0x0001, 0x3c4); outw(0x0302, 0x3c4); outw(0x0003, 0x3c4); outw(0x0204, 0x3c4); /* Ensure CRTC regs 0-7 are unlocked by clearing bit 7 of CRTC[17] */ outw(0x0e11, 0x3d4); /* CRTC registers */ outw(0x5f00, 0x3d4); outw(0x4f01, 0x3d4); outw(0x5002, 0x3d4); outw(0x8203, 0x3d4); outw(0x5504, 0x3d4); outw(0x8105, 0x3d4); outw(0xbf06, 0x3d4); outw(0x1f07, 0x3d4); outw(0x0008, 0x3d4); outw(0x4f09, 0x3d4); outw(0x200a, 0x3d4); outw(0x0e0b, 0x3d4); outw(0x000c, 0x3d4); outw(0x000d, 0x3d4); outw(0x010e, 0x3d4); outw(0xe00f, 0x3d4); outw(0x9c10, 0x3d4); outw(0x8e11, 0x3d4); outw(0x8f12, 0x3d4); outw(0x2813, 0x3d4); outw(0x1f14, 0x3d4); outw(0x9615, 0x3d4); outw(0xb916, 0x3d4); outw(0xa317, 0x3d4); outw(0xff18, 0x3d4); /* Graphic registers */ outw(0x0000, 0x3ce); outw(0x0001, 0x3ce); outw(0x0002, 0x3ce); outw(0x0003, 0x3ce); outw(0x0004, 0x3ce); outw(0x1005, 0x3ce); outw(0x0e06, 0x3ce); outw(0x0007, 0x3ce); outw(0xff08, 0x3ce); /* Attribute registers */ inb(0x3da); outb(0x00, 0x3c0); outb(0x00, 0x3c0); inb(0x3da); outb(0x01, 0x3c0); outb(0x01, 0x3c0); inb(0x3da); outb(0x02, 0x3c0); outb(0x02, 0x3c0); inb(0x3da); outb(0x03, 0x3c0); outb(0x03, 0x3c0); inb(0x3da); outb(0x04, 0x3c0); outb(0x04, 0x3c0); inb(0x3da); outb(0x05, 0x3c0); outb(0x05, 0x3c0); inb(0x3da); outb(0x06, 0x3c0); outb(0x14, 0x3c0); inb(0x3da); outb(0x07, 0x3c0); outb(0x07, 0x3c0); inb(0x3da); outb(0x08, 0x3c0); outb(0x38, 0x3c0); inb(0x3da); outb(0x09, 0x3c0); outb(0x39, 0x3c0); inb(0x3da); outb(0x0a, 0x3c0); outb(0x3a, 0x3c0); inb(0x3da); outb(0x0b, 0x3c0); outb(0x3b, 0x3c0); inb(0x3da); outb(0x0c, 0x3c0); outb(0x3c, 0x3c0); inb(0x3da); outb(0x0d, 0x3c0); outb(0x3d, 0x3c0); inb(0x3da); outb(0x0e, 0x3c0); outb(0x3e, 0x3c0); inb(0x3da); outb(0x0f, 0x3c0); outb(0x3f, 0x3c0); inb(0x3da); outb(0x10, 0x3c0); outb(0x0c, 0x3c0); inb(0x3da); outb(0x11, 0x3c0); outb(0x00, 0x3c0); inb(0x3da); outb(0x12, 0x3c0); outb(0x0f, 0x3c0); inb(0x3da); outb(0x13, 0x3c0); outb(0x08, 0x3c0); inb(0x3da); outb(0x14, 0x3c0); outb(0x00, 0x3c0); /* Goodbye */ inb(0x3da); outb(0x20, 0x3c0); } kexec-tools-2.0.10/purgatory/arch/ia64/io.h0000644001567400156740000000431711424244110017407 0ustar hormshorms#ifndef IO_H #define IO_H #define UNCACHED(x) (void *)((x)|(1UL<<63)) #define MF() asm volatile ("mf.a" ::: "memory") #define IO_SPACE_ENCODING(p) ((((p) >> 2) << 12) | (p & 0xfff)) extern long __noio; static inline void *io_addr (unsigned long port) { unsigned long offset; unsigned long io_base; asm volatile ("mov %0=ar.k0":"=r"(io_base)); offset = IO_SPACE_ENCODING(port); return UNCACHED(io_base | offset); } static inline unsigned int inb (unsigned long port) { volatile unsigned char *addr = io_addr(port); unsigned char ret = 0; if (!__noio) { ret = *addr; MF(); } return ret; } static inline unsigned int inw (unsigned long port) { volatile unsigned short *addr = io_addr(port); unsigned short ret = 0; if (!__noio) { ret = *addr; MF(); } return ret; } static inline unsigned int inl (unsigned long port) { volatile unsigned int *addr = io_addr(port); unsigned int ret ; if (!__noio) { ret = *addr; MF(); } return ret; } static inline void outb (unsigned char val, unsigned long port) { volatile unsigned char *addr = io_addr(port); if (!__noio) { *addr = val; MF(); } } static inline void outw (unsigned short val, unsigned long port) { volatile unsigned short *addr = io_addr(port); if (!__noio) { *addr = val; MF(); } } static inline void outl (unsigned int val, unsigned long port) { volatile unsigned int *addr = io_addr(port); if (!__noio) { *addr = val; MF(); } } static inline unsigned char readb(const volatile void *addr) { return __noio ? 0 :*(volatile unsigned char *) addr; } static inline unsigned short readw(const volatile void *addr) { return __noio ? 0 :*(volatile unsigned short *) addr; } static inline unsigned int readl(const volatile void *addr) { return __noio ? 0 :*(volatile unsigned int *) addr; } static inline void writeb(unsigned char b, volatile void *addr) { if (!__noio) *(volatile unsigned char *) addr = b; } static inline void writew(unsigned short b, volatile void *addr) { if (!__noio) *(volatile unsigned short *) addr = b; } static inline void writel(unsigned int b, volatile void *addr) { if (!__noio) *(volatile unsigned int *) addr = b; } #endif kexec-tools-2.0.10/purgatory/arch/ia64/purgatory-ia64.h0000644001567400156740000000014711424244110021572 0ustar hormshorms#ifndef PURGATORY_IA64_H #define PURGATORY_IA64_H void reset_vga(void); #endif /* PURGATORY_IA64_H */ kexec-tools-2.0.10/purgatory/arch/mips/Makefile0000644001567400156740000000036111424244110020467 0ustar hormshorms# # Purgatory mips # mips_PURGATORY_SRCS+= purgatory/arch/mips/purgatory-mips.c mips_PURGATORY_SRCS+= purgatory/arch/mips/console-mips.c dist += purgatory/arch/mips/Makefile $(mips_PURGATORY_SRCS) \ purgatory/arch/mips/purgatory-mips.h kexec-tools-2.0.10/purgatory/arch/mips/purgatory-mips.c0000644001567400156740000000014511424244110022175 0ustar hormshorms#include #include "purgatory-mips.h" void setup_arch(void) { /* Nothing for now */ } kexec-tools-2.0.10/purgatory/arch/mips/console-mips.c0000644001567400156740000000014411642166046021617 0ustar hormshorms#include #include "unused.h" void putchar(int UNUSED(ch)) { /* Nothing for now */ } kexec-tools-2.0.10/purgatory/arch/mips/purgatory-mips.h0000644001567400156740000000015211424244110022200 0ustar hormshorms#ifndef PURGATORY_MIPSEL_H #define PURGATORY_MIPSEL_H /* nothing yet */ #endif /* PURGATORY_MIPSEL_H */ kexec-tools-2.0.10/purgatory/arch/ppc/Makefile0000644001567400156740000000062612242534555020323 0ustar hormshorms# # Purgatory ppc # ppc_PURGATORY_SRCS += purgatory/arch/ppc/v2wrap_32.S ppc_PURGATORY_SRCS += purgatory/arch/ppc/misc.S ppc_PURGATORY_SRCS += purgatory/arch/ppc/purgatory-ppc.c ppc_PURGATORY_SRCS += purgatory/arch/ppc/console-ppc.c ppc_PURGATORY_EXTRA_CFLAGS += -msoft-float dist += purgatory/arch/ppc/Makefile $(ppc_PURGATORY_SRCS) \ purgatory/arch/ppc/purgatory-ppc.h purgatory/arch/ppc/ppc_asm.h kexec-tools-2.0.10/purgatory/arch/ppc/v2wrap_32.S0000644001567400156740000000573211642166046020536 0ustar hormshorms# # kexec: Linux boots Linux # # Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation # Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM 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 (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. # # v2wrap.S # a wrapper to call purgatory code to backup first # 32kB of first kernel into the backup region # reserved by kexec-tools. # Invokes powerpc kernel with the expected arguments # of kernel(device-tree, phys-offset, 0) # # calling convention: # r3 = physical number of this cpu (all cpus) # r4 = address of this chunk (master only) # master enters at purgatory_start (aka first byte of this chunk) # slaves (additional cpus), if any, enter a copy of the # first 0x100 bytes of this code relocated to 0x0 # # in other words, # a copy of the first 0x100 bytes of this code is copied to 0 # and the slaves are sent to address 0x60 # with r3 = their physical cpu number. .globl purgatory_start purgatory_start: b master .org purgatory_start + 0x60 # ABI: slaves start at 60 with r3=phys slave: b $ .org purgatory_start + 0x100 # ABI: end of copied region .size purgatory_start, . - purgatory_start # # The above 0x100 bytes at purgatory_start are replaced with the # code from the kernel (or next stage) by kexec/arch/powerpc/kexec-powerpc.c # master: or 1,1,1 # low priority to let other threads catchup isync mr 17,3 # save cpu id to r17 mr 15,4 # save physical address in reg15 lis 6,my_thread_ptr@h ori 6,6,my_thread_ptr@l lwz 2,0(6) # setup ThreadPointer(TP) lis 6,stack@h ori 6,6,stack@l lwz 1,0(6) #setup stack subi 1,1,112 bl purgatory nop or 3,3,3 # ok now to high priority, lets boot lis 6,0x1 mtctr 6 # delay a bit for slaves to catch up 83: bdnz 83b # before we overwrite 0-100 again lis 6,dt_offset@h ori 6,6,dt_offset@l lwz 3,0(6) # load device-tree address lwz 6,20(3) # fetch version number cmpwi 0,6,2 # v2 ? blt 80f stw 17,28(3) # save my cpu number as boot_cpu_phys 80: lis 6,kernel@h ori 6,6,kernel@l lwz 4,0(6) # load the kernel address li 5,0 # r5 will be 0 for kernel li 6,0 # clear r6 for good measure mtctr 4 # prepare branch too lwz 8,0(4) # get the first instruction that we stole stw 8,0(0) # and put it in the slave loop at 0 # skip cache flush, do we care? bctr # start kernel kexec-tools-2.0.10/purgatory/arch/ppc/misc.S0000644001567400156740000001760211642166046017743 0ustar hormshorms/* * This file contains miscellaneous low-level functions. * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) * and Paul Mackerras. * * Rewrittten to work with /sbin/kexec 20 December 2004 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. * */ #include "ppc_asm.h" /* This is from linux-2.6/arch/powerpc/lib/crtsavres.S: * * Special support for eabi and SVR4 * * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc. * Copyright 2008 Freescale Semiconductor, Inc. * Written By Michael Meissner * * Based on gcc/config/rs6000/crtsavres.asm from gcc * * This file 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, or (at your option) any * later version. * * In addition to the permissions in the GNU General Public License, the * Free Software Foundation gives you unlimited permission to link the * compiled version of this file with other programs, and to distribute * those programs without any restriction coming from the use of this * file. (The General Public License restrictions do apply in other * respects; for example, they cover modification of the file, and * distribution when not linked into another program.) * * This file 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; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * As a special exception, if you link this library with files * compiled with GCC to produce an executable, this does not cause * the resulting executable to be covered by the GNU General Public License. * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. */ #include "config.h" #define _GLOBAL(name) \ .type name,@function; \ .globl name; \ name: /* Routines for saving integer registers, called by the compiler. */ /* Called with r11 pointing to the stack header word of the caller of the */ /* function, just beyond the end of the integer save area. */ _GLOBAL(_savegpr_14) _GLOBAL(_save32gpr_14) stw 14,-72(11) /* save gp registers */ _GLOBAL(_savegpr_15) _GLOBAL(_save32gpr_15) stw 15,-68(11) _GLOBAL(_savegpr_16) _GLOBAL(_save32gpr_16) stw 16,-64(11) _GLOBAL(_savegpr_17) _GLOBAL(_save32gpr_17) stw 17,-60(11) _GLOBAL(_savegpr_18) _GLOBAL(_save32gpr_18) stw 18,-56(11) _GLOBAL(_savegpr_19) _GLOBAL(_save32gpr_19) stw 19,-52(11) _GLOBAL(_savegpr_20) _GLOBAL(_save32gpr_20) stw 20,-48(11) _GLOBAL(_savegpr_21) _GLOBAL(_save32gpr_21) stw 21,-44(11) _GLOBAL(_savegpr_22) _GLOBAL(_save32gpr_22) stw 22,-40(11) _GLOBAL(_savegpr_23) _GLOBAL(_save32gpr_23) stw 23,-36(11) _GLOBAL(_savegpr_24) _GLOBAL(_save32gpr_24) stw 24,-32(11) _GLOBAL(_savegpr_25) _GLOBAL(_save32gpr_25) stw 25,-28(11) _GLOBAL(_savegpr_26) _GLOBAL(_save32gpr_26) stw 26,-24(11) _GLOBAL(_savegpr_27) _GLOBAL(_save32gpr_27) stw 27,-20(11) _GLOBAL(_savegpr_28) _GLOBAL(_save32gpr_28) stw 28,-16(11) _GLOBAL(_savegpr_29) _GLOBAL(_save32gpr_29) stw 29,-12(11) _GLOBAL(_savegpr_30) _GLOBAL(_save32gpr_30) stw 30,-8(11) _GLOBAL(_savegpr_31) _GLOBAL(_save32gpr_31) stw 31,-4(11) blr /* Routines for restoring integer registers, called by the compiler. */ /* Called with r11 pointing to the stack header word of the caller of the */ /* function, just beyond the end of the integer restore area. */ _GLOBAL(_restgpr_14) _GLOBAL(_rest32gpr_14) lwz 14,-72(11) /* restore gp registers */ _GLOBAL(_restgpr_15) _GLOBAL(_rest32gpr_15) lwz 15,-68(11) _GLOBAL(_restgpr_16) _GLOBAL(_rest32gpr_16) lwz 16,-64(11) _GLOBAL(_restgpr_17) _GLOBAL(_rest32gpr_17) lwz 17,-60(11) _GLOBAL(_restgpr_18) _GLOBAL(_rest32gpr_18) lwz 18,-56(11) _GLOBAL(_restgpr_19) _GLOBAL(_rest32gpr_19) lwz 19,-52(11) _GLOBAL(_restgpr_20) _GLOBAL(_rest32gpr_20) lwz 20,-48(11) _GLOBAL(_restgpr_21) _GLOBAL(_rest32gpr_21) lwz 21,-44(11) _GLOBAL(_restgpr_22) _GLOBAL(_rest32gpr_22) lwz 22,-40(11) _GLOBAL(_restgpr_23) _GLOBAL(_rest32gpr_23) lwz 23,-36(11) _GLOBAL(_restgpr_24) _GLOBAL(_rest32gpr_24) lwz 24,-32(11) _GLOBAL(_restgpr_25) _GLOBAL(_rest32gpr_25) lwz 25,-28(11) _GLOBAL(_restgpr_26) _GLOBAL(_rest32gpr_26) lwz 26,-24(11) _GLOBAL(_restgpr_27) _GLOBAL(_rest32gpr_27) lwz 27,-20(11) _GLOBAL(_restgpr_28) _GLOBAL(_rest32gpr_28) lwz 28,-16(11) _GLOBAL(_restgpr_29) _GLOBAL(_rest32gpr_29) lwz 29,-12(11) _GLOBAL(_restgpr_30) _GLOBAL(_rest32gpr_30) lwz 30,-8(11) _GLOBAL(_restgpr_31) _GLOBAL(_rest32gpr_31) lwz 31,-4(11) blr /* Routines for restoring integer registers, called by the compiler. */ /* Called with r11 pointing to the stack header word of the caller of the */ /* function, just beyond the end of the integer restore area. */ _GLOBAL(_restgpr_14_x) _GLOBAL(_rest32gpr_14_x) lwz 14,-72(11) /* restore gp registers */ _GLOBAL(_restgpr_15_x) _GLOBAL(_rest32gpr_15_x) lwz 15,-68(11) _GLOBAL(_restgpr_16_x) _GLOBAL(_rest32gpr_16_x) lwz 16,-64(11) _GLOBAL(_restgpr_17_x) _GLOBAL(_rest32gpr_17_x) lwz 17,-60(11) _GLOBAL(_restgpr_18_x) _GLOBAL(_rest32gpr_18_x) lwz 18,-56(11) _GLOBAL(_restgpr_19_x) _GLOBAL(_rest32gpr_19_x) lwz 19,-52(11) _GLOBAL(_restgpr_20_x) _GLOBAL(_rest32gpr_20_x) lwz 20,-48(11) _GLOBAL(_restgpr_21_x) _GLOBAL(_rest32gpr_21_x) lwz 21,-44(11) _GLOBAL(_restgpr_22_x) _GLOBAL(_rest32gpr_22_x) lwz 22,-40(11) _GLOBAL(_restgpr_23_x) _GLOBAL(_rest32gpr_23_x) lwz 23,-36(11) _GLOBAL(_restgpr_24_x) _GLOBAL(_rest32gpr_24_x) lwz 24,-32(11) _GLOBAL(_restgpr_25_x) _GLOBAL(_rest32gpr_25_x) lwz 25,-28(11) _GLOBAL(_restgpr_26_x) _GLOBAL(_rest32gpr_26_x) lwz 26,-24(11) _GLOBAL(_restgpr_27_x) _GLOBAL(_rest32gpr_27_x) lwz 27,-20(11) _GLOBAL(_restgpr_28_x) _GLOBAL(_rest32gpr_28_x) lwz 28,-16(11) _GLOBAL(_restgpr_29_x) _GLOBAL(_rest32gpr_29_x) lwz 29,-12(11) _GLOBAL(_restgpr_30_x) _GLOBAL(_rest32gpr_30_x) lwz 30,-8(11) _GLOBAL(_restgpr_31_x) _GLOBAL(_rest32gpr_31_x) lwz 0,4(11) lwz 31,-4(11) mtlr 0 mr 1,11 blr .text /* * Extended precision shifts. * * Updated to be valid for shift counts from 0 to 63 inclusive. * -- Gabriel * * R3/R4 has 64 bit value * R5 has shift count * result in R3/R4 * * ashrdi3: arithmetic right shift (sign propagation) * lshrdi3: logical right shift * ashldi3: left shift */ .globl __ashrdi3 __ashrdi3: subfic r6,r5,32 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count addi r7,r5,32 # could be xori, or addi with -32 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 sraw r7,r3,r7 # t2 = MSW >> (count-32) or r4,r4,r6 # LSW |= t1 slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 sraw r3,r3,r5 # MSW = MSW >> count or r4,r4,r7 # LSW |= t2 blr .globl __ashldi3 __ashldi3: subfic r6,r5,32 slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count addi r7,r5,32 # could be xori, or addi with -32 srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) or r3,r3,r6 # MSW |= t1 slw r4,r4,r5 # LSW = LSW << count or r3,r3,r7 # MSW |= t2 blr .globl __lshrdi3 __lshrdi3: subfic r6,r5,32 srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count addi r7,r5,32 # could be xori, or addi with -32 slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) or r4,r4,r6 # LSW |= t1 srw r3,r3,r5 # MSW = MSW >> count or r4,r4,r7 # LSW |= t2 blr kexec-tools-2.0.10/purgatory/arch/ppc/purgatory-ppc.c0000644001567400156740000000232311650221515021626 0ustar hormshorms/* * kexec: Linux boots Linux * * Created by: Mohan Kumar M (mohan@in.ibm.com) * * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include "purgatory-ppc.h" unsigned int panic_kernel = 0; unsigned long backup_start = 0; unsigned long stack = 0; unsigned long dt_offset = 0; unsigned long my_thread_ptr = 0; unsigned long kernel = 0; void setup_arch(void) { return; } void post_verification_setup_arch(void) { #ifndef CONFIG_BOOKE if (panic_kernel) crashdump_backup_memory(); #endif } void crashdump_backup_memory(void) { return; } kexec-tools-2.0.10/purgatory/arch/ppc/console-ppc.c0000644001567400156740000000014411642166046021243 0ustar hormshorms#include #include "unused.h" void putchar(int UNUSED(ch)) { /* Nothing for now */ } kexec-tools-2.0.10/purgatory/arch/ppc/purgatory-ppc.h0000644001567400156740000000023311642166046021641 0ustar hormshorms#ifndef PURGATORY_PPC_H #define PURGATORY_PPC_H void crashdump_backup_memory(void); void post_verification_setup_arch(void); #endif /* PURGATORY_PPC_H */ kexec-tools-2.0.10/purgatory/arch/ppc/ppc_asm.h0000644001567400156740000005423111424244110020441 0ustar hormshorms/* * 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 kexec-tools-2.0.10/purgatory/arch/ppc64/Makefile0000644001567400156740000000172712520334015020464 0ustar hormshorms# # Purgatory ppc64 # ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/v2wrap.S ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/hvCall.S ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/purgatory-ppc64.c ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/console-ppc64.c ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/crashdump_backup.c ppc64_PURGATORY_SRCS += purgatory/arch/ppc64/misc.S ppc64_PURGATORY_EXTRA_CFLAGS += -m64 -msoft-float \ -fno-exceptions ppc64_PURGATORY_EXTRA_ASFLAGS += -m64 ifeq ($(SUBARCH),BE) ppc64_PURGATORY_EXTRA_LDFLAGS += -melf64ppc ppc64_PURGATORY_EXTRA_CFLAGS += -mcall-aixdesc ppc64_PURGATORY_EXTRA_ASFLAGS += -mcall-aixdesc else ppc64_PURGATORY_EXTRA_LDFLAGS += -melf64lppc ppc64_PURGATORY_EXTRA_CFLAGS += -mlittle-endian ppc64_PURGATORY_EXTRA_ASFLAGS += -mlittle-endian endif dist += purgatory/arch/ppc64/Makefile $(ppc64_PURGATORY_SRCS) \ purgatory/arch/ppc64/hvCall.h \ purgatory/arch/ppc64/ppc64_asm.h \ purgatory/arch/ppc64/purgatory-ppc64.h kexec-tools-2.0.10/purgatory/arch/ppc64/v2wrap.S0000644001567400156740000000740212417126536020401 0ustar hormshorms# # kexec: Linux boots Linux # # Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation # Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM 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 (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 "ppc64_asm.h" # v2wrap.S # a wrapper to call purgatory code to backup first # 32kB of first kernel into the backup region # reserved by kexec-tools. # Invokes ppc64 kernel with the expected arguments # of kernel(device-tree, phys-offset, 0) # # calling convention: # r3 = physical number of this cpu (all cpus) # r4 = address of this chunk (master only) # master enters at purgatory_start (aka first byte of this chunk) # slaves (additional cpus), if any, enter a copy of the # first 0x100 bytes of this code relocated to 0x0 # # in other words, # a copy of the first 0x100 bytes of this code is copied to 0 # and the slaves are sent to address 0x60 # with r3 = their physical cpu number. #define LOADADDR(rn,name) \ lis rn,name##@highest; \ ori rn,rn,name##@higher; \ rldicr rn,rn,32,31; \ oris rn,rn,name##@h; \ ori rn,rn,name##@l .machine ppc64 .align 8 .globl purgatory_start purgatory_start: b master .org purgatory_start + 0x5c # ABI: possible run_at_load flag at 0x5c .globl run_at_load run_at_load: .long 0 .size run_at_load, . - run_at_load .org purgatory_start + 0x60 # ABI: slaves start at 60 with r3=phys slave: b $ .org purgatory_start + 0x100 # ABI: end of copied region .size purgatory_start, . - purgatory_start # # The above 0x100 bytes at purgatory_start are replaced with the # code from the kernel (or next stage) by kexec/arch/ppc64/kexec-elf-ppc64.c # master: or 1,1,1 # low priority to let other threads catchup isync mr 17,3 # save cpu id to r17 mr 15,4 # save physical address in reg15 LOADADDR(6,my_toc) ld 2,0(6) #setup toc LOADADDR(6,stack) ld 1,0(6) #setup stack subi 1,1,112 bl DOTSYM(purgatory) nop or 3,3,3 # ok now to high priority, lets boot lis 6,0x1 mtctr 6 # delay a bit for slaves to catch up 83: bdnz 83b # before we overwrite 0-100 again LOADADDR(16, dt_offset) ld 3,0(16) # load device-tree address mr 16,3 # save dt address in reg16 #ifdef __BIG_ENDIAN__ lwz 6,20(3) # fetch version number #else li 4,20 lwbrx 6,3,4 # fetch BE version number #endif cmpwi 0,6,2 # v2 ? blt 80f #ifdef __BIG_ENDIAN__ stw 17,28(3) # save my cpu number as boot_cpu_phys #else li 4,28 stwbrx 17,3,4 # Store my cpu as BE value #endif 80: LOADADDR(6,opal_base) # For OPAL early debug ld 8,0(6) # load the OPAL base address in r8 LOADADDR(6,opal_entry) # For OPAL early debug ld 9,0(6) # load the OPAL entry address in r9 LOADADDR(6,kernel) ld 4,0(6) # load the kernel address LOADADDR(6,run_at_load) # the load flag lwz 7,0(6) # possibly patched by kexec-elf-ppc64 stw 7,0x5c(4) # and patch it into the kernel li 5,0 # r5 will be 0 for kernel mtctr 4 # prepare branch too mr 3,16 # restore dt address # skip cache flush, do we care? bctr # start kernel kexec-tools-2.0.10/purgatory/arch/ppc64/hvCall.S0000644001567400156740000000141312417126536020365 0ustar hormshorms/* * This file contains the generic function to perform a call to the * pSeries LPAR hypervisor. * * Taken from linux/arch/powerpc/platforms/pseries/hvCall.S * * 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. */ #include "ppc64_asm.h" #define HVSC .long 0x44000022 .text .machine ppc64 .globl DOTSYM(plpar_hcall_norets) DOTSYM(plpar_hcall_norets): or 6,6,6 # medium low priority mfcr 0 stw 0,8(1) HVSC /* invoke the hypervisor */ lwz 0,8(1) mtcrf 0xff,0 blr /* return r3 = status */ kexec-tools-2.0.10/purgatory/arch/ppc64/purgatory-ppc64.c0000644001567400156740000000232412417126536022164 0ustar hormshorms/* * kexec: Linux boots Linux * * Created by: Mohan Kumar M (mohan@in.ibm.com) * * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include "purgatory-ppc64.h" unsigned int panic_kernel = 0; unsigned long backup_start = 0; unsigned long stack = 0; unsigned long dt_offset = 0; unsigned long my_toc = 0; unsigned long kernel = 0; unsigned int debug = 0; unsigned long opal_base = 0; unsigned long opal_entry = 0; void setup_arch(void) { return; } void post_verification_setup_arch(void) { if (panic_kernel) crashdump_backup_memory(); } kexec-tools-2.0.10/purgatory/arch/ppc64/console-ppc64.c0000644001567400156740000000231512417126536021572 0ustar hormshorms/* * kexec: Linux boots Linux * * Created by: Mohan Kumar M (mohan@in.ibm.com) * * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include "hvCall.h" #include #include #include extern int debug; void putchar(int c) { char buff[16]; unsigned long *lbuf = (unsigned long *)buff; if (!debug) /* running on non pseries */ return; if (c == '\n') putchar('\r'); buff[0] = c; plpar_hcall_norets(H_PUT_TERM_CHAR, 0, 1, __cpu_to_be64(lbuf[0]), __cpu_to_be64(lbuf[1])); return; } kexec-tools-2.0.10/purgatory/arch/ppc64/crashdump_backup.c0000644001567400156740000000224711424244110022477 0ustar hormshorms/* * kexec: Linux boots Linux * * Created by: Mohan Kumar M (mohan@in.ibm.com) * * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include #include "../../../kexec/arch/ppc64/crashdump-ppc64.h" extern unsigned long backup_start; /* Backup first 32KB of memory to backup region reserved by kexec */ void crashdump_backup_memory(void) { void *dest, *src; src = (void *)BACKUP_SRC_START; if (backup_start) { dest = (void *)(backup_start); memcpy(dest, src, BACKUP_SRC_SIZE); } } kexec-tools-2.0.10/purgatory/arch/ppc64/misc.S0000644001567400156740000001040311660152422020076 0ustar hormshorms/* * This is from linux/arch/powerpc/lib/crtsavres.S: * * Special support for eabi and SVR4 * * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc. * Copyright 2008 Freescale Semiconductor, Inc. * Written By Michael Meissner * * Based on gcc/config/rs6000/crtsavres.asm from gcc * 64 bit additions from reading the PPC elf64abi document. * * This file 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, or (at your option) any * later version. * * In addition to the permissions in the GNU General Public License, the * Free Software Foundation gives you unlimited permission to link the * compiled version of this file with other programs, and to distribute * those programs without any restriction coming from the use of this * file. (The General Public License restrictions do apply in other * respects; for example, they cover modification of the file, and * distribution when not linked into another program.) * * This file 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; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * As a special exception, if you link this library with files * compiled with GCC to produce an executable, this does not cause * the resulting executable to be covered by the GNU General Public License. * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. */ #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 .text .globl _savegpr0_14 _savegpr0_14: std r14,-144(r1) .globl _savegpr0_15 _savegpr0_15: std r15,-136(r1) .globl _savegpr0_16 _savegpr0_16: std r16,-128(r1) .globl _savegpr0_17 _savegpr0_17: std r17,-120(r1) .globl _savegpr0_18 _savegpr0_18: std r18,-112(r1) .globl _savegpr0_19 _savegpr0_19: std r19,-104(r1) .globl _savegpr0_20 _savegpr0_20: std r20,-96(r1) .globl _savegpr0_21 _savegpr0_21: std r21,-88(r1) .globl _savegpr0_22 _savegpr0_22: std r22,-80(r1) .globl _savegpr0_23 _savegpr0_23: std r23,-72(r1) .globl _savegpr0_24 _savegpr0_24: std r24,-64(r1) .globl _savegpr0_25 _savegpr0_25: std r25,-56(r1) .globl _savegpr0_26 _savegpr0_26: std r26,-48(r1) .globl _savegpr0_27 _savegpr0_27: std r27,-40(r1) .globl _savegpr0_28 _savegpr0_28: std r28,-32(r1) .globl _savegpr0_29 _savegpr0_29: std r29,-24(r1) .globl _savegpr0_30 _savegpr0_30: std r30,-16(r1) .globl _savegpr0_31 _savegpr0_31: std r31,-8(r1) std r0,16(r1) blr .globl _restgpr0_14 _restgpr0_14: ld r14,-144(r1) .globl _restgpr0_15 _restgpr0_15: ld r15,-136(r1) .globl _restgpr0_16 _restgpr0_16: ld r16,-128(r1) .globl _restgpr0_17 _restgpr0_17: ld r17,-120(r1) .globl _restgpr0_18 _restgpr0_18: ld r18,-112(r1) .globl _restgpr0_19 _restgpr0_19: ld r19,-104(r1) .globl _restgpr0_20 _restgpr0_20: ld r20,-96(r1) .globl _restgpr0_21 _restgpr0_21: ld r21,-88(r1) .globl _restgpr0_22 _restgpr0_22: ld r22,-80(r1) .globl _restgpr0_23 _restgpr0_23: ld r23,-72(r1) .globl _restgpr0_24 _restgpr0_24: ld r24,-64(r1) .globl _restgpr0_25 _restgpr0_25: ld r25,-56(r1) .globl _restgpr0_26 _restgpr0_26: ld r26,-48(r1) .globl _restgpr0_27 _restgpr0_27: ld r27,-40(r1) .globl _restgpr0_28 _restgpr0_28: ld r28,-32(r1) .globl _restgpr0_29 _restgpr0_29: ld r0,16(r1) ld r29,-24(r1) mtlr r0 ld r30,-16(r1) ld r31,-8(r1) blr .globl _restgpr0_30 _restgpr0_30: ld r30,-16(r1) .globl _restgpr0_31 _restgpr0_31: ld r0,16(r1) ld r31,-8(r1) mtlr r0 blr kexec-tools-2.0.10/purgatory/arch/ppc64/hvCall.h0000644001567400156740000000017511642166046020415 0ustar hormshorms#ifndef HVCALL_H #define HVCALL_H #define H_PUT_TERM_CHAR 0x58 long plpar_hcall_norets(unsigned long opcode, ...); #endif kexec-tools-2.0.10/purgatory/arch/ppc64/ppc64_asm.h0000644001567400156740000000056712417126536021006 0ustar hormshorms/* * ppc64_asm.h - common defines for PPC64 assembly parts * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ /* * ABIv1 requires dot symbol while ABIv2 does not. */ #if defined(_CALL_ELF) && _CALL_ELF == 2 #define DOTSYM(a) a #else #define GLUE(a,b) a##b #define DOTSYM(a) GLUE(.,a) #endif kexec-tools-2.0.10/purgatory/arch/ppc64/purgatory-ppc64.h0000644001567400156740000000017111424244110022151 0ustar hormshorms#ifndef PURGATORY_PPC64_H #define PURGATORY_PPC64_H void crashdump_backup_memory(void); #endif /* PURGATORY_PPC64_H */ kexec-tools-2.0.10/purgatory/arch/s390/Makefile0000644001567400156740000000040212520334015020213 0ustar hormshorms# # Purgatory s390 # s390_PURGATORY_SRCS += purgatory/arch/s390/console-s390.c s390_PURGATORY_SRCS += purgatory/arch/s390/setup-s390.S s390_PURGATORY_SRCS += purgatory/arch/s390/purgatory-s390.c dist += purgatory/arch/s390/Makefile $(s390_PURGATORY_SRCS) kexec-tools-2.0.10/purgatory/arch/s390/console-s390.c0000644001567400156740000000034311642166046021074 0ustar hormshorms/* * S390 console code (currently not implemented) * * Copyright IBM Corp. 2011 * * Author(s): Michael Holzheu */ #include #include "unused.h" void putchar(int UNUSED(ch)) { } kexec-tools-2.0.10/purgatory/arch/s390/setup-s390.S0000644001567400156740000000125012242534555020551 0ustar hormshorms/* * Purgatory setup code * * Copyright IBM Corp. 2011 * * Author(s): Michael Holzheu */ .text .globl purgatory_start .balign 16 purgatory_start: #ifdef __s390x__ larl %r5,gprs_save_area stmg %r6,%r15,0(%r5) larl %r15,lstack_end aghi %r15,-160 cghi %r2,0 je verify_checksums brasl %r14,purgatory larl %r14,kdump_psw lpswe 0(%r14) verify_checksums: brasl %r14,verify_sha256_digest larl %r5,gprs_save_area lmg %r6,%r15,0(%r5) br %r14 .section ".data" .balign 16 kdump_psw: .quad 0x0000000180000000 .quad 0x0000000000010010 .bss gprs_save_area: .fill 80 .balign 4096 lstack: .skip 4096 lstack_end: #else 0: j 0 #endif kexec-tools-2.0.10/purgatory/arch/s390/purgatory-s390.c0000644001567400156740000000465411642166046021477 0ustar hormshorms/* * S390 purgatory * * Copyright IBM Corp. 2011 * * Author(s): Michael Holzheu */ #include #include #include #include "../../../kexec/kexec-sha256.h" #define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y)) extern struct sha256_region sha256_regions[SHA256_REGIONS]; unsigned long crash_base = (unsigned long) -1; unsigned long crash_size = (unsigned long) -1; /* * Implement memcpy using the mvcle instruction */ static void memcpy_fast(void *target, void *src, unsigned long size) { register unsigned long __target asm("2") = (unsigned long) target; register unsigned long __size1 asm("3") = size; register unsigned long __src asm("4") = (unsigned long) src; register unsigned long __size2 asm("5") = size; asm volatile ( "0: mvcle %0,%2,0\n" " jo 0b\n" : "+d" (__target), "+d" (__size1), "+d" (__src), "+d" (__size2) : : "cc", "memory" ); } /* * Swap memory areas */ static void memswap(void *addr1, void *addr2, unsigned long size) { unsigned long off, copy_len; static char buf[1024]; for (off = 0; off < size; off += sizeof(buf)) { copy_len = MIN(size - off, sizeof(buf)); memcpy_fast(buf, (void *) addr2 + off, copy_len); memcpy_fast(addr2 + off, addr1 + off, copy_len); memcpy_fast(addr1 + off, buf, copy_len); } } /* * Nothing to do */ void setup_arch(void) { } /* * Do swap of [crash base - crash base + size] with [0 - crash size] * * We swap all kexec segments except of purgatory. The rest is copied * from [0 - crash size] to [crash base - crash base + size]. * We use [0x2000 - 0x10000] for purgatory. This area is never used * by s390 Linux kernels. * * This functions assumes that the sha256_regions[] is sorted. */ void post_verification_setup_arch(void) { unsigned long start, len, last = crash_base + 0x10000; struct sha256_region *ptr, *end; end = &sha256_regions[sizeof(sha256_regions)/sizeof(sha256_regions[0])]; for (ptr = sha256_regions; ptr < end; ptr++) { if (!ptr->start) continue; start = MAX(ptr->start, crash_base + 0x10000); len = ptr->len - (start - ptr->start); memcpy_fast((void *) last, (void *) last - crash_base, start - last); memswap((void *) start - crash_base, (void *) start, len); last = start + len; } memcpy_fast((void *) last, (void *) last - crash_base, crash_base + crash_size - last); memcpy_fast((void *) crash_base, (void *) 0, 0x2000); } kexec-tools-2.0.10/purgatory/arch/sh/Makefile0000644001567400156740000000014211424244110020126 0ustar hormshorms# # Purgatory sh # sh_PURGATORY_SRCS = dist += purgatory/arch/sh/Makefile $(sh_PURGATORY_SRCS) kexec-tools-2.0.10/purgatory/arch/x86_64/Makefile0000644001567400156740000000210012520551445020460 0ustar hormshorms# # Purgatory x86_64 # x86_64_PURGATORY_SRCS_native = purgatory/arch/x86_64/entry64-32.S x86_64_PURGATORY_SRCS_native += purgatory/arch/x86_64/entry64.S x86_64_PURGATORY_SRCS_native += purgatory/arch/x86_64/setup-x86_64.S x86_64_PURGATORY_SRCS_native += purgatory/arch/x86_64/stack.S x86_64_PURGATORY_SRCS_native += purgatory/arch/x86_64/purgatory-x86_64.c x86_64_PURGATORY_SRCS += $(x86_64_PURGATORY_SRCS_native) dist += purgatory/arch/x86_64/Makefile $(x86_64_PURGATORY_SRCS_native) \ purgatory/arch/x86_64/include/arch/io.h \ purgatory/arch/x86_64/include/arch/debug.h \ purgatory/arch/x86_64/purgatory-x86_64.h # Don't add sources in i386/ to dist, as i386/Makefile adds them x86_64_PURGATORY_SRCS += purgatory/arch/i386/entry32-16.S x86_64_PURGATORY_SRCS += purgatory/arch/i386/entry32-16-debug.S x86_64_PURGATORY_SRCS += purgatory/arch/i386/crashdump_backup.c x86_64_PURGATORY_SRCS += purgatory/arch/i386/console-x86.c x86_64_PURGATORY_SRCS += purgatory/arch/i386/vga.c x86_64_PURGATORY_SRCS += purgatory/arch/i386/pic.c x86_64_PURGATORY_EXTRA_CFLAGS = -mcmodel=large kexec-tools-2.0.10/purgatory/arch/x86_64/entry64-32.S0000644001567400156740000000000012242534555031442 1kexec-tools-2.0.10/purgatory/arch/x86_64/entry64-32.Sustar hormshormskexec-tools-2.0.10/purgatory/arch/x86_64/entry64.S0000644001567400156740000000000012242534555030776 1kexec-tools-2.0.10/purgatory/arch/x86_64/entry64.Sustar hormshormskexec-tools-2.0.10/purgatory/arch/x86_64/setup-x86_64.S0000644001567400156740000000000012242534555032340 1kexec-tools-2.0.10/purgatory/arch/x86_64/setup-x86_64.Sustar hormshormskexec-tools-2.0.10/purgatory/arch/x86_64/stack.S0000644001567400156740000000000011424244110030344 1kexec-tools-2.0.10/purgatory/arch/x86_64/stack.Sustar hormshormskexec-tools-2.0.10/purgatory/arch/x86_64/purgatory-x86_64.c0000644001567400156740000000000011642166046034167 1kexec-tools-2.0.10/purgatory/arch/x86_64/purgatory-x86_64.custar hormshormskexec-tools-2.0.10/purgatory/arch/x86_64/include/arch/io.h0000644001567400156740000000022111424244110022130 0ustar hormshorms#ifndef ARCH_X86_64_IO_H #define ARCH_X86_64_IO_H #include #include "../../../i386/include/arch/io.h" #endif /* ARCH_X86_64_IO_H */ kexec-tools-2.0.10/purgatory/arch/x86_64/include/arch/debug.h0000644001567400156740000001326111424244110022617 0ustar hormshorms/* 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_CHAR(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') kexec-tools-2.0.10/purgatory/arch/x86_64/purgatory-x86_64.h0000644001567400156740000000017111424244110022155 0ustar hormshorms#ifndef PURGATORY_X86_64_H #define PURGATORY_X86_64_H #include "../i386/purgatory-x86.h" #endif /* PURGATORY_X86_64_H */ kexec-tools-2.0.10/kexec/Makefile0000644001567400156740000000637712417126536015700 0ustar hormshorms# # kexec (linux booting linux) # PURGATORY_HEX_C = kexec/purgatory.c $(PURGATORY_HEX_C): $(PURGATORY) $(BIN_TO_HEX) $(MKDIR) -p $(@D) $(BIN_TO_HEX) purgatory < $(PURGATORY) > $@ KEXEC_SRCS = $(KEXEC_SRCS_base) KEXEC_GENERATED_SRCS = KEXEC_SRCS_base += kexec/kexec.c KEXEC_SRCS_base += kexec/ifdown.c KEXEC_SRCS_base += kexec/kexec-elf.c KEXEC_SRCS_base += kexec/kexec-elf-exec.c KEXEC_SRCS_base += kexec/kexec-elf-core.c KEXEC_SRCS_base += kexec/kexec-elf-rel.c KEXEC_SRCS_base += kexec/kexec-elf-boot.c KEXEC_SRCS_base += kexec/kexec-iomem.c KEXEC_SRCS_base += kexec/firmware_memmap.c KEXEC_SRCS_base += kexec/crashdump.c KEXEC_SRCS_base += kexec/crashdump-xen.c KEXEC_SRCS_base += kexec/phys_arch.c KEXEC_SRCS_base += kexec/kernel_version.c KEXEC_SRCS_base += kexec/lzma.c KEXEC_SRCS_base += kexec/zlib.c KEXEC_SRCS_base += kexec/kexec-xen.c KEXEC_GENERATED_SRCS += $(PURGATORY_HEX_C) dist += kexec/Makefile \ $(KEXEC_SRCS_base) kexec/crashdump-elf.c \ kexec/crashdump.h kexec/firmware_memmap.h \ kexec/kexec-elf-boot.h \ kexec/kexec-elf.h kexec/kexec-sha256.h \ kexec/kexec-zlib.h kexec/kexec-lzma.h \ kexec/kexec-syscall.h kexec/kexec.h kexec/kexec.8 dist += kexec/proc_iomem.c $(ARCH)_PROC_IOMEM = kexec/proc_iomem.c KEXEC_SRCS += $($(ARCH)_PROC_IOMEM) dist += kexec/virt_to_phys.c $(ARCH)_VIRT_TO_PHYS = kexec/virt_to_phys.c KEXEC_SRCS += $($(ARCH)_VIRT_TO_PHYS) dist += kexec/phys_to_virt.c $(ARCH)_PHYS_TO_VIRT = kexec/phys_to_virt.c KEXEC_SRCS += $($(ARCH)_PHYS_TO_VIRT) dist += kexec/add_segment.c $(ARCH)_ADD_SEGMENT = kexec/add_segment.c KEXEC_SRCS += $($(ARCH)_ADD_SEGMENT) dist += kexec/add_buffer.c $(ARCH)_ADD_BUFFER = kexec/add_buffer.c KEXEC_SRCS += $($(ARCH)_ADD_BUFFER) dist += kexec/arch_reuse_initrd.c $(ARCH)_ARCH_REUSE_INITRD = kexec/arch_reuse_initrd.c KEXEC_SRCS += $($(ARCH)_ARCH_REUSE_INITRD) dist += kexec/kexec-uImage.c $(ARCH)_UIMAGE = KEXEC_SRCS += $($(ARCH)_UIMAGE) dist += kexec/fs2dt.c kexec/fs2dt.h $(ARCH)_FS2DT = KEXEC_SRCS += $($(ARCH)_FS2DT) include $(srcdir)/kexec/arch/alpha/Makefile include $(srcdir)/kexec/arch/arm/Makefile include $(srcdir)/kexec/arch/i386/Makefile include $(srcdir)/kexec/arch/ia64/Makefile include $(srcdir)/kexec/arch/m68k/Makefile include $(srcdir)/kexec/arch/mips/Makefile include $(srcdir)/kexec/arch/cris/Makefile include $(srcdir)/kexec/arch/ppc/Makefile include $(srcdir)/kexec/arch/ppc64/Makefile include $(srcdir)/kexec/arch/s390/Makefile include $(srcdir)/kexec/arch/sh/Makefile include $(srcdir)/kexec/arch/x86_64/Makefile KEXEC_SRCS += $($(ARCH)_KEXEC_SRCS) KEXEC_OBJS = $(call objify, $(KEXEC_SRCS) $(KEXEC_GENERATED_SRCS)) KEXEC_DEPS = $(call depify, $(KEXEC_OBJS)) clean += $(KEXEC_OBJS) $(KEXEC_DEPS) $(KEXEC_GENERATED_SRCS) \ $(KEXEC) $(KEXEC_MANPAGE) KEXEC = $(SBINDIR)/kexec KEXEC_MANPAGE = $(MANDIR)/man8/kexec.8 -include $(KEXEC_DEPS) $(KEXEC): $(KEXEC_OBJS) $(UTIL_LIB) @$(MKDIR) -p $(@D) $(LINK.o) -o $@ $^ $(CFLAGS) $(LIBS) $(KEXEC): CPPFLAGS+=-I$(srcdir)/kexec/arch/$(ARCH)/include kexec/fs2dt.o: CPPFLAGS+=$($(ARCH)_FS2DT_INCLUDE) $(KEXEC_MANPAGE): kexec/kexec.8 @$(MKDIR) -p $(MANDIR)/man8 cp $^ $(KEXEC_MANPAGE) echo:: @echo "KEXEC_SRCS $(KEXEC_SRCS)" @echo "KEXEC_DEPS $(KEXEC_DEPS)" @echo "KEXEC_OBJS $(KEXEC_OBJS)" kexec-tools-2.0.10/kexec/kexec.c0000644001567400156740000010236512513334672015474 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) 2003-2005 Eric Biederman (ebiederm@xmission.com) * * Modified (2007-05-15) by Francesco Chiechi to rudely handle mips platform * * 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 #include #include #include #include #include #include #include #include #include #include #ifndef _O_BINARY #define _O_BINARY 0 #endif #include #include #include "config.h" #include #include "kexec.h" #include "kexec-syscall.h" #include "kexec-elf.h" #include "kexec-sha256.h" #include "kexec-zlib.h" #include "kexec-lzma.h" #include unsigned long long mem_min = 0; unsigned long long mem_max = ULONG_MAX; static unsigned long kexec_flags = 0; /* Flags for kexec file (fd) based syscall */ static unsigned long kexec_file_flags = 0; int kexec_debug = 0; void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr) { int i; dbgprintf("%s\n", prefix); for (i = 0; i < nr_mr; i++) { dbgprintf("%016llx-%016llx (%d)\n", mr[i].start, mr[i].end, mr[i].type); } } void die(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fflush(stdout); fflush(stderr); exit(1); } static char *xstrdup(const char *str) { char *new = strdup(str); if (!new) die("Cannot strdup \"%s\": %s\n", str, strerror(errno)); return new; } void *xmalloc(size_t size) { void *buf; if (!size) return NULL; 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; } int valid_memory_range(struct kexec_info *info, 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 < info->memory_ranges; i++) { unsigned long mstart, mend; /* Only consider memory ranges */ if (info->memory_range[i].type != RANGE_RAM) continue; mstart = info->memory_range[i].start; mend = info->memory_range[i].end; if (i < info->memory_ranges - 1 && mend == info->memory_range[i+1].start && info->memory_range[i+1].type == RANGE_RAM) mend = info->memory_range[i+1].end; /* Check to see if we are fully contained */ if ((mstart <= sstart) && (mend >= send)) { return 1; } } return 0; } static int valid_memory_segment(struct kexec_info *info, struct kexec_segment *segment) { unsigned long sstart, send; sstart = (unsigned long)segment->mem; send = sstart + segment->memsz - 1; return valid_memory_range(info, 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 = 0x%zx\n", i, info->segment[i].bufsz); fprintf(f, "segment[%d].mem = %p\n", i, info->segment[i].mem); fprintf(f, "segment[%d].memsz = 0x%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 initial invalid value for the hole base */ hole_base = ULONG_MAX; /* Align everything to at least a page size boundary */ if (hole_align < (unsigned long)getpagesize()) { hole_align = getpagesize(); } /* Compute the free memory ranges */ max_mem_ranges = info->memory_ranges + info->nr_segments; mem_range = xmalloc(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 < info->memory_ranges; i++) { unsigned long long sstart, send; unsigned long long mstart, mend; mstart = info->memory_range[i].start; mend = info->memory_range[i].end; if (info->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 = _ALIGN(start, hole_align); 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 (!hole_size || size >= hole_size - 1) { if (hole_end > 0) { hole_base = start; break; } else { hole_base = _ALIGN_DOWN(end - hole_size + 1, hole_align); } } } free(mem_range); if (hole_base == ULONG_MAX) { fprintf(stderr, "Could not find a free area of memory of " "0x%lx bytes...\n", hole_size); return ULONG_MAX; } if (hole_size && (hole_base + hole_size - 1) > hole_max) { fprintf(stderr, "Could not find a free area of memory below: " "0x%lx...\n", hole_max); return ULONG_MAX; } return hole_base; } void add_segment_phys_virt(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz, int phys) { 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 = _ALIGN(memsz, pagesize); /* 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: 0x%lx is not page aligned\n", base); } if (phys) base = virt_to_phys(base); last = base + memsz -1; if (!valid_memory_range(info, 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_phys_virt(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, int phys) { unsigned long base; int result; int pagesize; result = sort_segments(info); if (result < 0) { die("sort_segments failed\n"); } /* Round memsz up to a multiple of pagesize */ pagesize = getpagesize(); memsz = _ALIGN(memsz, pagesize); base = locate_hole(info, memsz, buf_align, buf_min, buf_max, buf_end); if (base == ULONG_MAX) { die("locate_hole failed\n"); } add_segment_phys_virt(info, buf, bufsz, base, memsz, phys); return base; } unsigned long add_buffer_virt(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) { return add_buffer_phys_virt(info, buf, bufsz, memsz, buf_align, buf_min, buf_max, buf_end, 0); } static int find_memory_range(struct kexec_info *info, unsigned long *base, unsigned long *size) { int i; unsigned long start, end; for (i = 0; i < info->memory_ranges; i++) { if (info->memory_range[i].type != RANGE_RAM) continue; start = info->memory_range[i].start; end = info->memory_range[i].end; if (end > *base && start < *base + *size) { if (start > *base) { *size = *base + *size - start; *base = start; } if (end < *base + *size) *size = end - *base; return 1; } } return 0; } static int find_segment_hole(struct kexec_info *info, unsigned long *base, unsigned long *size) { int i; unsigned long seg_base, seg_size; for (i = 0; i < info->nr_segments; i++) { seg_base = (unsigned long)info->segment[i].mem; seg_size = info->segment[i].memsz; if (seg_base + seg_size <= *base) continue; else if (seg_base >= *base + *size) break; else if (*base < seg_base) { *size = seg_base - *base; break; } else if (seg_base + seg_size < *base + *size) { *size = *base + *size - (seg_base + seg_size); *base = seg_base + seg_size; } else { *size = 0; break; } } return *size; } static int add_backup_segments(struct kexec_info *info, unsigned long backup_base, unsigned long backup_size) { unsigned long mem_base, mem_size, bkseg_base, bkseg_size, start, end; unsigned long pagesize; pagesize = getpagesize(); while (backup_size) { mem_base = backup_base; mem_size = backup_size; if (!find_memory_range(info, &mem_base, &mem_size)) break; backup_size = backup_base + backup_size - \ (mem_base + mem_size); backup_base = mem_base + mem_size; while (mem_size) { bkseg_base = mem_base; bkseg_size = mem_size; if (sort_segments(info) < 0) return -1; if (!find_segment_hole(info, &bkseg_base, &bkseg_size)) break; start = _ALIGN(bkseg_base, pagesize); end = _ALIGN_DOWN(bkseg_base + bkseg_size, pagesize); add_segment_phys_virt(info, NULL, 0, start, end-start, 0); mem_size = mem_base + mem_size - \ (bkseg_base + bkseg_size); mem_base = bkseg_base + bkseg_size; } } return 0; } static char *slurp_fd(int fd, const char *filename, off_t size, off_t *nread) { char *buf; off_t progress; ssize_t result; buf = xmalloc(size); progress = 0; while (progress < size) { result = read(fd, buf + progress, size - progress); if (result < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; fprintf(stderr, "Read on %s failed: %s\n", filename, strerror(errno)); free(buf); close(fd); return NULL; } if (result == 0) /* EOF */ break; progress += result; } result = close(fd); if (result < 0) die("Close of %s failed: %s\n", filename, strerror(errno)); if (nread) *nread = progress; return buf; } char *slurp_file(const char *filename, off_t *r_size) { int fd; char *buf; off_t size, err, nread; ssize_t result; struct stat stats; if (!filename) { *r_size = 0; return 0; } fd = open(filename, O_RDONLY | _O_BINARY); 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)); } /* * Seek in case the kernel is a character node like /dev/ubi0_0. * This does not work on regular files which live in /proc and * we need this for some /proc/device-tree entries */ if (S_ISCHR(stats.st_mode)) { size = lseek(fd, 0, SEEK_END); if (size < 0) die("Can not seek file %s: %s\n", filename, strerror(errno)); err = lseek(fd, 0, SEEK_SET); if (err < 0) die("Can not seek to the begin of file %s: %s\n", filename, strerror(errno)); } else { size = stats.st_size; } buf = slurp_fd(fd, filename, size, &nread); if (!buf) die("Cannot read %s", filename); if (nread != size) die("Read on %s ended before stat said it should\n", filename); *r_size = size; return buf; } /* This functions reads either specified number of bytes from the file or lesser if EOF is met. */ char *slurp_file_len(const char *filename, off_t size, off_t *nread) { int fd; if (!filename) return 0; fd = open(filename, O_RDONLY | _O_BINARY); if (fd < 0) { fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); return 0; } return slurp_fd(fd, filename, size, nread); } char *slurp_decompress_file(const char *filename, off_t *r_size) { char *kernel_buf; kernel_buf = zlib_decompress_file(filename, r_size); if (!kernel_buf) { kernel_buf = lzma_decompress_file(filename, r_size); if (!kernel_buf) return slurp_file(filename, r_size); } return kernel_buf; } 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 = (unsigned long) 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, void *entry) { char *kernel; char *kernel_buf; off_t kernel_size; int i = 0; int result; struct kexec_info info; long native_arch; int guess_only = 0; memset(&info, 0, sizeof(info)); info.kexec_flags = kexec_flags; 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); dbgprintf("kernel: %p kernel_size: 0x%lx\n", kernel_buf, kernel_size); if (get_memory_ranges(&info.memory_range, &info.memory_ranges, info.kexec_flags) < 0 || info.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; } } } /* Figure out our native architecture before load */ native_arch = physical_arch(); if (native_arch < 0) { return -1; } info.kexec_flags |= native_arch; result = file_type[i].load(argc, argv, kernel_buf, kernel_size, &info); if (result < 0) { switch (result) { case ENOCRASHKERNEL: fprintf(stderr, "No crash kernel segment found in /proc/iomem\n" "Please check the crashkernel= boot parameter.\n"); break; case EFAILED: default: fprintf(stderr, "Cannot load %s\n", kernel); break; } return result; } /* If we are not in native mode setup an appropriate trampoline */ if (arch_compat_trampoline(&info) < 0) { return -1; } if (info.kexec_flags & KEXEC_PRESERVE_CONTEXT) { add_backup_segments(&info, mem_min, mem_max - mem_min + 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, 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 (entry) info.entry = entry; dbgprintf("kexec_load: entry = %p flags = 0x%lx\n", info.entry, info.kexec_flags); if (kexec_debug) print_segments(stderr, &info); if (xen_present()) result = xen_kexec_load(&info); else result = kexec_load(info.entry, info.nr_segments, info.segment, info.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 = 0x%lx\n", info.entry, info.kexec_flags); print_segments(stderr, &info); } return result; } static int kexec_file_unload(unsigned long kexec_file_flags) { int ret = 0; ret = kexec_file_load(-1, -1, 0, NULL, kexec_file_flags); if (ret != 0) { /* The unload failed, print some debugging information */ fprintf(stderr, "kexec_file_load(unload) failed\n: %s\n", strerror(errno)); } return ret; } static int k_unload (unsigned long kexec_flags) { int result; long native_arch; /* set the arch */ native_arch = physical_arch(); if (native_arch < 0) { return -1; } kexec_flags |= native_arch; if (xen_present()) result = xen_kexec_unload(kexec_flags); else result = kexec_load(NULL, 0, NULL, kexec_flags); if (result != 0) { /* The unload failed, print some debugging information */ fprintf(stderr, "kexec unload failed: %s\n", strerror(errno)); } return result; } /* * Start a reboot. */ static int my_shutdown(void) { char *args[] = { "shutdown", "-r", "now", 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) { if (xen_present()) xen_kexec_exec(); else reboot(LINUX_REBOOT_CMD_KEXEC); /* I have failed if I make it here */ fprintf(stderr, "kexec failed: %s\n", strerror(errno)); return -1; } static int kexec_loaded(void); static int load_jump_back_helper_image(unsigned long kexec_flags, void *entry) { int result; struct kexec_segment seg; memset(&seg, 0, sizeof(seg)); result = kexec_load(entry, 1, &seg, kexec_flags); return result; } /* * Jump back to the original kernel */ static int my_load_jump_back_helper(unsigned long kexec_flags, void *entry) { int result; if (kexec_loaded()) { fprintf(stderr, "There is kexec kernel loaded, make sure " "you are in kexeced kernel.\n"); return -1; } if (!entry) { fprintf(stderr, "Please specify jump back entry " "in command line\n"); return -1; } result = load_jump_back_helper_image(kexec_flags, entry); if (result) { fprintf(stderr, "load jump back kernel failed: %s\n", strerror(errno)); return result; } return result; } static void version(void) { printf(PACKAGE_STRING " released " PACKAGE_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,\n" " don't call shutdown.\n" " -x, --no-ifdown Don't bring down network interfaces.\n" " -y, --no-sync Don't sync filesystems before kexec.\n" " -l, --load Load the new kernel into the\n" " current kernel.\n" " -p, --load-panic Load the new kernel for use on panic.\n" " -u, --unload Unload the current kexec target kernel.\n" " If capture kernel is being unloaded\n" " specify -p with -u.\n" " -e, --exec Execute a currently loaded kernel.\n" " -t, --type=TYPE Specify the new kernel is of this type.\n" " --mem-min= Specify the lowest memory address to\n" " load code into.\n" " --mem-max= Specify the highest memory address to\n" " load code into.\n" " --reuseinitrd Reuse initrd from first boot.\n" " --load-preserve-context Load the new kernel and preserve\n" " context of current kernel during kexec.\n" " --load-jump-back-helper Load a helper image to jump back\n" " to original kernel.\n" " --entry= Specify jump back address.\n" " (0 means it's not jump back or\n" " preserve context)\n" " to original kernel.\n" " -s, --kexec-file-syscall Use file based syscall for kexec operation\n" " -d, --debug Enable debugging to help spot a failure.\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"); } static int kexec_loaded(void) { long ret = -1; FILE *fp; char *p; char line[3]; /* No way to tell if an image is loaded under Xen, assume it is. */ if (xen_present()) return 1; fp = fopen("/sys/kernel/kexec_loaded", "r"); if (fp == NULL) return -1; p = fgets(line, sizeof(line), fp); fclose(fp); if (p == NULL) return -1; ret = strtol(line, &p, 10); /* Too long */ if (ret > INT_MAX) return -1; /* No digits were found */ if (p == line) return -1; return (int)ret; } /* * Remove parameter from a kernel command line. Helper function by get_command_line(). */ static void remove_parameter(char *line, const char *param_name) { char *start, *end; start = strstr(line, param_name); /* parameter not found */ if (!start) return; /* * check if that's really the start of a parameter and not in * the middle of the word */ if (start != line && !isspace(*(start-1))) return; end = strstr(start, " "); if (!end) *start = 0; else { memmove(start, end+1, strlen(end)); *(end + strlen(end)) = 0; } } /* * Returns the contents of the current command line to be used with * --reuse-cmdline option. The function gets called from architecture specific * code. If we load a panic kernel, that function will strip the * "crashkernel=" option because it does not make sense that the crashkernel * reserves memory for a crashkernel (well, it would not boot since the * amount is exactly the same as the crashkernel has overall memory). Also, * remove the BOOT_IMAGE from lilo (and others) since that doesn't make * sense here any more. The kernel could be different even if we reuse the * commandline. * * The function returns dynamically allocated memory. */ char *get_command_line(void) { FILE *fp; char *line; const int sizeof_line = 2048; line = malloc(sizeof_line); if (line == NULL) die("Could not allocate memory to read /proc/cmdline."); fp = fopen("/proc/cmdline", "r"); if (!fp) die("Could not open /proc/cmdline."); if (fgets(line, sizeof_line, fp) == NULL) die("Can't read /proc/cmdline."); fclose(fp); /* strip newline */ line[strlen(line) - 1] = '\0'; remove_parameter(line, "BOOT_IMAGE"); if (kexec_flags & KEXEC_ON_CRASH) remove_parameter(line, "crashkernel"); return line; } /* check we retained the initrd */ static void check_reuse_initrd(void) { char *str = NULL; char *line = get_command_line(); str = strstr(line, "retain_initrd"); free(line); if (str == NULL) die("unrecoverable error: current boot didn't " "retain the initrd for reuse.\n"); } char *concat_cmdline(const char *base, const char *append) { char *cmdline; if (!base && !append) return NULL; if (append && !base) return xstrdup(append); if (base && !append) return xstrdup(base); cmdline = xmalloc(strlen(base) + 1 + strlen(append) + 1); strcpy(cmdline, base); strcat(cmdline, " "); strcat(cmdline, append); return cmdline; } /* New file based kexec system call related code */ static int do_kexec_file_load(int fileind, int argc, char **argv, unsigned long flags) { char *kernel; int kernel_fd, i; struct kexec_info info; int ret = 0; char *kernel_buf; off_t kernel_size; memset(&info, 0, sizeof(info)); info.segment = NULL; info.nr_segments = 0; info.entry = NULL; info.backup_start = 0; info.kexec_flags = flags; info.file_mode = 1; info.initrd_fd = -1; if (!is_kexec_file_load_implemented()) { fprintf(stderr, "syscall kexec_file_load not available.\n"); return -1; } if (argc - fileind <= 0) { fprintf(stderr, "No kernel specified\n"); usage(); return -1; } kernel = argv[fileind]; kernel_fd = open(kernel, O_RDONLY); if (kernel_fd == -1) { fprintf(stderr, "Failed to open file %s:%s\n", kernel, strerror(errno)); return -1; } /* slurp in the input kernel */ kernel_buf = slurp_decompress_file(kernel, &kernel_size); 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; } ret = file_type[i].load(argc, argv, kernel_buf, kernel_size, &info); if (ret < 0) { fprintf(stderr, "Cannot load %s\n", kernel); return ret; } /* * If there is no initramfs, set KEXEC_FILE_NO_INITRAMFS flag so that * kernel does not return error with negative initrd_fd. */ if (info.initrd_fd == -1) info.kexec_flags |= KEXEC_FILE_NO_INITRAMFS; ret = kexec_file_load(kernel_fd, info.initrd_fd, info.command_line_len, info.command_line, info.kexec_flags); if (ret != 0) fprintf(stderr, "kexec_file_load failed: %s\n", strerror(errno)); return ret; } int main(int argc, char *argv[]) { int do_load = 1; int do_exec = 0; int do_load_jump_back_helper = 0; int do_shutdown = 1; int do_sync = 1, skip_sync = 0; int do_ifdown = 0, skip_ifdown = 0; int do_unload = 0; int do_reuse_initrd = 0; int do_kexec_file_syscall = 0; void *entry = 0; char *type = 0; char *endptr; int opt; int result = 0; int fileind; static const struct option options[] = { KEXEC_ALL_OPTIONS { 0, 0, 0, 0}, }; static const char short_options[] = KEXEC_ALL_OPT_STR; /* * First check if --use-kexec-file-syscall is set. That changes lot of * things */ while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { case OPT_KEXEC_FILE_SYSCALL: do_kexec_file_syscall = 1; break; } } /* Reset getopt for the next pass. */ opterr = 1; optind = 1; while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { case '?': usage(); return 1; case OPT_HELP: usage(); return 0; case OPT_VERSION: version(); return 0; case OPT_DEBUG: kexec_debug = 1; case OPT_NOIFDOWN: skip_ifdown = 1; break; case OPT_NOSYNC: skip_sync = 1; 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; if (do_kexec_file_syscall) kexec_file_flags |= KEXEC_FILE_UNLOAD; break; case OPT_EXEC: do_load = 0; do_shutdown = 0; do_sync = 1; do_ifdown = 1; do_exec = 1; break; case OPT_LOAD_JUMP_BACK_HELPER: do_load = 0; do_shutdown = 0; do_sync = 1; do_ifdown = 1; do_exec = 0; do_load_jump_back_helper = 1; kexec_flags = KEXEC_PRESERVE_CONTEXT; break; case OPT_ENTRY: entry = (void *)strtoul(optarg, &endptr, 0); if (*endptr) { fprintf(stderr, "Bad option value in --entry=%s\n", optarg); usage(); return 1; } break; case OPT_LOAD_PRESERVE_CONTEXT: do_load = 1; do_exec = 0; do_shutdown = 0; do_sync = 1; kexec_flags = KEXEC_PRESERVE_CONTEXT; break; case OPT_TYPE: type = optarg; break; case OPT_PANIC: do_load = 1; do_exec = 0; do_shutdown = 0; do_sync = 0; if (do_kexec_file_syscall) kexec_file_flags |= KEXEC_FILE_ON_CRASH; else 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; case OPT_REUSE_INITRD: do_reuse_initrd = 1; break; case OPT_KEXEC_FILE_SYSCALL: /* We already parsed it. Nothing to do. */ break; default: break; } } if (skip_ifdown) do_ifdown = 0; if (skip_sync) do_sync = 0; if (do_load && (kexec_flags & KEXEC_ON_CRASH) && !is_crashkernel_mem_reserved()) { die("Memory for crashkernel is not reserved\n" "Please reserve memory by passing" "\"crashkernel=X@Y\" parameter to kernel\n" "Then try to loading kdump kernel\n"); } if (do_load && (kexec_flags & KEXEC_PRESERVE_CONTEXT) && mem_max == ULONG_MAX) { die("Please specify memory range used by kexeced kernel\n" "to preserve the context of original kernel with \n" "\"--mem-max\" parameter\n"); } fileind = optind; /* Reset getopt for the next pass; called in other source modules */ opterr = 1; optind = 1; result = arch_process_options(argc, argv); /* Check for bogus options */ if (!do_load) { while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { if ((opt == '?') || (opt >= OPT_ARCH_MAX)) { usage(); return 1; } } } if (do_reuse_initrd){ check_reuse_initrd(); arch_reuse_initrd(); } if (do_unload) { if (do_kexec_file_syscall) result = kexec_file_unload(kexec_file_flags); else result = k_unload(kexec_flags); } if (do_load && (result == 0)) { if (do_kexec_file_syscall) result = do_kexec_file_load(fileind, argc, argv, kexec_file_flags); else result = my_load(type, fileind, argc, argv, kexec_flags, entry); } /* Don't shutdown unless there is something to reboot to! */ if ((result == 0) && (do_shutdown || do_exec) && !kexec_loaded()) { die("Nothing has been loaded!\n"); } if ((result == 0) && do_shutdown) { result = my_shutdown(); } if ((result == 0) && do_sync) { sync(); } if ((result == 0) && do_ifdown) { ifdown(); } if ((result == 0) && do_exec) { result = my_exec(); } if ((result == 0) && do_load_jump_back_helper) { result = my_load_jump_back_helper(kexec_flags, entry); } fflush(stdout); fflush(stderr); return result; } kexec-tools-2.0.10/kexec/ifdown.c0000644001567400156740000000311211642166046015651 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include /* * 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 if_nameindex *ifa, *ifp; struct ifreq ifr; int fd, shaper; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { fprintf(stderr, "ifdown: "); perror("socket"); return -1; } if ((ifa = if_nameindex()) == NULL) { fprintf(stderr, "ifdown: "); perror("if_nameindex"); return -1; } for (shaper = 1; shaper >= 0; shaper--) { for (ifp = ifa; ifp->if_index; ifp++) { if ((strncmp(ifp->if_name, "shaper", 6) == 0) != shaper) continue; if (strcmp(ifp->if_name, "lo") == 0) continue; if (strchr(ifp->if_name, ':') != NULL) continue; strncpy(ifr.ifr_name, ifp->if_name, IFNAMSIZ); if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { fprintf(stderr, "ifdown: shutdown "); perror(ifp->if_name); return -1; } ifr.ifr_flags &= ~(IFF_UP); if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { fprintf(stderr, "ifdown: shutdown "); perror(ifp->if_name); return -1; } } } close(fd); return 0; } kexec-tools-2.0.10/kexec/kexec-elf.c0000644001567400156740000005201112242534555016231 0ustar hormshorms#include #include #include #include #include #include #include "elf.h" #include #include "kexec.h" #include "kexec-elf.h" #include "crashdump.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 ((uintmax_t)len < (uintmax_t)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) > UINT32_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) > UINT32_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) > UINT32_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 ((uintmax_t)len < (uintmax_t)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) > UINT32_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) > UINT32_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) > UINT32_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 ((uintmax_t)len < (uintmax_t)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, 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) > UINT32_MAX) || (elf32_to_cpu(ehdr, lphdr.p_memsz) > UINT32_MAX) || (elf32_to_cpu(ehdr, lphdr.p_offset) > UINT32_MAX) || (elf32_to_cpu(ehdr, lphdr.p_paddr) > UINT32_MAX) || (elf32_to_cpu(ehdr, lphdr.p_vaddr) > UINT32_MAX) || (elf32_to_cpu(ehdr, lphdr.p_align) > UINT32_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, 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) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_memsz) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_offset) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_paddr) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_vaddr) > UINT64_MAX) || (elf64_to_cpu(ehdr, lphdr.p_align) > UINT64_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, uint32_t flags) { size_t phdr_size, mem_phdr_size, 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 ((uintmax_t)(ehdr->e_phoff + phdr_size) > (uintmax_t)len) { /* The program header did not fit in the file buffer */ if (probe_debug || (flags & ELF_SKIP_FILESZ_CHECK)) { fprintf(stderr, "ELF program headers truncated" " have %ju bytes need %ju bytes\n", (uintmax_t)len, (uintmax_t)(ehdr->e_phoff + phdr_size)); } 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, ehdr, i); } else if (ehdr->ei_class == ELFCLASS64) { result = build_mem_elf64_phdr(buf, ehdr, i); } if (result < 0) { return result; } /* Check the program headers to be certain * they are safe to use. * Skip the check if ELF_SKIP_FILESZ_CHECK is set. */ phdr = &ehdr->e_phdr[i]; if (!(flags & ELF_SKIP_FILESZ_CHECK) && (uintmax_t)(phdr->p_offset + phdr->p_filesz) > (uintmax_t)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, 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) > UINT32_MAX) || (elf32_to_cpu(ehdr, lshdr.sh_addr) > UINT32_MAX) || (elf32_to_cpu(ehdr, lshdr.sh_offset) > UINT32_MAX) || (elf32_to_cpu(ehdr, lshdr.sh_size) > UINT32_MAX) || (elf32_to_cpu(ehdr, lshdr.sh_addralign) > UINT32_MAX) || (elf32_to_cpu(ehdr, lshdr.sh_entsize) > UINT32_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: %lld\n", shdr->sh_type, shdr->sh_entsize); return -1; } return 0; } static int build_mem_elf64_shdr(const char *buf, 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) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_addr) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_offset) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_size) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_addralign) > UINT64_MAX) || (elf64_to_cpu(ehdr, lshdr.sh_entsize) > UINT64_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: %lld\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, uint32_t flags) { size_t shdr_size, mem_shdr_size, 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 ((uintmax_t)(ehdr->e_shoff + shdr_size) > (uintmax_t)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, ehdr, i); } else if (ehdr->ei_class == ELFCLASS64) { result = build_mem_elf64_shdr(buf, ehdr, i); } if (result < 0) { return result; } /* Check the section headers to be certain * they are safe to use. * Skip the check if ELF_SKIP_FILESZ_CHECK is set. */ shdr = &ehdr->e_shdr[i]; if (!(flags & ELF_SKIP_FILESZ_CHECK) && (shdr->sh_type != SHT_NOBITS) && (uintmax_t)(shdr->sh_offset + shdr->sh_size) > (uintmax_t)len) { /* The section does not fit in the buffer */ if (probe_debug) { fprintf(stderr, "ELF section %zd 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 = (unsigned char *)(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(struct mem_ehdr *ehdr) { const unsigned char *note_start, *note_end, *note; size_t note_size, 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]; /* * binutils <= 2.17 has a bug where it can create the * PT_NOTE segment with an offset of 0. Therefore * check p_offset > 0. * * See: http://sourceware.org/bugzilla/show_bug.cgi?id=594 */ if (phdr->p_type == PT_NOTE && phdr->p_offset) { note_start = (unsigned char *)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 += _ALIGN(hdr.n_namesz, 4); note_size += _ALIGN(hdr.n_descsz, 4); 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 += _ALIGN(hdr.n_namesz, 4); desc = note + note_size; note_size += _ALIGN(hdr.n_descsz, 4); if ((hdr.n_namesz != 0) && (name[hdr.n_namesz -1] != '\0')) { /* If note name string is not null terminated, just * warn user about it and continue processing. This * allows us to parse /proc/kcore on older kernels * where /proc/kcore elf notes were not null * terminated. It has been fixed in 2.6.19. */ fprintf(stderr, "Warning: Elf Note name is not null " "terminated\n"); } ehdr->e_note[i].n_type = hdr.n_type; ehdr->e_note[i].n_name = (char *)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, uint32_t flags) { 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, flags); 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, flags); if (result < 0) { free_elf_info(ehdr); return result; } } result = build_mem_notes(ehdr); if (result < 0) { free_elf_info(ehdr); return result; } return 0; } kexec-tools-2.0.10/kexec/kexec-elf-exec.c0000644001567400156740000000647111642166046017163 0ustar hormshorms#include #include #include #include #include #include #include "elf.h" #include #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, uint32_t flags) { struct mem_phdr *phdr, *end_phdr; int result; result = build_elf_info(buf, len, ehdr, flags); if (result < 0) { return result; } if ((ehdr->e_type != ET_EXEC) && (ehdr->e_type != ET_DYN) && (ehdr->e_type != ET_CORE)) { /* 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(struct mem_ehdr *ehdr, struct kexec_info *info) { unsigned long base; int result; size_t 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 (first > start) { first = start; } 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(info, 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); } /* Update entry point to reflect new load address*/ ehdr->e_entry += base; result = 0; out: return result; } void elf_exec_build_load(struct kexec_info *info, struct mem_ehdr *ehdr, const char *buf, off_t len, uint32_t flags) { int result; /* Parse the Elf file */ result = build_elf_exec_info(buf, len, ehdr, flags); 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"); } } kexec-tools-2.0.10/kexec/kexec-elf-core.c0000644001567400156740000000106111424244110017140 0ustar hormshorms#include #include #include #include #include "elf.h" #include "kexec-elf.h" int build_elf_core_info(const char *buf, off_t len, struct mem_ehdr *ehdr, uint32_t flags) { int result; result = build_elf_info(buf, len, ehdr, flags); if (result < 0) { return result; } if ((ehdr->e_type != ET_CORE)) { /* not an ELF Core */ fprintf(stderr, "Not ELF type ET_CORE\n"); return -1; } if (!ehdr->e_phdr) { /* No program header */ fprintf(stderr, "No ELF program header\n"); return -1; } return 0; } kexec-tools-2.0.10/kexec/kexec-elf-rel.c0000644001567400156740000003336012417126536017017 0ustar hormshorms#include #include #include #include #include #include #include "elf.h" #include #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 = { 0, 0, 0, 0, 0, 0 }; 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 = { 0, 0, 0, 0 }; 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 = { 0, 0, 0, 0 }; 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, uint32_t flags) { int result; result = build_elf_info(buf, len, ehdr, flags); 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 = _ALIGN(bufsz, align); /* 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 = _ALIGN(bsssz, align); /* 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 = _ALIGN(data_addr, align); /* 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 = _ALIGN(bss_addr, align); /* 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 = {0}; struct mem_sym sym; const void *location; const unsigned char *name; 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 (sym.st_name) { name = strtab + sym.st_name; } else { name = ehdr->e_shdr[ehdr->e_shstrndx].sh_data; name += ehdr->e_shdr[sym.st_shndx].sh_name; } dbgprintf("sym: %10s info: %02x other: %02x shndx: %x value: %llx size: %llx\n", name, sym.st_info, sym.st_other, sym.st_shndx, sym.st_value, sym.st_size); if (sym.st_shndx == STN_UNDEF) { /* * NOTE: ppc64 elf .ro shows up a UNDEF section. * From Elf 1.2 Spec: * Relocation Entries: If the index is STN_UNDEF, * the undefined symbol index, the relocation uses 0 * as the "symbol value". * TOC symbols appear as undefined but should be * resolved as well. Their type is STT_NOTYPE so allow * such symbols to be processed. */ if (ELF32_ST_TYPE(sym.st_info) != STT_NOTYPE) die("Undefined symbol: %s\n", name); } sec_base = 0; if (sym.st_shndx == SHN_COMMON) { die("symbol: '%s' in common section\n", 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, name); } else { sec_base = ehdr->e_shdr[sym.st_shndx].sh_addr; } value = sym.st_value; value += sec_base; value += rel.r_addend; dbgprintf("sym: %s value: %lx addr: %lx\n", name, value, address); 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, uint32_t flags) { int result; /* Parse the Elf file */ result = build_elf_rel_info(buf, len, ehdr, flags); 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 = (char *)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: %lld not %zd\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", name); } if (sym.st_size != size) { die("Symbol: %s has size: %lld not %zd\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); } kexec-tools-2.0.10/kexec/kexec-elf-boot.c0000644001567400156740000000455212242534555017201 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include "kexec.h" #include "kexec-elf.h" #include "kexec-elf-boot.h" #define UPSZ(X) _ALIGN_UP(sizeof(X), 4) 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, }, }; unsigned long elf_boot_notes( struct kexec_info *info, unsigned long max_addr, const 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; } kexec-tools-2.0.10/kexec/kexec-iomem.c0000644001567400156740000000375612417126536016605 0ustar hormshorms#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "kexec.h" #include "crashdump.h" /* * kexec_iomem_for_each_line() * * Iterate over each line in the file returned by proc_iomem(). If match is * NULL or if the line matches with our match-pattern then call the * callback if non-NULL. * * Return the number of lines matched. */ int kexec_iomem_for_each_line(char *match, int (*callback)(void *data, int nr, char *str, unsigned long long base, unsigned long long length), void *data) { const char *iomem = proc_iomem(); char line[MAX_LINE]; FILE *fp; unsigned long long start, end, size; char *str; int consumed; int count; int nr = 0; fp = fopen(iomem, "r"); if (!fp) die("Cannot open %s\n", iomem); while(fgets(line, sizeof(line), fp) != 0) { count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed); if (count != 2) continue; str = line + consumed; size = end - start + 1; if (!match || memcmp(str, match, strlen(match)) == 0) { if (callback && callback(data, nr, str, start, size) < 0) { break; } nr++; } } fclose(fp); return nr; } static int kexec_iomem_single_callback(void *data, int nr, char *UNUSED(str), unsigned long long base, unsigned long long length) { struct memory_range *range = data; if (nr == 0) { range->start = base; range->end = base + length - 1; } return 0; } int parse_iomem_single(char *str, uint64_t *start, uint64_t *end) { struct memory_range range; int ret; memset(&range, 0, sizeof(range)); ret = kexec_iomem_for_each_line(str, kexec_iomem_single_callback, &range); if (ret == 1) { if (start) *start = range.start; if (end) *end = range.end; ret = 0; } else ret = -1; return ret; } kexec-tools-2.0.10/kexec/firmware_memmap.c0000644001567400156740000001470612417126536017547 0ustar hormshorms/* * firmware_memmap.c: Read /sys/firmware/memmap * * Created by: Bernhard Walle (bernhard.walle@gmx.de) * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved * * 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 /* for ULLONG_MAX without C99 */ #include #include #include #include #include #include #include #include #include #include "firmware_memmap.h" #include "kexec.h" /* * If the system is too old for ULLONG_MAX or LLONG_MAX, define it here. */ #ifndef ULLONG_MAX # define ULLONG_MAX (~0ULL) #endif /* ULLONG_MAX */ #ifndef LLONG_MAX # define LLONG_MAX (~0ULL >> 1) #endif /* LLONG_MAX */ /** * The full path to the sysfs interface that provides the memory map. */ #define FIRMWARE_MEMMAP_DIR "/sys/firmware/memmap" /** * Parses a file that only contains one number. Typical for sysfs files. * * @param[in] filename the name of the file that should be parsed * @return the value that has been read or ULLONG_MAX on error. */ static unsigned long long parse_numeric_sysfs(const char *filename) { FILE *fp; char linebuffer[BUFSIZ]; unsigned long long retval = ULLONG_MAX; fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "Opening \"%s\" failed: %s\n", filename, strerror(errno)); return ULLONG_MAX; } if (!fgets(linebuffer, BUFSIZ, fp)) goto err; linebuffer[BUFSIZ-1] = 0; /* let strtoll() detect the base */ retval = strtoll(linebuffer, NULL, 0); err: fclose(fp); return retval; } /** * Reads the contents of a one-line sysfs file to buffer. (This function is * not threadsafe.) * * @param[in] filename the name of the file that should be read * * @return NULL on failure, a pointer to a static buffer (that should be copied * with strdup() if the caller plans to use it after next function call) */ static char *parse_string_sysfs(const char *filename) { FILE *fp; static char linebuffer[BUFSIZ]; char *end; fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "Opening \"%s\" failed: %s\n", filename, strerror(errno)); return NULL; } if (!fgets(linebuffer, BUFSIZ, fp)) { fclose(fp); return NULL; } linebuffer[BUFSIZ-1] = 0; /* truncate trailing newline(s) */ end = linebuffer + strlen(linebuffer) - 1; while (*end == '\n') *end-- = 0; fclose(fp); return linebuffer; } static int parse_memmap_entry(const char *entry, struct memory_range *range) { char filename[PATH_MAX]; char *type; /* * entry/start */ snprintf(filename, PATH_MAX, "%s/%s", entry, "start"); filename[PATH_MAX-1] = 0; range->start = parse_numeric_sysfs(filename); if (range->start == ULLONG_MAX) return -1; /* * entry/end */ snprintf(filename, PATH_MAX, "%s/%s", entry, "end"); filename[PATH_MAX-1] = 0; range->end = parse_numeric_sysfs(filename); if (range->end == ULLONG_MAX) return -1; /* * entry/type */ snprintf(filename, PATH_MAX, "%s/%s", entry, "type"); filename[PATH_MAX-1] = 0; type = parse_string_sysfs(filename); if (!type) return -1; if (strcmp(type, "System RAM") == 0) range->type = RANGE_RAM; else if (strcmp(type, "ACPI Tables") == 0) range->type = RANGE_ACPI; else if (strcmp(type, "Unusable memory") == 0) range->type = RANGE_RESERVED; else if (strcmp(type, "reserved") == 0) range->type = RANGE_RESERVED; else if (strcmp(type, "ACPI Non-volatile Storage") == 0) range->type = RANGE_ACPI_NVS; else if (strcmp(type, "Uncached RAM") == 0) range->type = RANGE_UNCACHED; else { fprintf(stderr, "Unknown type (%s) while parsing %s. Please " "report this as bug. Using RANGE_RESERVED now.\n", type, filename); range->type = RANGE_RESERVED; } return 0; } /* documentation: firmware_memmap.h */ int compare_ranges(const void *first, const void *second) { const struct memory_range *first_range = first; const struct memory_range *second_range = second; /* * don't use the "first_range->start - second_range->start" * notation because unsigned long long might overflow */ if (first_range->start > second_range->start) return 1; else if (first_range->start < second_range->start) return -1; else /* first_range->start == second_range->start */ return 0; } /* documentation: firmware_memmap.h */ int have_sys_firmware_memmap(void) { int ret; struct stat mystat; ret = stat(FIRMWARE_MEMMAP_DIR, &mystat); if (ret != 0) return 0; return S_ISDIR(mystat.st_mode); } /* documentation: firmware_memmap.h */ int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges) { DIR *firmware_memmap_dir = NULL; struct dirent *dirent; int i = 0; /* argument checking */ if (!range || !ranges) { fprintf(stderr, "%s: Invalid arguments.\n", __FUNCTION__); return -1; } /* open the directory */ firmware_memmap_dir = opendir(FIRMWARE_MEMMAP_DIR); if (!firmware_memmap_dir) { perror("Could not open \"" FIRMWARE_MEMMAP_DIR "\""); goto error; } /* parse the entries */ while ((dirent = readdir(firmware_memmap_dir)) != NULL) { int ret; char full_path[PATH_MAX]; /* array overflow check */ if ((size_t)i >= *ranges) { fprintf(stderr, "The firmware provides more entries " "allowed (%zd). Please report that as bug.\n", *ranges); goto error; } /* exclude '.' and '..' */ if (dirent->d_name[0] && dirent->d_name[0] == '.') { continue; } snprintf(full_path, PATH_MAX, "%s/%s", FIRMWARE_MEMMAP_DIR, dirent->d_name); full_path[PATH_MAX-1] = 0; ret = parse_memmap_entry(full_path, &range[i]); if (ret < 0) { goto error; } i++; } /* close the dir as we don't need it any more */ closedir(firmware_memmap_dir); /* update the number of ranges for the caller */ *ranges = i; /* and finally sort the entries with qsort */ qsort(range, *ranges, sizeof(struct memory_range), compare_ranges); return 0; error: if (firmware_memmap_dir) { closedir(firmware_memmap_dir); } return -1; } kexec-tools-2.0.10/kexec/crashdump.c0000644001567400156740000001024612417126536016360 0ustar hormshorms/* * crashdump.c: Architecture independent code for crashdump support. * * Created by: Vivek Goyal (vgoyal@in.ibm.com) * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include #include #include #include #include #include #include #include #include "kexec.h" #include "crashdump.h" #include "kexec-syscall.h" /* include "crashdump-elf.c" twice to create two functions from one */ #define ELF_WIDTH 64 #define FUNC crash_create_elf64_headers #define EHDR Elf64_Ehdr #define PHDR Elf64_Phdr #include "crashdump-elf.c" #undef ELF_WIDTH #undef PHDR #undef EHDR #undef FUNC #define ELF_WIDTH 32 #define FUNC crash_create_elf32_headers #define EHDR Elf32_Ehdr #define PHDR Elf32_Phdr #include "crashdump-elf.c" #undef ELF_WIDTH #undef PHDR #undef EHDR #undef FUNC unsigned long crash_architecture(struct crash_elf_info *elf_info) { if (xen_present()) return xen_architecture(elf_info); else return elf_info->machine; } /* Returns the physical address of start of crash notes buffer for a cpu. */ int get_crash_notes_per_cpu(int cpu, uint64_t *addr, uint64_t *len) { char crash_notes[PATH_MAX]; char crash_notes_size[PATH_MAX]; char line[MAX_LINE]; FILE *fp; struct stat cpu_stat; int count; unsigned long long temp; int fopen_errno; int stat_errno; *addr = 0; *len = 0; sprintf(crash_notes, "/sys/devices/system/cpu/cpu%d/crash_notes", cpu); fp = fopen(crash_notes, "r"); if (!fp) { fopen_errno = errno; if (fopen_errno != ENOENT) die("Could not open \"%s\": %s\n", crash_notes, strerror(fopen_errno)); if (stat("/sys/devices", &cpu_stat)) { stat_errno = errno; if (stat_errno == ENOENT) die("\"/sys/devices\" does not exist. " "Sysfs does not seem to be mounted. " "Try mounting sysfs.\n"); die("Could not open \"/sys/devices\": %s\n", strerror(stat_errno)); } /* CPU is not physically present.*/ return -1; } if (!fgets(line, sizeof(line), fp)) die("Cannot parse %s: %s\n", crash_notes, strerror(errno)); count = sscanf(line, "%Lx", &temp); if (count != 1) die("Cannot parse %s: %s\n", crash_notes, strerror(errno)); *addr = (uint64_t) temp; fclose(fp); *len = MAX_NOTE_BYTES; sprintf(crash_notes_size, "/sys/devices/system/cpu/cpu%d/crash_notes_size", cpu); fp = fopen(crash_notes_size, "r"); if (fp) { if (!fgets(line, sizeof(line), fp)) die("Cannot parse %s: %s\n", crash_notes_size, strerror(errno)); count = sscanf(line, "%Lu", &temp); if (count != 1) die("Cannot parse %s: %s\n", crash_notes_size, strerror(errno)); *len = (uint64_t) temp; fclose(fp); } dbgprintf("%s: crash_notes addr = %Lx, size = %Lu\n", __FUNCTION__, (unsigned long long)*addr, (unsigned long long)*len); return 0; } static int get_vmcoreinfo(const char *kdump_info, uint64_t *addr, uint64_t *len) { char line[MAX_LINE]; int count; FILE *fp; unsigned long long temp, temp2; *addr = 0; *len = 0; if (!(fp = fopen(kdump_info, "r"))) return -1; if (!fgets(line, sizeof(line), fp)) die("Cannot parse %s: %s\n", kdump_info, strerror(errno)); count = sscanf(line, "%Lx %Lx", &temp, &temp2); if (count != 2) die("Cannot parse %s: %s\n", kdump_info, strerror(errno)); *addr = (uint64_t) temp; *len = (uint64_t) temp2; fclose(fp); return 0; } /* Returns the physical address of start of crash notes buffer for a kernel. */ int get_kernel_vmcoreinfo(uint64_t *addr, uint64_t *len) { return get_vmcoreinfo("/sys/kernel/vmcoreinfo", addr, len); } kexec-tools-2.0.10/kexec/crashdump-xen.c0000644001567400156740000001315712417126536017154 0ustar hormshorms#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kexec.h" #include "crashdump.h" #include "kexec-syscall.h" #include "config.h" #ifdef HAVE_LIBXENCTRL #include #endif struct crash_note_info { unsigned long base; unsigned long length; }; static int xen_phys_cpus; static struct crash_note_info *xen_phys_notes; /* based on code from xen-detect.c */ static int is_dom0; #if defined(__i386__) || defined(__x86_64__) static jmp_buf xen_sigill_jmp; void xen_sigill_handler(int sig) { longjmp(xen_sigill_jmp, 1); } static void xen_cpuid(uint32_t idx, uint32_t *regs, int pv_context) { #ifdef __i386__ /* Use the stack to avoid reg constraint failures with some gcc flags */ asm volatile ( "push %%eax; push %%ebx; push %%ecx; push %%edx\n\t" "test %1,%1 ; jz 1f ; ud2a ; .ascii \"xen\" ; 1: cpuid\n\t" "mov %%eax,(%2); mov %%ebx,4(%2)\n\t" "mov %%ecx,8(%2); mov %%edx,12(%2)\n\t" "pop %%edx; pop %%ecx; pop %%ebx; pop %%eax\n\t" : : "a" (idx), "c" (pv_context), "S" (regs) : "memory" ); #else asm volatile ( "test %5,%5 ; jz 1f ; ud2a ; .ascii \"xen\" ; 1: cpuid\n\t" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) : "0" (idx), "1" (pv_context), "2" (0) ); #endif } static int check_for_xen(int pv_context) { uint32_t regs[4]; char signature[13]; uint32_t base; for (base = 0x40000000; base < 0x40010000; base += 0x100) { xen_cpuid(base, regs, pv_context); *(uint32_t *)(signature + 0) = regs[1]; *(uint32_t *)(signature + 4) = regs[2]; *(uint32_t *)(signature + 8) = regs[3]; signature[12] = '\0'; if (strcmp("XenVMMXenVMM", signature) == 0 && regs[0] >= (base + 2)) goto found; } return 0; found: xen_cpuid(base + 1, regs, pv_context); return regs[0]; } static int xen_detect_pv_guest(void) { struct sigaction act, oldact; int is_pv = -1; if (setjmp(xen_sigill_jmp)) return is_pv; memset(&act, 0, sizeof(act)); act.sa_handler = xen_sigill_handler; sigemptyset (&act.sa_mask); if (sigaction(SIGILL, &act, &oldact)) return is_pv; if (check_for_xen(1)) is_pv = 1; sigaction(SIGILL, &oldact, NULL); return is_pv; } #else static int xen_detect_pv_guest(void) { return 1; } #endif /* * Return 1 if its a PV guest. * This includes dom0, which is the only PV guest where kexec/kdump works. * HVM guests have to be handled as native hardware. */ int xen_present(void) { if (!is_dom0) { if (access("/proc/xen", F_OK) == 0) is_dom0 = xen_detect_pv_guest(); else is_dom0 = -1; } return is_dom0 > 0; } unsigned long xen_architecture(struct crash_elf_info *elf_info) { unsigned long machine = elf_info->machine; #ifdef HAVE_LIBXENCTRL int rc; xen_capabilities_info_t capabilities; xc_interface *xc; if (!xen_present()) goto out; memset(capabilities, '0', XEN_CAPABILITIES_INFO_LEN); xc = xc_interface_open(NULL, NULL, 0); if ( !xc ) { fprintf(stderr, "failed to open xen control interface.\n"); goto out; } rc = xc_version(xc, XENVER_capabilities, &capabilities[0]); if ( rc == -1 ) { fprintf(stderr, "failed to make Xen version hypercall.\n"); goto out_close; } if (strstr(capabilities, "xen-3.0-x86_64")) machine = EM_X86_64; else if (strstr(capabilities, "xen-3.0-x86_32")) machine = EM_386; out_close: xc_interface_close(xc); out: #endif return machine; } #ifdef HAVE_LIBXENCTRL int get_xen_vmcoreinfo(uint64_t *addr, uint64_t *len) { xc_interface *xc; int ret = 0; xc = xc_interface_open(NULL, NULL, 0); if (!xc) { fprintf(stderr, "failed to open xen control interface.\n"); return -1; } ret = xc_kexec_get_range(xc, KEXEC_RANGE_MA_VMCOREINFO, 0, len, addr); xc_interface_close(xc); if (ret < 0) return -1; return 0; } int xen_get_nr_phys_cpus(void) { xc_interface *xc; int max_cpus; int cpu = -1; if (xen_phys_cpus) return xen_phys_cpus; xc = xc_interface_open(NULL, NULL, 0); if (!xc) { fprintf(stderr, "failed to open xen control interface.\n"); return -1; } max_cpus = xc_get_max_cpus(xc); if (max_cpus <= 0) goto out; xen_phys_notes = calloc(max_cpus, sizeof(*xen_phys_notes)); if (xen_phys_notes == NULL) goto out; for (cpu = 0; cpu < max_cpus; cpu++) { uint64_t size, start; int ret; ret = xc_kexec_get_range(xc, KEXEC_RANGE_MA_CPU, cpu, &size, &start); if (ret < 0) break; xen_phys_notes[cpu].base = start; xen_phys_notes[cpu].length = size; } xen_phys_cpus = cpu; out: xc_interface_close(xc); return cpu; } #else int get_xen_vmcoreinfo(uint64_t *addr, uint64_t *len) { return -1; } int xen_get_nr_phys_cpus(void) { return -1; } #endif int xen_get_note(int cpu, uint64_t *addr, uint64_t *len) { struct crash_note_info *note; if (xen_phys_cpus <= 0) return -1; note = xen_phys_notes + cpu; *addr = note->base; *len = note->length; return 0; } #ifdef HAVE_LIBXENCTRL int xen_get_crashkernel_region(uint64_t *start, uint64_t *end) { uint64_t size; xc_interface *xc; int rc = -1; xc = xc_interface_open(NULL, NULL, 0); if (!xc) { fprintf(stderr, "failed to open xen control interface.\n"); goto out; } rc = xc_kexec_get_range(xc, KEXEC_RANGE_MA_CRASH, 0, &size, start); if (rc < 0) { fprintf(stderr, "failed to get crash region from hypervisor.\n"); goto out_close; } *end = *start + size - 1; out_close: xc_interface_close(xc); out: return rc; } #else int xen_get_crashkernel_region(uint64_t *start, uint64_t *end) { return -1; } #endif kexec-tools-2.0.10/kexec/phys_arch.c0000644001567400156740000000120311642166046016342 0ustar hormshorms#include "kexec.h" #include #include #include long physical_arch(void) { struct utsname utsname; int i, result = uname(&utsname); if (result < 0) { fprintf(stderr, "uname failed: %s\n", strerror(errno)); return -1; } for (i = 0; arches[i].machine; ++i) { if (strcmp(utsname.machine, arches[i].machine) == 0) return arches[i].arch; if ((strcmp(arches[i].machine, "arm") == 0) && (strncmp(utsname.machine, arches[i].machine, strlen(arches[i].machine)) == 0)) return arches[i].arch; } fprintf(stderr, "Unsupported machine type: %s\n", utsname.machine); return -1; } kexec-tools-2.0.10/kexec/kernel_version.c0000644001567400156740000000224112417126536017413 0ustar hormshorms#include "kexec.h" #include #include #include #include #include #include long kernel_version(void) { struct utsname utsname; unsigned long major, minor, patch; char *p; if (uname(&utsname) < 0) { fprintf(stderr, "uname failed: %s\n", strerror(errno)); return -1; } p = utsname.release; major = strtoul(p, &p, 10); if (major == ULONG_MAX) { fprintf(stderr, "strtoul failed: %s\n", strerror(errno)); return -1; } if (*p++ != '.') { fprintf(stderr, "Unsupported utsname.release: %s\n", utsname.release); return -1; } minor = strtoul(p, &p, 10); if (minor == ULONG_MAX) { fprintf(stderr, "strtoul failed: %s\n", strerror(errno)); return -1; } /* There may or may not be a patch level for this kernel */ if (*p++ == '.') { patch = strtoul(p, &p, 10); if (patch == ULONG_MAX) { fprintf(stderr, "strtoul failed: %s\n",strerror(errno)); return -1; } } else { patch = 0; } if (major >= 256 || minor >= 256 || patch >= 256) { fprintf(stderr, "Unsupported utsname.release: %s\n", utsname.release); return -1; } return KERNEL_VERSION(major, minor, patch); } kexec-tools-2.0.10/kexec/lzma.c0000644001567400156740000001001012466046354015325 0ustar hormshorms#include #include #include "kexec-lzma.h" #include "config.h" #include "kexec.h" #ifdef HAVE_LIBLZMA #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define kBufferSize (1 << 15) typedef struct lzfile { uint8_t buf[kBufferSize]; lzma_stream strm; FILE *file; int encoding; int eof; } LZFILE; LZFILE *lzopen(const char *path, const char *mode); int lzclose(LZFILE *lzfile); ssize_t lzread(LZFILE *lzfile, void *buf, size_t len); static LZFILE *lzopen_internal(const char *path, const char *mode, int fd) { int level = 5; int encoding = 0; FILE *fp; LZFILE *lzfile; lzma_ret ret; lzma_stream lzma_strm_tmp = LZMA_STREAM_INIT; for (; *mode; mode++) { if (*mode == 'w') encoding = 1; else if (*mode == 'r') encoding = 0; else if (*mode >= '1' && *mode <= '9') level = *mode - '0'; } if (fd != -1) fp = fdopen(fd, encoding ? "w" : "r"); else fp = fopen(path, encoding ? "w" : "r"); if (!fp) return NULL; lzfile = calloc(1, sizeof(*lzfile)); if (!lzfile) { fclose(fp); return NULL; } lzfile->file = fp; lzfile->encoding = encoding; lzfile->eof = 0; lzfile->strm = lzma_strm_tmp; if (encoding) { lzma_options_lzma opt_lzma; if (lzma_lzma_preset(&opt_lzma, level - 1)) return NULL; ret = lzma_alone_encoder(&lzfile->strm, &opt_lzma); } else { ret = lzma_auto_decoder(&lzfile->strm, UINT64_C(64) * 1024 * 1024, 0); } if (ret != LZMA_OK) { fclose(fp); free(lzfile); return NULL; } return lzfile; } LZFILE *lzopen(const char *path, const char *mode) { return lzopen_internal(path, mode, -1); } int lzclose(LZFILE *lzfile) { lzma_ret ret; size_t n; if (!lzfile) return -1; if (lzfile->encoding) { for (;;) { lzfile->strm.avail_out = kBufferSize; lzfile->strm.next_out = lzfile->buf; ret = lzma_code(&lzfile->strm, LZMA_FINISH); if (ret != LZMA_OK && ret != LZMA_STREAM_END) return -1; n = kBufferSize - lzfile->strm.avail_out; if (n && fwrite(lzfile->buf, 1, n, lzfile->file) != n) return -1; if (ret == LZMA_STREAM_END) break; } } lzma_end(&lzfile->strm); return fclose(lzfile->file); free(lzfile); } ssize_t lzread(LZFILE *lzfile, void *buf, size_t len) { lzma_ret ret; int eof = 0; if (!lzfile || lzfile->encoding) return -1; if (lzfile->eof) return 0; lzfile->strm.next_out = buf; lzfile->strm.avail_out = len; for (;;) { if (!lzfile->strm.avail_in) { lzfile->strm.next_in = lzfile->buf; lzfile->strm.avail_in = fread(lzfile->buf, 1, kBufferSize, lzfile->file); if (!lzfile->strm.avail_in) eof = 1; } ret = lzma_code(&lzfile->strm, LZMA_RUN); if (ret == LZMA_STREAM_END) { lzfile->eof = 1; return len - lzfile->strm.avail_out; } if (ret != LZMA_OK) return -1; if (!lzfile->strm.avail_out) return len; if (eof) return -1; } } char *lzma_decompress_file(const char *filename, off_t *r_size) { LZFILE *fp; char *buf; off_t size, allocated; ssize_t result; dbgprintf("Try LZMA decompression.\n"); *r_size = 0; if (!filename) return NULL; fp = lzopen(filename, "rb"); if (fp == 0) { dbgprintf("Cannot open `%s'\n", filename); return NULL; } size = 0; allocated = 65536; buf = xmalloc(allocated); do { if (size == allocated) { allocated <<= 1; buf = xrealloc(buf, allocated); } result = lzread(fp, buf + size, allocated - size); if (result < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; dbgprintf("%s: read on %s of %ld bytes failed\n", __func__, filename, (allocated - size) + 0UL); break; } size += result; } while (result > 0); if (lzclose(fp) != LZMA_OK) { dbgprintf("%s: Close of %s failed\n", __func__, filename); goto fail; } if (result < 0) goto fail; *r_size = size; return buf; fail: free(buf); return NULL; } #else char *lzma_decompress_file(const char *UNUSED(filename), off_t *UNUSED(r_size)) { return NULL; } #endif /* HAVE_LIBLZMA */ kexec-tools-2.0.10/kexec/zlib.c0000644001567400156740000000336612466046354015342 0ustar hormshorms#include "kexec-zlib.h" #include "kexec.h" #ifdef HAVE_LIBZ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include static void _gzerror(gzFile fp, int *errnum, const char **errmsg) { *errmsg = gzerror(fp, errnum); if (*errnum == Z_ERRNO) { *errmsg = strerror(*errnum); } } char *zlib_decompress_file(const char *filename, off_t *r_size) { gzFile fp; int errnum; const char *msg; char *buf; off_t size = 0, allocated; ssize_t result; dbgprintf("Try gzip decompression.\n"); *r_size = 0; if (!filename) { return NULL; } fp = gzopen(filename, "rb"); if (fp == 0) { _gzerror(fp, &errnum, &msg); dbgprintf("Cannot open `%s': %s\n", filename, msg); return NULL; } if (gzdirect(fp)) { /* It's not in gzip format */ return NULL; } 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; _gzerror(fp, &errnum, &msg); dbgprintf("Read on %s of %ld bytes failed: %s\n", filename, (allocated - size) + 0UL, msg); size = 0; goto fail; } size += result; } while(result > 0); fail: result = gzclose(fp); if (result != Z_OK) { _gzerror(fp, &errnum, &msg); dbgprintf(" Close of %s failed: %s\n", filename, msg); } if (size > 0) { *r_size = size; } else { free(buf); buf = NULL; } return buf; } #else char *zlib_decompress_file(const char *UNUSED(filename), off_t *UNUSED(r_size)) { return NULL; } #endif /* HAVE_ZLIB */ kexec-tools-2.0.10/kexec/kexec-xen.c0000644001567400156740000000526212417126536016263 0ustar hormshorms#define _GNU_SOURCE #include #include #include #include #include "kexec.h" #include "kexec-syscall.h" #include "crashdump.h" #include "config.h" #ifdef HAVE_LIBXENCTRL #include #include "crashdump.h" int xen_kexec_load(struct kexec_info *info) { uint32_t nr_segments = info->nr_segments; struct kexec_segment *segments = info->segment; xc_interface *xch; xc_hypercall_buffer_array_t *array = NULL; uint8_t type; uint8_t arch; xen_kexec_segment_t *xen_segs; int s; int ret = -1; xch = xc_interface_open(NULL, NULL, 0); if (!xch) return -1; xen_segs = calloc(nr_segments + 1, sizeof(*xen_segs)); if (!xen_segs) goto out; array = xc_hypercall_buffer_array_create(xch, nr_segments); if (array == NULL) goto out; for (s = 0; s < nr_segments; s++) { DECLARE_HYPERCALL_BUFFER(void, seg_buf); seg_buf = xc_hypercall_buffer_array_alloc(xch, array, s, seg_buf, segments[s].bufsz); if (seg_buf == NULL) goto out; memcpy(seg_buf, segments[s].buf, segments[s].bufsz); set_xen_guest_handle(xen_segs[s].buf.h, seg_buf); xen_segs[s].buf_size = segments[s].bufsz; xen_segs[s].dest_maddr = (uint64_t)segments[s].mem; xen_segs[s].dest_size = segments[s].memsz; } /* * Ensure 0 - 1 MiB is mapped and accessible by the image. * * This allows access to the VGA memory and the region * purgatory copies in the crash case. */ set_xen_guest_handle(xen_segs[s].buf.h, HYPERCALL_BUFFER_NULL); xen_segs[s].buf_size = 0; xen_segs[s].dest_maddr = 0; xen_segs[s].dest_size = 1 * 1024 * 1024; nr_segments++; type = (info->kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH : KEXEC_TYPE_DEFAULT; arch = (info->kexec_flags & KEXEC_ARCH_MASK) >> 16; #if defined(__i386__) || defined(__x86_64__) if (!arch) arch = EM_386; #endif ret = xc_kexec_load(xch, type, arch, (uint64_t)info->entry, nr_segments, xen_segs); out: xc_hypercall_buffer_array_destroy(xch, array); free(xen_segs); xc_interface_close(xch); return ret; } int xen_kexec_unload(uint64_t kexec_flags) { xc_interface *xch; uint8_t type; int ret; xch = xc_interface_open(NULL, NULL, 0); if (!xch) return -1; type = (kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH : KEXEC_TYPE_DEFAULT; ret = xc_kexec_unload(xch, type); xc_interface_close(xch); return ret; } void xen_kexec_exec(void) { xc_interface *xch; xch = xc_interface_open(NULL, NULL, 0); if (!xch) return; xc_kexec_exec(xch, KEXEC_TYPE_DEFAULT); xc_interface_close(xch); } #else /* ! HAVE_LIBXENCTRL */ int xen_kexec_load(struct kexec_info *UNUSED(info)) { return -1; } int xen_kexec_unload(uint64_t kexec_flags) { return -1; } void xen_kexec_exec(void) { } #endif kexec-tools-2.0.10/kexec/crashdump-elf.c0000644001567400156740000001544512417126536017132 0ustar hormshorms #if !defined(FUNC) || !defined(EHDR) || !defined(PHDR) #error FUNC, EHDR and PHDR must be defined #endif #if (ELF_WIDTH == 64) #define dbgprintf_phdr(prefix, phdr) \ do { \ dbgprintf("%s: p_type = %u, p_offset = 0x%llx p_paddr = 0x%llx " \ "p_vaddr = 0x%llx p_filesz = 0x%llx p_memsz = 0x%llx\n", \ (prefix), (phdr)->p_type, \ (unsigned long long)((phdr)->p_offset), \ (unsigned long long)((phdr)->p_paddr), \ (unsigned long long)((phdr)->p_vaddr), \ (unsigned long long)((phdr)->p_filesz), \ (unsigned long long)((phdr)->p_memsz)); \ } while(0) #else #define dbgprintf_phdr(prefix, phdr) \ do { \ dbgprintf("%s: p_type = %u, p_offset = 0x%x " "p_paddr = 0x%x " \ "p_vaddr = 0x%x p_filesz = 0x%x p_memsz = 0x%x\n", \ (prefix), (phdr)->p_type, (phdr)->p_offset, (phdr)->p_paddr, \ (phdr)->p_vaddr, (phdr)->p_filesz, (phdr)->p_memsz); \ } while(0) #endif /* Prepares the crash memory headers and stores in supplied buffer. */ int FUNC(struct kexec_info *info, struct crash_elf_info *elf_info, struct memory_range *range, int ranges, void **buf, unsigned long *size, unsigned long align) { EHDR *elf; PHDR *phdr; int i; unsigned long sz; char *bufp; long int nr_cpus = 0; uint64_t notes_addr, notes_len; uint64_t vmcoreinfo_addr, vmcoreinfo_len; int has_vmcoreinfo = 0; int (*get_note_info)(int cpu, uint64_t *addr, uint64_t *len); long int count_cpu; if (xen_present()) nr_cpus = xen_get_nr_phys_cpus(); else nr_cpus = sysconf(_SC_NPROCESSORS_CONF); if (nr_cpus < 0) { return -1; } if (xen_present()) { if (!get_xen_vmcoreinfo(&vmcoreinfo_addr, &vmcoreinfo_len)) has_vmcoreinfo = 1; } else if (!get_kernel_vmcoreinfo(&vmcoreinfo_addr, &vmcoreinfo_len)) has_vmcoreinfo = 1; sz = sizeof(EHDR) + (nr_cpus + has_vmcoreinfo) * sizeof(PHDR) + ranges * sizeof(PHDR); /* * Certain architectures such as x86_64 and ia64 require a separate * PT_LOAD program header for the kernel. This is controlled through * elf_info->kern_size. * * The separate PT_LOAD program header is required either because the * kernel is mapped at a different location than the rest of the * physical memory or because we need to support relocatable kernels. * Or both as on x86_64. * * In the relocatable kernel case this PT_LOAD segment is used to tell * where the kernel was actually loaded which may be different from * the load address present in the vmlinux file. * * The extra kernel PT_LOAD program header results in a vmcore file * which is larger than the size of the physical memory. This is * because the memory for the kernel is present both in the kernel * PT_LOAD program header and in the physical RAM program headers. */ if (elf_info->kern_size && !xen_present()) { sz += sizeof(PHDR); } /* * Make sure the ELF core header is aligned to at least 1024. * We do this because the secondary kernel gets the ELF core * header address on the kernel command line through the memmap= * option, and this option requires 1k granularity. */ if (align % ELF_CORE_HEADER_ALIGN) { return -1; } sz = _ALIGN(sz, align); bufp = xmalloc(sz); memset(bufp, 0, sz); *buf = bufp; *size = sz; /* Setup ELF Header*/ elf = (EHDR *) bufp; bufp += sizeof(EHDR); memcpy(elf->e_ident, ELFMAG, SELFMAG); elf->e_ident[EI_CLASS] = elf_info->class; elf->e_ident[EI_DATA] = elf_info->data; elf->e_ident[EI_VERSION]= EV_CURRENT; elf->e_ident[EI_OSABI] = ELFOSABI_NONE; memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf->e_type = ET_CORE; elf->e_machine = crash_architecture(elf_info); elf->e_version = EV_CURRENT; elf->e_entry = 0; elf->e_phoff = sizeof(EHDR); elf->e_shoff = 0; elf->e_flags = 0; elf->e_ehsize = sizeof(EHDR); elf->e_phentsize= sizeof(PHDR); elf->e_phnum = 0; elf->e_shentsize= 0; elf->e_shnum = 0; elf->e_shstrndx = 0; /* Default way to get crash notes is by get_crash_notes_per_cpu() */ get_note_info = elf_info->get_note_info; if (!get_note_info) get_note_info = get_crash_notes_per_cpu; if (xen_present()) get_note_info = xen_get_note; /* PT_NOTE program headers. One per cpu */ count_cpu = nr_cpus; for (i = 0; count_cpu > 0; i++) { if (get_note_info(i, ¬es_addr, ¬es_len) < 0) { /* This cpu is not present. Skip it. */ continue; } count_cpu--; phdr = (PHDR *) bufp; bufp += sizeof(PHDR); phdr->p_type = PT_NOTE; phdr->p_flags = 0; phdr->p_offset = phdr->p_paddr = notes_addr; phdr->p_vaddr = 0; phdr->p_filesz = phdr->p_memsz = notes_len; /* Do we need any alignment of segments? */ phdr->p_align = 0; /* Increment number of program headers. */ (elf->e_phnum)++; dbgprintf_phdr("Elf header", phdr); } if (has_vmcoreinfo && !(info->kexec_flags & KEXEC_PRESERVE_CONTEXT)) { phdr = (PHDR *) bufp; bufp += sizeof(PHDR); phdr->p_type = PT_NOTE; phdr->p_flags = 0; phdr->p_offset = phdr->p_paddr = vmcoreinfo_addr; phdr->p_vaddr = 0; phdr->p_filesz = phdr->p_memsz = vmcoreinfo_len; /* Do we need any alignment of segments? */ phdr->p_align = 0; (elf->e_phnum)++; dbgprintf_phdr("vmcoreinfo header", phdr); } /* Setup an PT_LOAD type program header for the region where * Kernel is mapped if elf_info->kern_size is non-zero. */ if (elf_info->kern_size && !xen_present()) { phdr = (PHDR *) bufp; bufp += sizeof(PHDR); phdr->p_type = PT_LOAD; phdr->p_flags = PF_R|PF_W|PF_X; phdr->p_offset = phdr->p_paddr = elf_info->kern_paddr_start; phdr->p_vaddr = elf_info->kern_vaddr_start; phdr->p_filesz = phdr->p_memsz = elf_info->kern_size; phdr->p_align = 0; (elf->e_phnum)++; dbgprintf_phdr("Kernel text Elf header", phdr); } /* Setup PT_LOAD type program header for every system RAM chunk. * A seprate program header for Backup Region*/ for (i = 0; i < ranges; i++, range++) { unsigned long long mstart, mend; if (range->type != RANGE_RAM) continue; mstart = range->start; mend = range->end; if (!mstart && !mend) continue; phdr = (PHDR *) bufp; bufp += sizeof(PHDR); phdr->p_type = PT_LOAD; phdr->p_flags = PF_R|PF_W|PF_X; phdr->p_offset = mstart; if (mstart == info->backup_src_start && (mend - mstart + 1) == info->backup_src_size) phdr->p_offset = info->backup_start; /* We already prepared the header for kernel text. Map * rest of the memory segments to kernel linearly mapped * memory region. */ phdr->p_paddr = mstart; phdr->p_vaddr = phys_to_virt(elf_info, mstart); phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; /* Do we need any alignment of segments? */ phdr->p_align = 0; /* HIGMEM has a virtual address of -1 */ if (elf_info->lowmem_limit && (mend > (elf_info->lowmem_limit - 1))) phdr->p_vaddr = -1; /* Increment number of program headers. */ (elf->e_phnum)++; dbgprintf_phdr("Elf header", phdr); } return 0; } #undef dbgprintf_phdr kexec-tools-2.0.10/kexec/crashdump.h0000644001567400156740000000434412417126536016367 0ustar hormshorms#ifndef CRASHDUMP_H #define CRASHDUMP_H int get_crashkernel_region(uint64_t *start, uint64_t *end); extern int get_crash_notes_per_cpu(int cpu, uint64_t *addr, uint64_t *len); extern int get_kernel_vmcoreinfo(uint64_t *addr, uint64_t *len); extern int get_xen_vmcoreinfo(uint64_t *addr, uint64_t *len); /* Need to find a better way to determine per cpu notes section size. */ #define MAX_NOTE_BYTES 1024 /* Expecting ELF headers to fit in 32K. Increase it if you need more. */ #define KCORE_ELF_HEADERS_SIZE 32768 /* The address of the ELF header is passed to the secondary kernel * using the kernel command line option memmap=nnn. * The smallest unit the kernel accepts is in kilobytes, * so we need to make sure the ELF header is aligned to 1024. */ #define ELF_CORE_HEADER_ALIGN 1024 /* structure passed to crash_create_elf32/64_headers() */ struct crash_elf_info { unsigned long class; unsigned long data; unsigned long machine; unsigned long long page_offset; unsigned long long kern_vaddr_start; unsigned long long kern_paddr_start; unsigned long kern_size; unsigned long lowmem_limit; int (*get_note_info)(int cpu, uint64_t *addr, uint64_t *len); }; typedef int(*crash_create_elf_headers_func)(struct kexec_info *info, struct crash_elf_info *elf_info, struct memory_range *range, int ranges, void **buf, unsigned long *size, unsigned long align); int crash_create_elf32_headers(struct kexec_info *info, struct crash_elf_info *elf_info, struct memory_range *range, int ranges, void **buf, unsigned long *size, unsigned long align); int crash_create_elf64_headers(struct kexec_info *info, struct crash_elf_info *elf_info, struct memory_range *range, int ranges, void **buf, unsigned long *size, unsigned long align); unsigned long crash_architecture(struct crash_elf_info *elf_info); unsigned long phys_to_virt(struct crash_elf_info *elf_info, unsigned long paddr); unsigned long xen_architecture(struct crash_elf_info *elf_info); int xen_get_nr_phys_cpus(void); int xen_get_note(int cpu, uint64_t *addr, uint64_t *len); int xen_get_crashkernel_region(uint64_t *start, uint64_t *end); #endif /* CRASHDUMP_H */ kexec-tools-2.0.10/kexec/firmware_memmap.h0000644001567400156740000000610011642166046017540 0ustar hormshorms/* * firmware_memmap.c: Read /sys/firmware/memmap * * Created by: Bernhard Walle (bernhard.walle@gmx.de) * Copyright (C) SUSE LINUX Products GmbH, 2008. All rights reserved * * 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. */ #ifndef FIRMWARE_MEMMAP_H #define FIRMWARE_MEMMAP_H #include "kexec.h" /** * Reads the /sys/firmware/memmap interface, documented in * Documentation/ABI/testing/sysfs-firmware-memmap (kernel tree). * * The difference between /proc/iomem and /sys/firmware/memmap is that * /sys/firmware/memmap provides the raw memory map, provided by the * firmware of the system. That memory map should be passed to a kexec'd * kernel because the behaviour should be the same as a normal booted kernel, * so any limitation (e.g. by the user providing the mem command line option) * should not be passed to the kexec'd kernel. * * The parsing of the code is independent of the architecture. However, the * actual architecture-specific code might postprocess the code a bit, like * x86 does. */ /** * Compares two memory ranges according to their start address. This function * can be used with qsort() as @c compar function. * * @param[in] first a pointer to the first memory range * @param[in] second a pointer to the second memory range * @return 0 if @p first and @p second have the same start address, * a value less then 0 if the start address of @p first is less than * the start address of @p second, and a value greater than 0 if * the opposite is in case. */ int compare_ranges(const void *first, const void *second); /** * Checks if the kernel provides the /sys/firmware/memmap interface. * It makes sense to use that function in advance before calling * get_firmware_memmap_ranges() because the latter function prints an error * if it cannot open the directory. If have_sys_firmware_memmap() returns * false, then one can use the old /proc/iomem interface (for older kernels). */ int have_sys_firmware_memmap(void); /** * Parses the /sys/firmware/memmap memory map. * * @param[out] range a pointer to an array of type struct memory_range with * at least *range entries * @param[in,out] ranges a pointer to an integer that holds the number of * entries which range contains (at least). After successful * return, the number of actual entries will be written. * @return 0 on success, -1 on failure. */ int get_firmware_memmap_ranges(struct memory_range *range, size_t *ranges); #endif /* FIRMWARE_MEMMAP_H */ kexec-tools-2.0.10/kexec/kexec-elf-boot.h0000644001567400156740000000031311642166046017174 0ustar hormshorms#ifndef KEXEC_ELF_BOOT_H #define KEXEC_ELF_BOOT_H unsigned long elf_boot_notes( struct kexec_info *info, unsigned long max_addr, const char *cmdline, int cmdline_len); #endif /* KEXEC_ELF_BOOT_H */ kexec-tools-2.0.10/kexec/kexec-elf.h0000644001567400156740000000773512242534555016253 0ustar hormshorms#ifndef KEXEC_ELF_H #define KEXEC_ELF_H #include #include 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 long e_entry; unsigned long long e_phoff; unsigned long 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 long p_paddr; unsigned long long p_vaddr; unsigned long long p_filesz; unsigned long long p_memsz; unsigned long long p_offset; const char *p_data; unsigned p_type; unsigned p_flags; unsigned long long p_align; }; struct mem_shdr { unsigned sh_name; unsigned sh_type; unsigned long long sh_flags; unsigned long long sh_addr; unsigned long long sh_offset; unsigned long long sh_size; unsigned sh_link; unsigned sh_info; unsigned long long sh_addralign; unsigned long 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 st_shndx; /* Section index */ unsigned long long st_value; /* Symbol value */ unsigned long long st_size; /* Symbol size */ }; struct mem_rela { unsigned long long r_offset; unsigned r_sym; unsigned r_type; unsigned long 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; /* Misc flags */ #define ELF_SKIP_FILESZ_CHECK 0x00000001 extern void free_elf_info(struct mem_ehdr *ehdr); extern int build_elf_info(const char *buf, off_t len, struct mem_ehdr *ehdr, uint32_t flags); extern int build_elf_exec_info(const char *buf, off_t len, struct mem_ehdr *ehdr, uint32_t flags); extern int build_elf_rel_info(const char *buf, off_t len, struct mem_ehdr *ehdr, uint32_t flags); extern int build_elf_core_info(const char *buf, off_t len, struct mem_ehdr *ehdr, uint32_t flags); extern int elf_exec_load(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, uint32_t flags); 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, uint32_t flags); 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 */ kexec-tools-2.0.10/kexec/kexec-sha256.h0000644001567400156740000000024111424244110016460 0ustar hormshorms#ifndef KEXEC_SHA256_H #define KEXEC_SHA256_H struct sha256_region { uint64_t start; uint64_t len; }; #define SHA256_REGIONS 16 #endif /* KEXEC_SHA256_H */ kexec-tools-2.0.10/kexec/kexec-zlib.h0000644001567400156740000000031411642166046016426 0ustar hormshorms#ifndef __KEXEC_ZLIB_H #define __KEXEC_ZLIB_H #include #include #include "config.h" char *zlib_decompress_file(const char *filename, off_t *r_size); #endif /* __KEXEC_ZLIB_H */ kexec-tools-2.0.10/kexec/kexec-lzma.h0000644001567400156740000000024511642166046016434 0ustar hormshorms#ifndef __KEXEC_LZMA_H #define __KEXEC_LZMA_H #include char *lzma_decompress_file(const char *filename, off_t *r_size); #endif /* __KEXEC_LZMA_H */ kexec-tools-2.0.10/kexec/kexec-syscall.h0000644001567400156740000000732112520551445017142 0ustar hormshorms#ifndef KEXEC_SYSCALL_H #define KEXEC_SYSCALL_H #define __LIBRARY__ #include #include #define LINUX_REBOOT_CMD_KEXEC_OLD 0x81726354 #define LINUX_REBOOT_CMD_KEXEC_OLD2 0x18263645 #define LINUX_REBOOT_CMD_KEXEC 0x45584543 #ifndef __NR_kexec_load #ifdef __i386__ #define __NR_kexec_load 283 #endif #ifdef __sh__ #define __NR_kexec_load 283 #endif #ifdef __cris__ #ifndef __NR_kexec_load #define __NR_kexec_load 283 #endif #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 #ifdef __s390x__ #define __NR_kexec_load 277 #endif #ifdef __s390__ #define __NR_kexec_load 277 #endif #ifdef __arm__ #define __NR_kexec_load __NR_SYSCALL_BASE + 347 #endif #if defined(__mips__) #define __NR_kexec_load 4311 #endif #ifdef __m68k__ #define __NR_kexec_load 313 #endif #ifndef __NR_kexec_load #error Unknown processor architecture. Needs a kexec_load syscall number. #endif #endif /*ifndef __NR_kexec_load*/ #ifndef __NR_kexec_file_load #ifdef __x86_64__ #define __NR_kexec_file_load 320 #endif #ifndef __NR_kexec_file_load /* system call not available for the arch */ #define __NR_kexec_file_load 0xffffffff /* system call not available */ #endif #endif /*ifndef __NR_kexec_file_load*/ 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 int is_kexec_file_load_implemented(void) { if (__NR_kexec_file_load != 0xffffffff) return 1; return 0; } static inline long kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char *cmdline_ptr, unsigned long flags) { return (long) syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len, cmdline_ptr, flags); } #define KEXEC_ON_CRASH 0x00000001 #define KEXEC_PRESERVE_CONTEXT 0x00000002 #define KEXEC_ARCH_MASK 0xffff0000 /* Flags for kexec file based system call */ #define KEXEC_FILE_UNLOAD 0x00000001 #define KEXEC_FILE_ON_CRASH 0x00000002 #define KEXEC_FILE_NO_INITRAMFS 0x00000004 /* 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_68K ( 4 << 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_ARCH_ARM (40 << 16) #define KEXEC_ARCH_S390 (22 << 16) #define KEXEC_ARCH_SH (42 << 16) #define KEXEC_ARCH_MIPS_LE (10 << 16) #define KEXEC_ARCH_MIPS ( 8 << 16) #define KEXEC_ARCH_CRIS (76 << 16) #define KEXEC_MAX_SEGMENTS 16 #ifdef __i386__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_386 #endif #ifdef __sh__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_SH #endif #ifdef __cris__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_CRIS #endif #ifdef __ia64__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_IA_64 #endif #ifdef __powerpc64__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_PPC64 #else #ifdef __powerpc__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_PPC #endif #endif #ifdef __x86_64__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_X86_64 #endif #ifdef __s390x__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_S390 #endif #ifdef __s390__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_S390 #endif #ifdef __arm__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_ARM #endif #if defined(__mips__) #define KEXEC_ARCH_NATIVE KEXEC_ARCH_MIPS #endif #ifdef __m68k__ #define KEXEC_ARCH_NATIVE KEXEC_ARCH_68K #endif #endif /* KEXEC_SYSCALL_H */ kexec-tools-2.0.10/kexec/kexec.h0000644001567400156740000002126412513334567015502 0ustar hormshorms#ifndef KEXEC_H #define KEXEC_H #include "config.h" #include #include #include #include #define USE_BSD #include #include #define _GNU_SOURCE #include "kexec-elf.h" #include "unused.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 /* * Document some of the reasons why crashdump may fail, so we can give * better error messages */ #define EFAILED -1 /* default error code */ #define ENOCRASHKERNEL -2 /* no memory reserved for crashkernel */ /* * 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)) _v; \ size_t size = sizeof(*(loc)); \ switch(size) { \ case 1: case 2: case 4: case 8: \ memcpy(&_v, (loc), size); \ break; \ default: \ _v = bad_unaligned_access_length(); \ break; \ } \ _v; \ }) #define put_unaligned(value, loc) \ do { \ size_t size = sizeof(*(loc)); \ __typeof__(*(loc)) _v = value; \ switch(size) { \ case 1: case 2: case 4: case 8: \ memcpy((loc), &_v, size); \ break; \ default: \ bad_unaligned_access_length(); \ break; \ } \ } while(0) #define _ALIGN_UP_MASK(addr, mask) (((addr) + (mask)) & ~(mask)) #define _ALIGN_DOWN_MASK(addr, mask) ((addr) & ~(mask)) /* align addr on a size boundary - adjust address up/down if needed */ #define _ALIGN_UP(addr, size) \ _ALIGN_UP_MASK(addr, (typeof(addr))(size) - 1) #define _ALIGN_DOWN(addr, size) \ _ALIGN_DOWN_MASK(addr, (typeof(addr))(size) - 1) /* align addr on a size boundary - adjust address up if needed */ #define _ALIGN(addr, size) _ALIGN_UP(addr, size) extern unsigned long long mem_min, mem_max; extern int kexec_debug; #define dbgprintf(...) \ do { \ if (kexec_debug) \ fprintf(stderr, __VA_ARGS__); \ } while(0) 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 #define RANGE_UNCACHED 4 }; struct memory_ranges { unsigned int size; struct memory_range *ranges; }; struct kexec_info { struct kexec_segment *segment; int nr_segments; struct memory_range *memory_range; int memory_ranges; struct memory_range *crash_range; int nr_crash_ranges; void *entry; struct mem_ehdr rhdr; unsigned long backup_start; unsigned long kexec_flags; unsigned long backup_src_start; unsigned long backup_src_size; /* Set to 1 if we are using kexec file syscall */ unsigned long file_mode :1; /* Filled by kernel image processing code */ int initrd_fd; char *command_line; int command_line_len; }; struct arch_map_entry { const char *machine; unsigned long arch; }; extern const struct arch_map_entry arches[]; long physical_arch(void); #define KERNEL_VERSION(major, minor, patch) \ (((major) << 16) | ((minor) << 8) | patch) long kernel_version(void); void usage(void); int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags); int valid_memory_range(struct kexec_info *info, unsigned long sstart, unsigned long send); 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_NOSYNC 'y' #define OPT_EXEC 'e' #define OPT_LOAD 'l' #define OPT_UNLOAD 'u' #define OPT_TYPE 't' #define OPT_PANIC 'p' #define OPT_KEXEC_FILE_SYSCALL 's' #define OPT_MEM_MIN 256 #define OPT_MEM_MAX 257 #define OPT_REUSE_INITRD 258 #define OPT_LOAD_PRESERVE_CONTEXT 259 #define OPT_LOAD_JUMP_BACK_HELPER 260 #define OPT_ENTRY 261 #define OPT_MAX 262 #define KEXEC_OPTIONS \ { "help", 0, 0, OPT_HELP }, \ { "version", 0, 0, OPT_VERSION }, \ { "force", 0, 0, OPT_FORCE }, \ { "no-ifdown", 0, 0, OPT_NOIFDOWN }, \ { "no-sync", 0, 0, OPT_NOSYNC }, \ { "load", 0, 0, OPT_LOAD }, \ { "unload", 0, 0, OPT_UNLOAD }, \ { "exec", 0, 0, OPT_EXEC }, \ { "load-preserve-context", 0, 0, OPT_LOAD_PRESERVE_CONTEXT}, \ { "load-jump-back-helper", 0, 0, OPT_LOAD_JUMP_BACK_HELPER }, \ { "entry", 1, 0, OPT_ENTRY }, \ { "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 }, \ { "reuseinitrd", 0, 0, OPT_REUSE_INITRD }, \ { "kexec-file-syscall", 0, 0, OPT_KEXEC_FILE_SYSCALL }, \ { "debug", 0, 0, OPT_DEBUG }, \ #define KEXEC_OPT_STR "h?vdfxyluet:ps" extern void dbgprint_mem_range(const char *prefix, struct memory_range *mr, int nr_mr); extern void die(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); 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_file_len(const char *filename, off_t size, off_t *nread); extern char *slurp_decompress_file(const char *filename, off_t *r_size); extern unsigned long virt_to_phys(unsigned long addr); extern void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz); extern void add_segment_phys_virt(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz, int phys); 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 long add_buffer_virt(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 long add_buffer_phys_virt(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, int phys); extern void arch_reuse_initrd(void); extern int ifdown(void); extern char purgatory[]; extern size_t purgatory_size; #define BOOTLOADER "kexec" #define BOOTLOADER_VERSION PACKAGE_VERSION void arch_usage(void); int arch_process_options(int argc, char **argv); int arch_compat_trampoline(struct kexec_info *info); void arch_update_purgatory(struct kexec_info *info); int is_crashkernel_mem_reserved(void); int get_max_crash_kernel_limit(uint64_t *start, uint64_t *end); char *get_command_line(void); int kexec_iomem_for_each_line(char *match, int (*callback)(void *data, int nr, char *str, unsigned long long base, unsigned long long length), void *data); int parse_iomem_single(char *str, uint64_t *start, uint64_t *end); const char * proc_iomem(void); #define MAX_LINE 160 char *concat_cmdline(const char *base, const char *append); int xen_present(void); int xen_kexec_load(struct kexec_info *info); int xen_kexec_unload(uint64_t kexec_flags); void xen_kexec_exec(void); #endif /* KEXEC_H */ kexec-tools-2.0.10/kexec/kexec.80000644001567400156740000001463212513334672015420 0ustar hormshorms.\" Process this file with .\" groff -man -Tascii kexec.8 .\" .TH kexec 8 "April 2006" Linux "User Manuals" .SH NAME kexec \- directly boot into a new kernel .SH SYNOPSIS .B /sbin/kexec .B [-v (\-\-version)] [-f (\-\-force)] [-x (\-\-no-ifdown)] [-y (\-\-no-sync)] [-l (\-\-load)] [-p (\-\-load-panic)] [-u (\-\-unload)] [-e (\-\-exec)] [-t (\-\-type)] .BI [\-\-mem\-min= addr ] .BI [\-\-mem\-max= addr ] .SH DESCRIPTION .B kexec is a system call that enables you to load and boot into another kernel from the currently running kernel. .B kexec performs the function of the boot loader from within the kernel. The primary difference between a standard system boot and a .B kexec boot is that the hardware initialization normally performed by the BIOS or firmware (depending on architecture) is not performed during a .B kexec boot. This has the effect of reducing the time required for a reboot. .PP Make sure you have selected .B CONFIG_KEXEC=y when configuring the kernel. The .B CONFIG_KEXEC option enables the .B kexec system call. .SH USAGE Using .B kexec consists of .RS (1) loading the kernel to be rebooted to into memory, and .RE .RS (2) actually rebooting to the pre-loaded kernel. .RE .PP To load a kernel, the syntax is as follows: .RS .B kexec .RI \-l\ kernel-image .RI "\-\-append=" command\-line\-options .RI "\-\-initrd=" initrd\-image .RE where .I kernel\-image is the kernel file that you intend to reboot to. .PP Insert the command-line parameters that must be passed to the new kernel into .IR command\-line\-options . Passing the exact contents of /proc/cmdline into .I command\-line\-options is the safest way to ensure that correct values are passed to the rebooting kernel. .PP The optional .I initrd-image is the initrd image to be used during boot. .PP It's also possible to invoke .B kexec without an option parameter. In that case, kexec loads the specified kernel and then invokes .BR shutdown (8). If the shutdown scripts of your Linux distribution support kexec-based rebooting, they then call .B kexec .I -e just before actually rebooting the machine. That way, the machine does a clean shutdown including all shutdown scripts. .SH EXAMPLE .PP For example, if the kernel image you want to reboot to is .BR /boot/vmlinux , the contents of /proc/cmdline is .BR "root\=/dev/hda1" , and the path to the initrd is .BR /boot/initrd , then you would use the following command to load the kernel: .RS .B kexec .RB \-l\ /boot/vmlinux .RB "\-\-append=" "root=/dev/hda1" "\ \-\-initrd=" /boot/initrd .RE .PP After this kernel is loaded, it can be booted to at any time using the command: .RS .BR kexec \ \-e .RE .SH OPTIONS .TP .B \-d\ (\-\-debug) Enable debugging messages. .TP .B \-e\ (\-\-exec) Run the currently loaded kernel. Note that it will reboot into the loaded kernel without calling shutdown(8). .TP .B \-f\ (\-\-force) Force an immediate .B kexec call, do not call .BR shutdown (8) (contrary to the default action without any option parameter). This option performs the same actions like executing .IR -l and .IR -e in one call. .TP .B \-h\ (\-\-help) Open a help file for .BR kexec . .TP .BI \-l\ (\-\-load) \ kernel Load the specified .I kernel into the current kernel. .TP .B \-p\ (\-\-load\-panic) Load the new kernel for use on panic. .TP .BI \-t\ (\-\-type= type ) Specify that the new kernel is of this .I type. .TP .B \-u\ (\-\-unload) Unload the current .B kexec target kernel. If a capture kernel is being unloaded then specify -p with -u. .TP .B \-v\ (\-\-version) Return the version number of the installed utility. .TP .B \-x\ (\-\-no\-ifdown) Shut down the running kernel, but restore the interface on reload. .TP .B \-y\ (\-\-no\-sync) Shut down the running kernel, but skip syncing the filesystems. .TP .BI \-\-mem\-min= addr Specify the lowest memory address .I addr to load code into. .TP .BI \-\-mem\-max= addr Specify the highest memory address .I addr to load code into. .TP .BI \-\-entry= addr Specify the jump back address. (0 means it's not jump back or preserve context) .TP .BI \-\-load\-preserve\-context Load the new kernel and preserve context of current kernel during kexec. .TP .BI \-\-load\-jump\-back\-helper Load a helper image to jump back to original kernel. .TP .BI \-\-reuseinitrd Reuse initrd from first boot. .SH SUPPORTED KERNEL FILE TYPES AND OPTIONS .B Beoboot-x86 .RS .TP .B \-\-args\-elf Pass ELF boot notes. .TP .B \-\-args\-linux Pass Linux kernel style options. .TP .B \-\-real\-mode Use the kernel's real mode entry point. .RE .PP .B elf-x86 .RS .TP .BI \-\-append= string Append .I string to the kernel command line. .TP .BI \-\-command\-line= string Set the kernel command line to .IR string . .TP .BI \-\-reuse-cmdline Use the command line from the running system. When a panic kernel is loaded, it strips the .I crashkernel parameter automatically. The .I BOOT_IMAGE parameter is also stripped. .TP .BI \-\-initrd= file Use .I file as the kernel's initial ramdisk. .TP .BI \-\-ramdisk= file Use .I file as the kernel's initial ramdisk. .RE .PP .B bzImage-x86 .RS .TP .BI \-\-append= string Append .I string to the kernel command line. .TP .BI \-\-command\-line= string Set the kernel command line to .IR string . .TP .BI \-\-reuse-cmdline Use the command line from the running system. When a panic kernel is loaded, it strips the .I crashkernel parameter automatically. The .I BOOT_IMAGE parameter is also stripped. .TP .BI \-\-initrd= file Use .I file as the kernel's initial ramdisk. .TP .BI \-\-ramdisk= file Use .I file as the kernel's initial ramdisk. .TP .BI \-\-real-mode Use real-mode entry point. .RE .PP .B multiboot-x86 .RS .TP .BI \-\-command\-line= string Set the kernel command line to .IR string . .TP .BI \-\-reuse-cmdline Use the command line from the running system. When a panic kernel is loaded, it strips the .I crashkernel parameter automatically. The .I BOOT_IMAGE parameter is also stripped. .TP .BI \-\-module= "mod arg1 arg2 ..." Load module .I mod with command-line arguments .I "arg1 arg2 ..." This parameter can be specified multiple times. .RE .SH ARCHITECTURE OPTIONS .TP .B \-\-console\-serial Enable the serial console. .TP .B \-\-console\-vga Enable the VGA console. .TP .B \-\-elf32\-core\-headers Prepare core headers in ELF32 format. .TP .B \-\-elf64\-core\-headers Prepare core headers in ELF64 format. .TP .B \-\-reset\-vga Attempt to reset a standard VGA device. .TP .BI \-\-serial= port Specify the serial .I port for debug output. .TP .BI \-\-serial\-baud= baud_rate Specify the .I baud rate of the serial port. kexec-tools-2.0.10/kexec/proc_iomem.c0000644001567400156740000000043211424244110016501 0ustar hormshorms#include "kexec.h" static const char proc_iomem_str[] = "/proc/iomem"; /* * Allow an architecture specific implementation of this * function to override the location of a file looking a lot * like /proc/iomem */ const char *proc_iomem(void) { return proc_iomem_str; } kexec-tools-2.0.10/kexec/virt_to_phys.c0000644001567400156740000000015511642166046017120 0ustar hormshorms#include "kexec.h" #include unsigned long virt_to_phys(unsigned long UNUSED(addr)) { abort(); } kexec-tools-2.0.10/kexec/phys_to_virt.c0000644001567400156740000000072411645037362017123 0ustar hormshorms#include "kexec.h" #include "crashdump.h" /** * phys_to_virt() - translate physical address to virtual address * @paddr: physical address to translate * * For most architectures physical address is simply virtual address minus * PAGE_OFFSET. Architectures that don't follow this convention should provide * their own implementation. */ unsigned long phys_to_virt(struct crash_elf_info *elf_info, unsigned long paddr) { return paddr + elf_info->page_offset; } kexec-tools-2.0.10/kexec/add_segment.c0000644001567400156740000000031211424244110016617 0ustar hormshorms#include "kexec.h" void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz) { return add_segment_phys_virt(info, buf, bufsz, base, memsz, 0); } kexec-tools-2.0.10/kexec/add_buffer.c0000644001567400156740000000052711424244110016436 0ustar hormshorms#include "kexec.h" 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) { return add_buffer_virt(info, buf, bufsz, memsz, buf_align, buf_min, buf_max, buf_end); } kexec-tools-2.0.10/kexec/arch_reuse_initrd.c0000644001567400156740000000022412242534555020056 0ustar hormshorms#include "kexec.h" unsigned char reuse_initrd = 0; void arch_reuse_initrd(void) { die("--reuseinitrd not implemented on this architecture\n"); } kexec-tools-2.0.10/kexec/kexec-uImage.c0000644001567400156740000001413612417126536016700 0ustar hormshorms#define _GNU_SOURCE #include #include #include #include #include #include #include #include "kexec.h" #include #ifdef HAVE_LIBZ #include #endif /* * Basic uImage loader. Not rocket science. */ /* * Returns the image type if everything goes well. This would * allow the user to decide if the image is of their interest. * * Returns -1 on a corrupted image * * Returns 0 if this is not a uImage */ int uImage_probe(const unsigned char *buf, off_t len, unsigned int arch) { struct image_header header; #ifdef HAVE_LIBZ unsigned int crc; unsigned int hcrc; #endif if ((uintmax_t)len < (uintmax_t)sizeof(header)) return -1; memcpy(&header, buf, sizeof(header)); if (be32_to_cpu(header.ih_magic) != IH_MAGIC) return 0; #ifdef HAVE_LIBZ hcrc = be32_to_cpu(header.ih_hcrc); header.ih_hcrc = 0; crc = crc32(0, (void *)&header, sizeof(header)); if (crc != hcrc) { printf("Header checksum of the uImage does not match\n"); return -1; } #endif switch (header.ih_type) { case IH_TYPE_KERNEL: case IH_TYPE_KERNEL_NOLOAD: break; case IH_TYPE_RAMDISK: break; default: printf("uImage type %d unsupported\n", header.ih_type); return -1; } if (header.ih_os != IH_OS_LINUX) { printf("uImage os %d unsupported\n", header.ih_os); return -1; } if (header.ih_arch != arch) { printf("uImage arch %d unsupported\n", header.ih_arch); return -1; } switch (header.ih_comp) { case IH_COMP_NONE: #ifdef HAVE_LIBZ case IH_COMP_GZIP: #endif break; default: printf("uImage uses unsupported compression method\n"); return -1; } if (be32_to_cpu(header.ih_size) > len - sizeof(header)) { printf("uImage header claims that image has %d bytes\n", be32_to_cpu(header.ih_size)); printf("we read only %ld bytes.\n", len - sizeof(header)); return -1; } #ifdef HAVE_LIBZ crc = crc32(0, (void *)buf + sizeof(header), be32_to_cpu(header.ih_size)); if (crc != be32_to_cpu(header.ih_dcrc)) { printf("uImage: The data CRC does not match. Computed: %08x " "expected %08x\n", crc, be32_to_cpu(header.ih_dcrc)); return -1; } #endif return (int)header.ih_type; } /* * To conform to the 'probe' routine in file_type struct, * we return : * 0 - If the image is valid 'type' image. * * Now, we have to pass on the 'errors' in the image. So, * * -1 - If the image is corrupted. * 1 - If the image is not a uImage. */ int uImage_probe_kernel(const unsigned char *buf, off_t len, unsigned int arch) { int type = uImage_probe(buf, len, arch); if (type < 0) return -1; return !(type == IH_TYPE_KERNEL || type == IH_TYPE_KERNEL_NOLOAD); } int uImage_probe_ramdisk(const unsigned char *buf, off_t len, unsigned int arch) { int type = uImage_probe(buf, len, arch); if (type < 0) return -1; return !(type == IH_TYPE_RAMDISK); } #ifdef HAVE_LIBZ /* gzip flag byte */ #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ static int uImage_gz_load(const unsigned char *buf, off_t len, struct Image_info *image) { int ret; z_stream strm; unsigned int skip; unsigned int flags; unsigned char *uncomp_buf; unsigned int mem_alloc; mem_alloc = 10 * 1024 * 1024; uncomp_buf = malloc(mem_alloc); if (!uncomp_buf) return -1; memset(&strm, 0, sizeof(strm)); /* Skip magic, method, time, flags, os code ... */ skip = 10; /* check GZ magic */ if (buf[0] != 0x1f || buf[1] != 0x8b) return -1; flags = buf[3]; if (buf[2] != Z_DEFLATED || (flags & RESERVED) != 0) { puts ("Error: Bad gzipped data\n"); return -1; } if (flags & EXTRA_FIELD) { skip += 2; skip += buf[10]; skip += buf[11] << 8; } if (flags & ORIG_NAME) { while (buf[skip++]) ; } if (flags & COMMENT) { while (buf[skip++]) ; } if (flags & HEAD_CRC) skip += 2; strm.avail_in = len - skip; strm.next_in = (void *)buf + skip; /* - activates parsing gz headers */ ret = inflateInit2(&strm, -MAX_WBITS); if (ret != Z_OK) return -1; strm.next_out = uncomp_buf; strm.avail_out = mem_alloc; do { ret = inflate(&strm, Z_FINISH); if (ret == Z_STREAM_END) break; if (ret == Z_OK || ret == Z_BUF_ERROR) { void *new_buf; int inc_buf = 5 * 1024 * 1024; mem_alloc += inc_buf; new_buf = realloc(uncomp_buf, mem_alloc); if (!new_buf) { inflateEnd(&strm); free(uncomp_buf); return -1; } strm.next_out = uncomp_buf + mem_alloc - inc_buf; strm.avail_out = inc_buf; uncomp_buf = new_buf; } else { printf("Error during decompression %d\n", ret); return -1; } } while (1); inflateEnd(&strm); image->buf = uncomp_buf; image->len = mem_alloc - strm.avail_out; return 0; } #else static int uImage_gz_load(const char *UNUSED(buf), off_t UNUSED(len), struct Image_info *UNUSED(image)) { return -1; } #endif int uImage_load(const unsigned char *buf, off_t len, struct Image_info *image) { const struct image_header *header = (const struct image_header *)buf; const unsigned char *img_buf = buf + sizeof(struct image_header); off_t img_len = header->ih_size; /* * Prevent loading a modified image. * CRC check is perfomed only when zlib is compiled * in. This check will help us to detect * size related vulnerabilities. */ if (img_len != (len - sizeof(struct image_header))) { printf("Image size doesn't match the header\n"); return -1; } image->base = cpu_to_be32(header->ih_load); image->ep = cpu_to_be32(header->ih_ep); switch (header->ih_comp) { case IH_COMP_NONE: image->buf = img_buf; image->len = img_len; return 0; break; case IH_COMP_GZIP: /* * uboot doesn't decompress the RAMDISK images. * Comply to the uboot behaviour. */ if (header->ih_type == IH_TYPE_RAMDISK) { image->buf = img_buf; image->len = img_len; return 0; } else return uImage_gz_load(img_buf, img_len, image); break; default: return -1; } } kexec-tools-2.0.10/kexec/fs2dt.c0000644001567400156740000005212412471201644015407 0ustar hormshorms/* * fs2dt: creates a flattened device-tree * * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation * Copyright (C) 2005 R Sharada (sharada@in.ibm.com), IBM 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 (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 #include #include #include #include #include #include #include #include #include "kexec.h" #include "fs2dt.h" #define MAXPATH 1024 /* max path name length */ #define NAMESPACE 16384 /* max bytes for property names */ #define INIT_TREE_WORDS 65536 /* Initial num words for prop values */ #define MEMRESERVE 256 /* max number of reserved memory blocks */ #define MEM_RANGE_CHUNK_SZ 2048 /* Initial num dwords for mem ranges */ static char pathname[MAXPATH], *pathstart; static char propnames[NAMESPACE] = { 0 }; static unsigned *dt_base, *dt; static unsigned int dt_cur_size; static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0ULL, 0ULL }; static int crash_param = 0; static char local_cmdline[COMMAND_LINE_SIZE] = { "" }; extern unsigned char reuse_initrd; /* Used for enabling printing message from purgatory code * Only has implemented for PPC64 */ int my_debug; /* This provides the behaviour of hte existing ppc64 implementation */ static void pad_structure_block(size_t len) { #ifdef NEED_STRUCTURE_BLOCK_EXTRA_PAD if ((len >= 8) && ((unsigned long)dt & 0x4)) dt++; #endif } /* Before we add something to the dt, reserve N words using this. * If there isn't enough room, it's realloced -- and you don't overflow and * splat bits of your heap. */ static void dt_reserve(unsigned **dt_ptr, unsigned words) { unsigned int sz = INIT_TREE_WORDS; if (sz < words) sz = words; if (((*dt_ptr - dt_base) + words) >= dt_cur_size) { int offset; unsigned int new_size = dt_cur_size + sz; unsigned *new_dt = realloc(dt_base, new_size*4); if (!new_dt) die("unrecoverable error: Can't realloc %d bytes for " "device tree\n", new_size*4); offset = *dt_ptr - dt_base; dt_base = new_dt; dt_cur_size = new_size; *dt_ptr = dt_base + offset; memset(*dt_ptr, 0, (new_size - offset)*4); } } void reserve(unsigned long long where, unsigned long long length) { size_t offset; for (offset = 0; be64_to_cpu(mem_rsrv[offset + 1]); offset += 2) ; if (offset + 4 >= 2 * MEMRESERVE) die("unrecoverable error: exhasuted reservation meta data\n"); mem_rsrv[offset] = cpu_to_be64(where); mem_rsrv[offset + 1] = cpu_to_be64(length); mem_rsrv[offset + 2] = mem_rsrv[offset + 3] = cpu_to_be64(0); } /* look for properties we need to reserve memory space for */ static void checkprop(char *name, unsigned *data, int len) { static unsigned long long base, size, end; if ((data == NULL) && (base || size || end)) die("unrecoverable error: no property data"); else if (!strcmp(name, "linux,rtas-base")) base = be32_to_cpu(*data); else if (!strcmp(name, "opal-base-address")) base = be64_to_cpu(*(unsigned long long *)data); else if (!strcmp(name, "opal-runtime-size")) size = be64_to_cpu(*(unsigned long long *)data); else if (!strcmp(name, "linux,tce-base")) base = be64_to_cpu(*(unsigned long long *) data); else if (!strcmp(name, "rtas-size") || !strcmp(name, "linux,tce-size")) size = be32_to_cpu(*data); else if (reuse_initrd && !strcmp(name, "linux,initrd-start")) { if (len == 8) base = be64_to_cpu(*(unsigned long long *) data); else base = be32_to_cpu(*data); } else if (reuse_initrd && !strcmp(name, "linux,initrd-end")) { if (len == 8) end = be64_to_cpu(*(unsigned long long *) data); else end = be32_to_cpu(*data); } if (size && end) die("unrecoverable error: size and end set at same time\n"); if (base && size) { reserve(base, size); base = size = 0; } if (base && end) { reserve(base, end-base); base = end = 0; } } /* * return the property index for a property name, creating a new one * if needed. */ static unsigned propnum(const char *name) { unsigned offset = 0; while(propnames[offset]) if (strcmp(name, propnames+offset)) offset += strlen(propnames+offset)+1; else return offset; if (NAMESPACE - offset < strlen(name) + 1) die("unrecoverable error: propnames overrun\n"); strcpy(propnames+offset, name); return offset; } #ifdef HAVE_DYNAMIC_MEMORY static void add_dyn_reconf_usable_mem_property__(int fd) { char fname[MAXPATH], *bname; uint64_t buf[32]; uint64_t *ranges; int ranges_size = MEM_RANGE_CHUNK_SZ; uint64_t base, end, loc_base, loc_end; size_t i, rngs_cnt, range; int rlen = 0; int tmp_indx; strcpy(fname, pathname); bname = strrchr(fname, '/'); bname[0] = '\0'; bname = strrchr(fname, '/'); if (strncmp(bname, "/ibm,dynamic-reconfiguration-memory", 36)) return; if (lseek(fd, 4, SEEK_SET) < 0) die("unrecoverable error: error seeking in \"%s\": %s\n", pathname, strerror(errno)); ranges = malloc(ranges_size*8); if (!ranges) die("unrecoverable error: can't alloc %d bytes for ranges.\n", ranges_size*8); rlen = 0; for (i = 0; i < num_of_lmbs; i++) { if (read(fd, buf, 24) < 0) die("unrecoverable error: error reading \"%s\": %s\n", pathname, strerror(errno)); base = be64_to_cpu((uint64_t) buf[0]); end = base + lmb_size; if (~0ULL - base < end) die("unrecoverable error: mem property overflow\n"); tmp_indx = rlen++; rngs_cnt = 0; for (range = 0; range < usablemem_rgns.size; range++) { int add = 0; loc_base = usablemem_rgns.ranges[range].start; loc_end = usablemem_rgns.ranges[range].end; if (loc_base >= base && loc_end <= end) { add = 1; } else if (base < loc_end && end > loc_base) { if (loc_base < base) loc_base = base; if (loc_end > end) loc_end = end; add = 1; } if (add) { if (rlen >= (ranges_size-2)) { ranges_size += MEM_RANGE_CHUNK_SZ; ranges = realloc(ranges, ranges_size*8); if (!ranges) die("unrecoverable error: can't" " realloc %d bytes for" " ranges.\n", ranges_size*8); } ranges[rlen++] = cpu_to_be64(loc_base); ranges[rlen++] = cpu_to_be64(loc_end - loc_base); rngs_cnt++; } } if (rngs_cnt == 0) { /* We still need to add a counter for every LMB because * the kernel parsing code is dumb. We just have * a zero in this case, with no following base/len. */ ranges[tmp_indx] = 0; /* rlen is already just tmp_indx+1 as we didn't write * anything. Check array size here, as we'll probably * go on for a while writing zeros now. */ if (rlen >= (ranges_size-1)) { ranges_size += MEM_RANGE_CHUNK_SZ; ranges = realloc(ranges, ranges_size*8); if (!ranges) die("unrecoverable error: can't" " realloc %d bytes for" " ranges.\n", ranges_size*8); } } else { /* Store the count of (base, size) duple */ ranges[tmp_indx] = cpu_to_be64((uint64_t) rngs_cnt); } } rlen = rlen * sizeof(uint64_t); /* * Add linux,drconf-usable-memory property. */ dt_reserve(&dt, 4+((rlen + 3)/4)); *dt++ = cpu_to_be32(3); *dt++ = cpu_to_be32(rlen); *dt++ = cpu_to_be32(propnum("linux,drconf-usable-memory")); pad_structure_block(rlen); memcpy(dt, ranges, rlen); free(ranges); dt += (rlen + 3)/4; } static void add_dyn_reconf_usable_mem_property(struct dirent *dp, int fd) { if (!strcmp(dp->d_name, "ibm,dynamic-memory") && usablemem_rgns.size) add_dyn_reconf_usable_mem_property__(fd); } #else static void add_dyn_reconf_usable_mem_property(struct dirent *dp, int fd) {} #endif static void add_usable_mem_property(int fd, size_t len) { char fname[MAXPATH], *bname; uint64_t buf[2]; uint64_t *ranges; int ranges_size = MEM_RANGE_CHUNK_SZ; uint64_t base, end, loc_base, loc_end; size_t range; int rlen = 0; strcpy(fname, pathname); bname = strrchr(fname,'/'); bname[0] = '\0'; bname = strrchr(fname,'/'); if (strncmp(bname, "/memory@", 8) && strcmp(bname, "/memory")) return; if (len < sizeof(buf)) die("unrecoverable error: not enough data for mem property\n"); if (lseek(fd, 0, SEEK_SET) < 0) die("unrecoverable error: error seeking in \"%s\": %s\n", pathname, strerror(errno)); if (read(fd, buf, sizeof(buf)) != sizeof(buf)) die("unrecoverable error: error reading \"%s\": %s\n", pathname, strerror(errno)); base = be64_to_cpu(buf[0]); end = be64_to_cpu(buf[1]); if (~0ULL - base < end) die("unrecoverable error: mem property overflow\n"); end += base; ranges = malloc(ranges_size * sizeof(*ranges)); if (!ranges) die("unrecoverable error: can't alloc %zu bytes for ranges.\n", ranges_size * sizeof(*ranges)); for (range = 0; range < usablemem_rgns.size; range++) { int add = 0; loc_base = usablemem_rgns.ranges[range].start; loc_end = usablemem_rgns.ranges[range].end; if (loc_base >= base && loc_end <= end) { add = 1; } else if (base < loc_end && end > loc_base) { if (loc_base < base) loc_base = base; if (loc_end > end) loc_end = end; add = 1; } if (add) { if (rlen >= (ranges_size-2)) { ranges_size += MEM_RANGE_CHUNK_SZ; ranges = realloc(ranges, ranges_size * sizeof(*ranges)); if (!ranges) die("unrecoverable error: can't realloc" "%zu bytes for ranges.\n", ranges_size*sizeof(*ranges)); } ranges[rlen++] = cpu_to_be64(loc_base); ranges[rlen++] = cpu_to_be64(loc_end - loc_base); } } if (!rlen) { /* * User did not pass any ranges for thsi region. Hence, write * (0,0) duple in linux,usable-memory property such that * this region will be ignored. */ ranges[rlen++] = 0; ranges[rlen++] = 0; } rlen = rlen * sizeof(*ranges); /* * No add linux,usable-memory property. */ dt_reserve(&dt, 4+((rlen + 3)/4)); *dt++ = cpu_to_be32(3); *dt++ = cpu_to_be32(rlen); *dt++ = cpu_to_be32(propnum("linux,usable-memory")); pad_structure_block(rlen); memcpy(dt, ranges, rlen); free(ranges); dt += (rlen + 3)/4; } /* put all properties (files) in the property structure */ static void putprops(char *fn, struct dirent **nlist, int numlist) { struct dirent *dp; int i = 0, fd; off_t len; off_t slen; struct stat statbuf; for (i = 0; i < numlist; i++) { dp = nlist[i]; strcpy(fn, dp->d_name); if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; /* Empirically, this seems to need to be ecluded. * Observed on ARM with 3.6-rc2 kernel */ if (!strcmp(dp->d_name, "name")) continue; if (lstat(pathname, &statbuf)) die("unrecoverable error: could not stat \"%s\": %s\n", pathname, strerror(errno)); if (!crash_param && !strcmp(fn,"linux,crashkernel-base")) continue; if (!crash_param && !strcmp(fn,"linux,crashkernel-size")) continue; /* * This property will be created for each node during kexec * boot. So, ignore it. */ if (!strcmp(dp->d_name, "linux,pci-domain") || !strcmp(dp->d_name, "linux,htab-base") || !strcmp(dp->d_name, "linux,htab-size") || !strcmp(dp->d_name, "linux,kernel-end")) continue; /* This property will be created/modified later in putnode() * So ignore it, unless we are reusing the initrd. */ if ((!strcmp(dp->d_name, "linux,initrd-start") || !strcmp(dp->d_name, "linux,initrd-end")) && !reuse_initrd) continue; /* This property will be created later in putnode() So * ignore it now. */ if (!strcmp(dp->d_name, "bootargs")) continue; if (! S_ISREG(statbuf.st_mode)) continue; len = statbuf.st_size; dt_reserve(&dt, 4+((len + 3)/4)); *dt++ = cpu_to_be32(3); *dt++ = cpu_to_be32(len); *dt++ = cpu_to_be32(propnum(fn)); pad_structure_block(len); if (len) { char *buf; buf = slurp_file_len(pathname, len, &slen); if (slen != len) die("unrecoverable error: short read from\"%s\"\n", pathname); memcpy(dt, buf, slen); free(buf); } checkprop(fn, dt, len); dt += (len + 3)/4; fd = open(pathname, O_RDONLY); if (fd == -1) die("unrecoverable error: could not open \"%s\": %s\n", pathname, strerror(errno)); if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size) add_usable_mem_property(fd, len); add_dyn_reconf_usable_mem_property(dp, fd); close(fd); } fn[0] = '\0'; checkprop(pathname, NULL, 0); } /* * Compare function used to sort the device-tree directories * This function will be passed to scandir. */ static int comparefunc(const struct dirent **dentry1, const struct dirent **dentry2) { char *str1 = (*(struct dirent **)dentry1)->d_name; char *str2 = (*(struct dirent **)dentry2)->d_name; char *sep1 = strchr(str1, '@'); char *sep2 = strchr(str2, '@'); /* * strcmp scans from left to right and fails to idetify for some * strings such as memory@10000000 and memory@f000000. * Therefore, we get the wrong sorted order like memory@10000000 and * memory@f000000. */ if (sep1 && sep2) { int baselen1 = sep1 - str1; int baselen2 = sep2 - str2; int len1 = strlen(str1); int len2 = strlen(str2); /* * Check the base name matches, and the properties are * different lengths. */ if ((baselen1 == baselen2) && (len1 != len2) && !strncmp(str1, str2, baselen2)) return (len1 > len2) - (len1 < len2); } return strcmp(str1, str2); } /* * put a node (directory) in the property structure. first properties * then children. */ static void putnode(void) { char *dn; struct dirent *dp; char *basename; struct dirent **namelist; int numlist, i; struct stat statbuf; int plen; numlist = scandir(pathname, &namelist, 0, comparefunc); if (numlist < 0) die("unrecoverable error: could not scan \"%s\": %s\n", pathname, strerror(errno)); if (numlist == 0) die("unrecoverable error: no directory entries in \"%s\"", pathname); basename = strrchr(pathname,'/') + 1; plen = *basename ? strlen(basename) : 0; /* Reserve space for string packed to words; e.g. string length 10 * occupies 3 words, length 12 occupies 4 (for terminating \0s). * So round up & include the \0: */ dt_reserve(&dt, 1+((plen + 4)/4)); *dt++ = cpu_to_be32(1); strcpy((void *)dt, *basename ? basename : ""); dt += ((plen + 4)/4); strcat(pathname, "/"); dn = pathname + strlen(pathname); putprops(dn, namelist, numlist); /* Add initrd entries to the second kernel */ if (initrd_base && initrd_size && !strcmp(basename,"chosen/")) { int len = 8; uint64_t bevalue; dt_reserve(&dt, 12); /* both props, of 6 words ea. */ *dt++ = cpu_to_be32(3); *dt++ = cpu_to_be32(len); *dt++ = cpu_to_be32(propnum("linux,initrd-start")); pad_structure_block(len); bevalue = cpu_to_be64(initrd_base); memcpy(dt, &bevalue, len); dt += (len + 3)/4; len = 8; *dt++ = cpu_to_be32(3); *dt++ = cpu_to_be32(len); *dt++ = cpu_to_be32(propnum("linux,initrd-end")); bevalue = cpu_to_be64(initrd_base + initrd_size); pad_structure_block(len); memcpy(dt, &bevalue, len); dt += (len + 3)/4; reserve(initrd_base, initrd_size); } /* Add cmdline to the second kernel. Check to see if the new * cmdline has a root=. If not, use the old root= cmdline. */ if (!strcmp(basename,"chosen/")) { size_t result; size_t cmd_len = 0; char *param = NULL; char filename[MAXPATH]; char *buff; int fd; cmd_len = strlen(local_cmdline); if (cmd_len != 0) { param = strstr(local_cmdline, "crashkernel="); if (param) crash_param = 1; /* does the new cmdline have a root= ? ... */ param = strstr(local_cmdline, "root="); } /* ... if not, grab root= from the old command line */ if (!param) { FILE *fp; char *last_cmdline = NULL; char *old_param; strcpy(filename, pathname); strcat(filename, "bootargs"); fp = fopen(filename, "r"); if (fp) { if (getline(&last_cmdline, &cmd_len, fp) == -1) die("unable to read %s\n", filename); param = strstr(last_cmdline, "root="); if (param) { old_param = strtok(param, " "); if (cmd_len != 0) strcat(local_cmdline, " "); strcat(local_cmdline, old_param); } } if (last_cmdline) free(last_cmdline); } strcat(local_cmdline, " "); cmd_len = strlen(local_cmdline); cmd_len = cmd_len + 1; /* add new bootargs */ dt_reserve(&dt, 4+((cmd_len+3)/4)); *dt++ = cpu_to_be32(3); *dt++ = cpu_to_be32(cmd_len); *dt++ = cpu_to_be32(propnum("bootargs")); pad_structure_block(cmd_len); memcpy(dt, local_cmdline,cmd_len); dt += (cmd_len + 3)/4; fprintf(stderr, "Modified cmdline:%s\n", local_cmdline); /* * Determine the platform type/stdout type, so that purgatory * code can print 'I'm in purgatory' message. Currently only * pseries/hvcterminal is supported. */ snprintf(filename, MAXPATH, "%slinux,stdout-path", pathname); fd = open(filename, O_RDONLY); if (fd == -1) { printf("Unable to find %s, printing from purgatory is diabled\n", filename); goto no_debug; } if (fstat(fd, &statbuf)) { printf("Unable to stat %s, printing from purgatory is diabled\n", filename); close(fd); goto no_debug; } buff = malloc(statbuf.st_size); if (!buff) { printf("Can not allocate memory for buff\n"); close(fd); goto no_debug; } result = read(fd, buff, statbuf.st_size); close(fd); if (result <= 0) { printf("Unable to read %s, printing from purgatory is diabled\n", filename); goto no_debug; } snprintf(filename, MAXPATH, "/proc/device-tree/%s/compatible", buff); fd = open(filename, O_RDONLY); if (fd == -1) { printf("Unable to find %s printing from purgatory is diabled\n", filename); goto no_debug; } if (fstat(fd, &statbuf)) { printf("Unable to stat %s printing from purgatory is diabled\n", filename); close(fd); goto no_debug; } buff = realloc(buff, statbuf.st_size); if (!buff) { printf("Can not allocate memory for buff\n"); close(fd); goto no_debug; } result = read(fd, buff, statbuf.st_size); if (result && (!strcmp(buff, "hvterm1") || !strcmp(buff, "hvterm-protocol"))) my_debug = 1; close(fd); free(buff); } no_debug: for (i=0; i < numlist; i++) { dp = namelist[i]; strcpy(dn, dp->d_name); free(namelist[i]); if (!strcmp(dn, ".") || !strcmp(dn, "..")) continue; if (lstat(pathname, &statbuf)) die("unrecoverable error: could not stat \"%s\": %s\n", pathname, strerror(errno)); if (S_ISDIR(statbuf.st_mode)) putnode(); } dt_reserve(&dt, 1); *dt++ = cpu_to_be32(2); dn[-1] = '\0'; free(namelist); } struct bootblock bb[1]; static void add_boot_block(char **bufp, off_t *sizep) { unsigned long len; unsigned long tlen, toff; char *buf; len = _ALIGN(sizeof(bb[0]), 8); bb->off_mem_rsvmap = cpu_to_be32(len); for (len = 1; be64_to_cpu(mem_rsrv[len]); len += 2) ; len++; #ifdef NEED_RESERVE_DTB len+= 3; /* Leave space for totalsize reservation */ #endif len *= sizeof(mem_rsrv[0]); bb->off_dt_struct = cpu_to_be32(be32_to_cpu(bb->off_mem_rsvmap) + len); len = dt - dt_base; len *= sizeof(unsigned); #if (BOOT_BLOCK_VERSION >= 17) bb->dt_struct_size = cpu_to_be32(len); #endif bb->off_dt_strings = cpu_to_be32(be32_to_cpu(bb->off_dt_struct) + len); len = propnum(""); bb->dt_strings_size = cpu_to_be32(len); len = _ALIGN(len, 4); bb->totalsize = cpu_to_be32(be32_to_cpu(bb->off_dt_strings) + len); bb->magic = cpu_to_be32(0xd00dfeed); bb->version = cpu_to_be32(BOOT_BLOCK_VERSION); bb->last_comp_version = cpu_to_be32(BOOT_BLOCK_LAST_COMP_VERSION); #ifdef NEED_RESERVE_DTB reserve(0, be32_to_cpu(bb->totalsize)); /* patched later in kexec_load */ #endif buf = malloc(be32_to_cpu(bb->totalsize)); *bufp = buf; tlen = be32_to_cpu(bb->off_mem_rsvmap); memcpy(buf, bb, tlen); toff = be32_to_cpu(bb->off_mem_rsvmap); tlen = be32_to_cpu(bb->off_dt_struct) - be32_to_cpu(bb->off_mem_rsvmap); memcpy(buf + toff, mem_rsrv, tlen); toff += be32_to_cpu(bb->off_dt_struct) - be32_to_cpu(bb->off_mem_rsvmap); tlen = be32_to_cpu(bb->off_dt_strings) - be32_to_cpu(bb->off_dt_struct); memcpy(buf + toff, dt_base, tlen); toff += be32_to_cpu(bb->off_dt_strings) - be32_to_cpu(bb->off_dt_struct); tlen = be32_to_cpu(bb->totalsize) - be32_to_cpu(bb->off_dt_strings); memcpy(buf + toff, propnames, tlen); *sizep = toff + be32_to_cpu(bb->totalsize) - be32_to_cpu(bb->off_dt_strings); } void create_flatten_tree(char **bufp, off_t *sizep, const char *cmdline) { strcpy(pathname, "/proc/device-tree/"); pathstart = pathname + strlen(pathname); dt_cur_size = INIT_TREE_WORDS; dt_base = malloc(dt_cur_size*4); if (!dt_base) { die("Can't malloc %d bytes for dt struct!\n", dt_cur_size*4); } memset(dt_base, 0, dt_cur_size*4); dt = dt_base; if (cmdline) strcpy(local_cmdline, cmdline); putnode(); dt_reserve(&dt, 1); *dt++ = cpu_to_be32(9); add_boot_block(bufp, sizep); free(dt_base); } kexec-tools-2.0.10/kexec/fs2dt.h0000644001567400156740000000163612242534555015424 0ustar hormshorms#ifndef FS2DT_H #define FS2DT_H #if (BOOT_BLOCK_VERSION != 2 && BOOT_BLOCK_VERSION != 17) #error Please add or correct definition of BOOT_BLOCK_VERSION #endif /* boot block as defined by the linux kernel */ struct bootblock { unsigned magic; unsigned totalsize; unsigned off_dt_struct; unsigned off_dt_strings; unsigned off_mem_rsvmap; unsigned version; unsigned last_comp_version; #if (BOOT_BLOCK_VERSION >= 2) /* version 2 fields below */ unsigned boot_physid; /* version 3 fields below */ unsigned dt_strings_size; #if (BOOT_BLOCK_VERSION >= 17) /* version 17 fields below */ unsigned dt_struct_size; #endif #endif }; extern struct bootblock bb[1]; /* Used for enabling printing message from purgatory code * Only has implemented for PPC64 */ int my_debug; void reserve(unsigned long long where, unsigned long long length); void create_flatten_tree(char **, off_t *, const char *); #endif /* KEXEC_H */ kexec-tools-2.0.10/kexec/arch/alpha/Makefile0000644001567400156740000000017111424244110017646 0ustar hormshormsalpha_KEXEC_SRCS= dist += kexec/arch/alpha/Makefile kexec/arch/alpha/include/arch/options.h $(alpha_KEXEC_SRCS) kexec-tools-2.0.10/kexec/arch/alpha/include/arch/options.h0000644001567400156740000000102411642166046022425 0ustar hormshorms#ifndef KEXEC_ARCH_ALPHA_OPTIONS_H #define KEXEC_ARCH_ALPHA_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* See the other architectures for details of these; Alpha has no * loader-specific options yet. */ #define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR #endif /* KEXEC_ARCH_ALPHA_OPTIONS_H */ kexec-tools-2.0.10/kexec/libfdt/Makefile.libfdt0000644001567400156740000000067212242534555020377 0ustar hormshorms# Makefile.libfdt # # This is not a complete Makefile of itself. Instead, it is designed to # be easily embeddable into other systems of Makefiles. # LIBFDT_INCLUDES = fdt.h libfdt.h LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) dist += kexec/libfdt/Makefile.libfdt \ kexec/libfdt/fdt.h kexec/libfdt/libfdt.h \ kexec/libfdt/libfdt_env.h \ kexec/libfdt/libfdt_internal.h kexec-tools-2.0.10/kexec/libfdt/fdt.h0000644001567400156740000000302512242534555016415 0ustar hormshorms#ifndef _FDT_H #define _FDT_H #ifndef __ASSEMBLY__ struct fdt_header { uint32_t magic; /* magic word FDT_MAGIC */ uint32_t totalsize; /* total size of DT block */ uint32_t off_dt_struct; /* offset to structure */ uint32_t off_dt_strings; /* offset to strings */ uint32_t off_mem_rsvmap; /* offset to memory reserve map */ uint32_t version; /* format version */ uint32_t last_comp_version; /* last compatible version */ /* version 2 fields below */ uint32_t boot_cpuid_phys; /* Which physical CPU id we're booting on */ /* version 3 fields below */ uint32_t size_dt_strings; /* size of the strings block */ /* version 17 fields below */ uint32_t size_dt_struct; /* size of the structure block */ }; struct fdt_reserve_entry { uint64_t address; uint64_t size; }; struct fdt_node_header { uint32_t tag; char name[0]; }; struct fdt_property { uint32_t tag; uint32_t len; uint32_t nameoff; char data[0]; }; #endif /* !__ASSEMBLY */ #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ #define FDT_TAGSIZE sizeof(uint32_t) #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ #define FDT_END_NODE 0x2 /* End node */ #define FDT_PROP 0x3 /* Property: name off, size, content */ #define FDT_NOP 0x4 /* nop */ #define FDT_END 0x9 #define FDT_V1_SIZE (7*sizeof(uint32_t)) #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t)) #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t)) #define FDT_V16_SIZE FDT_V3_SIZE #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t)) #endif /* _FDT_H */ kexec-tools-2.0.10/kexec/libfdt/libfdt.h0000644001567400156740000012010512417126536017103 0ustar hormshorms#ifndef _LIBFDT_H #define _LIBFDT_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #define FDT_FIRST_SUPPORTED_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 /* FDT_ERR_EXISTS: Attemped to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device * tree, but its buffer did not have sufficient space to * contain the expanded tree. Use fdt_open_into() to move the * device tree to a buffer with more space. */ /* Error codes: codes for bad parameters */ #define FDT_ERR_BADOFFSET 4 /* FDT_ERR_BADOFFSET: Function was passed a structure block * offset which is out-of-bounds, or which points to an * unsuitable part of the structure for the operation. */ #define FDT_ERR_BADPATH 5 /* FDT_ERR_BADPATH: Function was passed a badly formatted path * (e.g. missing a leading / for a function which requires an * absolute path) */ #define FDT_ERR_BADPHANDLE 6 /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle * value. phandle values of 0 and -1 are not permitted. */ #define FDT_ERR_BADSTATE 7 /* FDT_ERR_BADSTATE: Function was passed an incomplete device * tree created by the sequential-write functions, which is * not sufficiently complete for the requested operation. */ /* Error codes: codes for bad device tree blobs */ #define FDT_ERR_TRUNCATED 8 /* FDT_ERR_TRUNCATED: Structure block of the given device tree * ends without an FDT_END tag. */ #define FDT_ERR_BADMAGIC 9 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a * device tree at all - it is missing the flattened device * tree magic number. */ #define FDT_ERR_BADVERSION 10 /* FDT_ERR_BADVERSION: Given device tree has a version which * can't be handled by the requested operation. For * read-write functions, this may mean that fdt_open_into() is * required to convert the tree to the expected version. */ #define FDT_ERR_BADSTRUCTURE 11 /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt * structure block or other serious error (e.g. misnested * nodes, or subnodes preceding properties). */ #define FDT_ERR_BADLAYOUT 12 /* FDT_ERR_BADLAYOUT: For read-write functions, the given * device tree has it's sub-blocks in an order that the * function can't handle (memory reserve map, then structure, * then strings). Use fdt_open_into() to reorganize the tree * into a form suitable for the read-write operations. */ /* "Can't happen" error indicating a bug in libfdt */ #define FDT_ERR_INTERNAL 13 /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. * Should never be returned, if it is, it indicates a bug in * libfdt itself. */ #define FDT_ERR_MAX 13 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ /**********************************************************************/ const void *fdt_offset_ptr(const void *fdt, int offset, int checklen); static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) { return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); } uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); /**********************************************************************/ /* Traversal functions */ /**********************************************************************/ int fdt_next_node(const void *fdt, int offset, int *depth); /**********************************************************************/ /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) #define fdt_version(fdt) (fdt_get_header(fdt, version)) #define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) #define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) #define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define __fdt_set_hdr(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ struct fdt_header *fdth = fdt; \ fdth->name = cpu_to_fdt32(val); \ } __fdt_set_hdr(magic); __fdt_set_hdr(totalsize); __fdt_set_hdr(off_dt_struct); __fdt_set_hdr(off_dt_strings); __fdt_set_hdr(off_mem_rsvmap); __fdt_set_hdr(version); __fdt_set_hdr(last_comp_version); __fdt_set_hdr(boot_cpuid_phys); __fdt_set_hdr(size_dt_strings); __fdt_set_hdr(size_dt_struct); #undef __fdt_set_hdr /** * fdt_check_header - sanity check a device tree or possible device tree * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what * appears to be a flattened device tree with sane information in its * header. * * returns: * 0, if the buffer appears to contain a valid device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings, as above */ int fdt_check_header(const void *fdt); /** * fdt_move - move a device tree around in memory * @fdt: pointer to the device tree to move * @buf: pointer to memory where the device is to be moved * @bufsize: size of the memory space at buf * * fdt_move() relocates, if possible, the device tree blob located at * fdt to the buffer at buf of size bufsize. The buffer may overlap * with the existing device tree blob at fdt. Therefore, * fdt_move(fdt, fdt, fdt_totalsize(fdt)) * should always succeed. * * returns: * 0, on success * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_move(const void *fdt, void *buf, int bufsize); /**********************************************************************/ /* Read-only functions */ /**********************************************************************/ /** * fdt_string - retrieve a string from the strings block of a device tree * @fdt: pointer to the device tree blob * @stroffset: offset of the string within the strings block (native endian) * * fdt_string() retrieves a pointer to a single string from the * strings block of the device tree blob at fdt. * * returns: * a pointer to the string, on success * NULL, if stroffset is out of bounds */ const char *fdt_string(const void *fdt, int stroffset); /** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob * * Returns the number of entries in the device tree blob's memory * reservation map. This does not include the terminating 0,0 entry * or any other (0,0) entries reserved for expansion. * * returns: * the number of entries */ int fdt_num_mem_rsv(const void *fdt); /** * fdt_get_mem_rsv - retrieve one memory reserve map entry * @fdt: pointer to the device tree blob * @address, @size: pointers to 64-bit variables * * On success, *address and *size will contain the address and size of * the n-th reserve map entry from the device tree blob, in * native-endian format. * * returns: * 0, on success * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); /** * fdt_subnode_offset_namelen - find a subnode based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * @namelen: number of characters of name to consider * * Identical to fdt_subnode_offset(), but only examine the first * namelen characters of name for matching the subnode name. This is * useful for finding subnodes based on a portion of a larger string, * such as a full path. */ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, const char *name, int namelen); /** * fdt_subnode_offset - find a subnode of a given node * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * * fdt_subnode_offset() finds a subnode of the node at structure block * offset parentoffset with the given name. name may include a unit * address, in which case fdt_subnode_offset() will find the subnode * with that unit address, or the unit address may be omitted, in * which case fdt_subnode_offset() will find an arbitrary subnode * whose name excluding unit address matches the given name. * * returns: * structure block offset of the requested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); /** * fdt_path_offset - find a tree node by its full path * @fdt: pointer to the device tree blob * @path: full path of the node to locate * * fdt_path_offset() finds a node of a given path in the device tree. * Each path component may omit the unit address portion, but the * results of this are undefined if any such path component is * ambiguous (that is if there are multiple nodes at the relevant * level matching the given component, differentiated only by unit * address). * * returns: * structure block offset of the node with the requested path (>=0), on success * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_path_offset(const void *fdt, const char *path); /** * fdt_get_name - retrieve the name of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the starting node * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_name() retrieves the name (including unit address) of the * device tree node at structure block offset nodeoffset. If lenp is * non-NULL, the length of this name is also returned, in the integer * pointed to by lenp. * * returns: * pointer to the node's name, on success * If lenp is non-NULL, *lenp contains the length of that name (>=0) * NULL, on error * if lenp is non-NULL *lenp contains an error code (<0): * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); /** * fdt_get_property - find a given property in a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_property() retrieves a pointer to the fdt_property * structure within the device tree blob corresponding to the property * named 'name' of the node at offset nodeoffset. If lenp is * non-NULL, the length of the property value is also returned, in the * integer pointed to by lenp. * * returns: * pointer to the structure representing the property * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp); static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, const char *name, int *lenp) { return (struct fdt_property *)(uintptr_t) fdt_get_property(fdt, nodeoffset, name, lenp); } /** * fdt_getprop - retrieve the value of a given property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop() retrieves a pointer to the value of the property * named 'name' of the node at offset nodeoffset (this will be a * pointer to within the device blob itself, not a copy of the value). * If lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. * * returns: * pointer to the property's value * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp); static inline void *fdt_getprop_w(void *fdt, int nodeoffset, const char *name, int *lenp) { return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); } /** * fdt_get_phandle - retrieve the phandle of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the node * * fdt_get_phandle() retrieves the phandle of the device tree node at * structure block offset nodeoffset. * * returns: * the phandle of the node at nodeoffset, on success (!= 0, != -1) * 0, if the node has no phandle, or another error occurs */ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); /** * fdt_get_path - determine the full path of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose path to find * @buf: character buffer to contain the returned path (will be overwritten) * @buflen: size of the character buffer at buf * * fdt_get_path() computes the full path of the node at offset * nodeoffset, and records that path in the buffer at buf. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * 0, on success * buf contains the absolute path of the node at * nodeoffset, as a NUL-terminated string. * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) * characters and will not fit in the given buffer. * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); /** * fdt_supernode_atdepth_offset - find a specific ancestor of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * @supernodedepth: depth of the ancestor to find * @nodedepth: pointer to an integer variable (will be overwritten) or NULL * * fdt_supernode_atdepth_offset() finds an ancestor of the given node * at a specific depth from the root (where the root itself has depth * 0, its immediate subnodes depth 1 and so forth). So * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); * will always return 0, the offset of the root node. If the node at * nodeoffset has depth D, then: * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); * will return nodeoffset itself. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth); /** * fdt_node_depth - find the depth of a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * * fdt_node_depth() finds the depth of a given node. The root node * has depth 0, its immediate subnodes depth 1 and so forth. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * depth of the node at nodeoffset (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_depth(const void *fdt, int nodeoffset); /** * fdt_parent_offset - find the parent of a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * * fdt_parent_offset() locates the parent node of a given node (that * is, it finds the offset of the node which contains the node at * nodeoffset as a subnode). * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset, *twice*. * * returns: * structure block offset of the parent of the node at nodeoffset * (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_parent_offset(const void *fdt, int nodeoffset); /** * fdt_node_offset_by_prop_value - find nodes with a given property value * @fdt: pointer to the device tree blob * @startoffset: only find nodes after this offset * @propname: property name to check * @propval: property value to search for * @proplen: length of the value in propval * * fdt_node_offset_by_prop_value() returns the offset of the first * node after startoffset, which has a property named propname whose * value is of length proplen and has value equal to propval; or if * startoffset is -1, the very first such node in the tree. * * To iterate through all nodes matching the criterion, the following * idiom can be used: * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, * propval, proplen); * while (offset != -FDT_ERR_NOTFOUND) { * // other code here * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, * propval, proplen); * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: * structure block offset of the located node (>= 0, >startoffset), * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen); /** * fdt_node_offset_by_phandle - find the node with a given phandle * @fdt: pointer to the device tree blob * @phandle: phandle value * * fdt_node_offset_by_phandle() returns the offset of the node * which has the given phandle value. If there is more than one node * in the tree with the given phandle (an invalid tree), results are * undefined. * * returns: * structure block offset of the located node (>= 0), on success * -FDT_ERR_NOTFOUND, no node with that phandle exists * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); /** * fdt_node_check_compatible: check a node's compatible property * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @compatible: string to match against * * * fdt_node_check_compatible() returns 0 if the given node contains a * 'compatible' property with the given string as one of its elements, * it returns non-zero otherwise, or on error. * * returns: * 0, if the node has a 'compatible' property listing the given string * 1, if the node has a 'compatible' property, but it does not list * the given string * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible); /** * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value * @fdt: pointer to the device tree blob * @startoffset: only find nodes after this offset * @compatible: 'compatible' string to match against * * fdt_node_offset_by_compatible() returns the offset of the first * node after startoffset, which has a 'compatible' property which * lists the given compatible string; or if startoffset is -1, the * very first such node in the tree. * * To iterate through all nodes matching the criterion, the following * idiom can be used: * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); * while (offset != -FDT_ERR_NOTFOUND) { * // other code here * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: * structure block offset of the located node (>= 0, >startoffset), * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible); /**********************************************************************/ /* Write-in-place functions */ /**********************************************************************/ /** * fdt_setprop_inplace - change a property's value, but not its size * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: pointer to data to replace the property value with * @len: length of the property value * * fdt_setprop_inplace() replaces the value of a given property with * the data in val, of length len. This function cannot change the * size of a property, and so will only work if len is equal to the * current length of the property. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if len is not equal to the property's current length * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** * fdt_setprop_inplace_cell - change the value of a single-cell property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: cell (32-bit integer) value to replace the property with * * fdt_setprop_inplace_cell() replaces the value of a given property * with the 32-bit integer cell value in val, converting val to * big-endian if necessary. This function cannot change the size of a * property, and so will only work if the property already exists and * has length 4. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val)); } /** * fdt_nop_property - replace a property with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * * fdt_nop_property() will replace a given property's representation * in the blob with FDT_NOP tags, effectively removing it from the * tree. * * This function will alter only the bytes in the blob which contain * the property, and will not alter or move any other part of the * tree. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_property(void *fdt, int nodeoffset, const char *name); /** * fdt_nop_node - replace a node (subtree) with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to nop * * fdt_nop_node() will replace a given node's representation in the * blob, including all its subnodes, if any, with FDT_NOP tags, * effectively removing it from the tree. * * This function will alter only the bytes in the blob which contain * the node and its properties and subnodes, and will not alter or * move any other part of the tree. * * returns: * 0, on success * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_node(void *fdt, int nodeoffset); /**********************************************************************/ /* Sequential write functions */ /**********************************************************************/ int fdt_create(void *buf, int bufsize); int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_property(fdt, name, &val, sizeof(val)); } #define fdt_property_string(fdt, name, str) \ fdt_property(fdt, name, str, strlen(str)+1) int fdt_end_node(void *fdt); int fdt_finish(void *fdt); /**********************************************************************/ /* Read-write functions */ /**********************************************************************/ int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); /** * fdt_add_mem_rsv - add one memory reserve map entry * @fdt: pointer to the device tree blob * @address, @size: 64-bit values (native endian) * * Adds a reserve map entry to the given blob reserving a region at * address address of length size. * * This function will insert data into the reserve map and will * therefore change the indexes of some entries in the table. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new reservation entry * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); /** * fdt_del_mem_rsv - remove a memory reserve map entry * @fdt: pointer to the device tree blob * @n: entry to remove * * fdt_del_mem_rsv() removes the n-th memory reserve map entry from * the blob. * * This function will delete data from the reservation table and will * therefore change the indexes of some entries in the table. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there * are less than n+1 reserve map entries) * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_mem_rsv(void *fdt, int n); /** * fdt_set_name - change the name of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of a node * @name: name to give the node * * fdt_set_name() replaces the name (including unit address, if any) * of the given node with the given string. NOTE: this function can't * efficiently check if the new name is unique amongst the given * node's siblings; results are undefined if this function is invoked * with a name equal to one of the given node's siblings. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob * to contain the new name * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_set_name(void *fdt, int nodeoffset, const char *name); /** * fdt_setprop - create or change a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: pointer to data to set the property value to * @len: length of the property value * * fdt_setprop() sets the value of the named property in the given * node to the given value and length, creating the property if it * does not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** * fdt_setprop_cell - set a property to a single cell value * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value for the property (native endian) * * fdt_setprop_cell() sets the value of the named property in the * given node to the given cell value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { val = cpu_to_fdt32(val); return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val)); } /** * fdt_setprop_string - set a property to a string value * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @str: string value for the property * * fdt_setprop_string() sets the value of the named property in the * given node to the given string value (using the length of the * string to determine the new length of the property), or creates a * new property with that value if it does not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_setprop_string(fdt, nodeoffset, name, str) \ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** * fdt_delprop - delete a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * * fdt_del_property() will delete the given property. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_delprop(void *fdt, int nodeoffset, const char *name); /** * fdt_add_subnode_namelen - creates a new node based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * @namelen: number of characters of name to consider * * Identical to fdt_add_subnode(), but use only the first namelen * characters of name as the name of the new node. This is useful for * creating subnodes based on a portion of a larger string, such as a * full path. */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, const char *name, int namelen); /** * fdt_add_subnode - creates a new node * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * * fdt_add_subnode() creates a new node as a subnode of the node at * structure block offset parentoffset, with the given name (which * should include the unit address, if any). * * This function will insert data into the blob, and will therefore * change the offsets of some existing nodes. * returns: * structure block offset of the created nodeequested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of * the given name * -FDT_ERR_NOSPACE, if there is insufficient free space in the * blob to contain the new node * -FDT_ERR_NOSPACE * -FDT_ERR_BADLAYOUT * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); /** * fdt_del_node - delete a node (subtree) * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to nop * * fdt_del_node() will remove the given node, including all its * subnodes if any, from the blob. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_node(void *fdt, int nodeoffset); /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ const char *fdt_strerror(int errval); #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) /* * if add a new subnode: * see: fdt_add_subnode -> fdt_add_subnode_namelen */ static inline int fdt_node_len(const char* node_name) { return sizeof(struct fdt_node_header) + FDT_TAGALIGN(strlen(node_name) + 1) + FDT_TAGSIZE; } /* * if add a new prop: (assume prop_name not exist in strtab) * see: fdt_setprop -> _fdt_add_property */ static inline int fdt_prop_len(const char* prop_name, int len) { return (strlen(prop_name) + 1) + sizeof(struct fdt_property) + FDT_TAGALIGN(len); } #endif /* _LIBFDT_H */ kexec-tools-2.0.10/kexec/libfdt/libfdt_env.h0000644001567400156740000000107612242534555017760 0ustar hormshorms#ifndef _LIBFDT_ENV_H #define _LIBFDT_ENV_H #include #include #include #define _B(n) ((unsigned long long)((uint8_t *)&x)[n]) static inline uint32_t fdt32_to_cpu(uint32_t x) { return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3); } #define cpu_to_fdt32(x) fdt32_to_cpu(x) static inline uint64_t fdt64_to_cpu(uint64_t x) { return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32) | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7); } #define cpu_to_fdt64(x) fdt64_to_cpu(x) #undef _B #endif /* _LIBFDT_ENV_H */ kexec-tools-2.0.10/kexec/libfdt/libfdt_internal.h0000644001567400156740000000676612417126536021017 0ustar hormshorms#ifndef _LIBFDT_INTERNAL_H #define _LIBFDT_INTERNAL_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define FDT_CHECK_HEADER(fdt) \ { \ int err; \ if ((err = fdt_check_header(fdt)) != 0) \ return err; \ } uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); int _fdt_check_node_offset(const void *fdt, int offset); const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); int _fdt_node_end_offset(void *fdt, int nodeoffset); static inline const void *_fdt_offset_ptr(const void *fdt, int offset) { return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; } static inline void *_fdt_offset_ptr_w(void *fdt, int offset) { return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset); } static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n) { const struct fdt_reserve_entry *rsv_table = (const struct fdt_reserve_entry *) ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); return rsv_table + n; } static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n) { return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n); } #define FDT_SW_MAGIC (~FDT_MAGIC) #endif /* _LIBFDT_INTERNAL_H */ kexec-tools-2.0.10/kexec/arch/arm/Makefile0000644001567400156740000000164312417126536017363 0ustar hormshorms# # kexec arm (linux booting linux) # include $(srcdir)/kexec/libfdt/Makefile.libfdt arm_FS2DT = kexec/fs2dt.c arm_FS2DT_INCLUDE = -include $(srcdir)/kexec/arch/arm/crashdump-arm.h \ -include $(srcdir)/kexec/arch/arm/kexec-arm.h arm_KEXEC_SRCS= kexec/arch/arm/kexec-elf-rel-arm.c arm_KEXEC_SRCS+= kexec/arch/arm/kexec-zImage-arm.c arm_KEXEC_SRCS+= kexec/arch/arm/kexec-uImage-arm.c arm_KEXEC_SRCS+= kexec/arch/arm/kexec-arm.c arm_KEXEC_SRCS+= kexec/arch/arm/crashdump-arm.c arm_KEXEC_SRCS+= kexec/fs2dt.c libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) arm_CPPFLAGS = -I$(srcdir)/kexec/libfdt arm_KEXEC_SRCS += $(libfdt_SRCS) arm_UIMAGE = kexec/kexec-uImage.c arm_PHYS_TO_VIRT = kexec/arch/arm/phys_to_virt.c dist += kexec/arch/arm/Makefile $(arm_KEXEC_SRCS) $(arm_PHYS_TO_VIRT) \ kexec/arch/arm/crashdump-arm.h kexec/arch/arm/kexec-arm.h \ kexec/arch/arm/include/arch/options.h kexec-tools-2.0.10/kexec/arch/arm/kexec-elf-rel-arm.c0000644001567400156740000000125311642166046021263 0ustar hormshorms#include #include #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_ARM) { return 0; } return 1; } void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), unsigned long r_type, void *location, unsigned long address, unsigned long value) { switch(r_type) { case R_ARM_ABS32: *((uint32_t *)location) += value; break; case R_ARM_REL32: *((uint32_t *)location) += value - address; break; default: die("Unknown rel relocation: %lu\n", r_type); break; } } kexec-tools-2.0.10/kexec/arch/arm/kexec-zImage-arm.c0000644001567400156740000003137112417126536021156 0ustar hormshorms/* * - 08/21/2007 ATAG support added by Uli Luckas * */ #define _GNU_SOURCE #define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-arm.h" #include "../../fs2dt.h" #include "crashdump-arm.h" #define BOOT_PARAMS_SIZE 1536 off_t initrd_base = 0, initrd_size = 0; unsigned int kexec_arm_image_size = 0; unsigned long long user_page_offset = (-1ULL); struct tag_header { uint32_t size; uint32_t tag; }; /* The list must start with an ATAG_CORE node */ #define ATAG_CORE 0x54410001 struct tag_core { uint32_t flags; /* bit 0 = read-only */ uint32_t pagesize; uint32_t rootdev; }; /* it is allowed to have multiple ATAG_MEM nodes */ #define ATAG_MEM 0x54410002 struct tag_mem32 { uint32_t size; uint32_t start; /* physical start address */ }; /* describes where the compressed ramdisk image lives (virtual address) */ /* * this one accidentally used virtual addresses - as such, * it's deprecated. */ #define ATAG_INITRD 0x54410005 /* describes where the compressed ramdisk image lives (physical address) */ #define ATAG_INITRD2 0x54420005 struct tag_initrd { uint32_t start; /* physical start address */ uint32_t size; /* size of compressed ramdisk image in bytes */ }; /* command line: \0 terminated string */ #define ATAG_CMDLINE 0x54410009 struct tag_cmdline { char cmdline[1]; /* this is the minimum size */ }; /* The list ends with an ATAG_NONE node. */ #define ATAG_NONE 0x00000000 struct tag { struct tag_header hdr; union { struct tag_core core; struct tag_mem32 mem; struct tag_initrd initrd; struct tag_cmdline cmdline; } u; }; #define tag_next(t) ((struct tag *)((uint32_t *)(t) + (t)->hdr.size)) #define byte_size(t) ((t)->hdr.size << 2) #define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type) + 3) >> 2) int zImage_arm_probe(const char *UNUSED(buf), off_t UNUSED(len)) { /* * Only zImage loading is supported. Do not check if * the buffer is valid kernel image */ return 0; } void zImage_arm_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" " --dtb=FILE Use FILE as the fdt blob.\n" " --atags Use ATAGs instead of device-tree.\n" " --page-offset=PAGE_OFFSET\n" " Set PAGE_OFFSET of crash dump vmcore\n" ); } static struct tag * atag_read_tags(void) { static unsigned long buf[BOOT_PARAMS_SIZE]; const char fn[]= "/proc/atags"; FILE *fp; fp = fopen(fn, "r"); if (!fp) { fprintf(stderr, "Cannot open %s: %s\n", fn, strerror(errno)); return NULL; } if (!fread(buf, sizeof(buf[1]), BOOT_PARAMS_SIZE, fp)) { fclose(fp); return NULL; } if (ferror(fp)) { fprintf(stderr, "Cannot read %s: %s\n", fn, strerror(errno)); fclose(fp); return NULL; } fclose(fp); return (struct tag *) buf; } static int atag_arm_load(struct kexec_info *info, unsigned long base, const char *command_line, off_t command_line_len, const char *initrd, off_t initrd_len, off_t initrd_off) { struct tag *saved_tags = atag_read_tags(); char *buf; off_t len; struct tag *params; uint32_t *initrd_start = NULL; buf = xmalloc(getpagesize()); if (!buf) { fprintf(stderr, "Compiling ATAGs: out of memory\n"); return -1; } memset(buf, 0xff, getpagesize()); params = (struct tag *)buf; if (saved_tags) { // Copy tags saved_tags = (struct tag *) saved_tags; while(byte_size(saved_tags)) { switch (saved_tags->hdr.tag) { case ATAG_INITRD: case ATAG_INITRD2: case ATAG_CMDLINE: case ATAG_NONE: // skip these tags break; default: // copy all other tags memcpy(params, saved_tags, byte_size(saved_tags)); params = tag_next(params); } saved_tags = tag_next(saved_tags); } } else { params->hdr.size = 2; params->hdr.tag = ATAG_CORE; params = tag_next(params); } if (initrd) { params->hdr.size = tag_size(tag_initrd); params->hdr.tag = ATAG_INITRD2; initrd_start = ¶ms->u.initrd.start; params->u.initrd.size = initrd_len; params = tag_next(params); } if (command_line) { params->hdr.size = (sizeof(struct tag_header) + command_line_len + 3) >> 2; params->hdr.tag = ATAG_CMDLINE; memcpy(params->u.cmdline.cmdline, command_line, command_line_len); params->u.cmdline.cmdline[command_line_len - 1] = '\0'; params = tag_next(params); } params->hdr.size = 0; params->hdr.tag = ATAG_NONE; len = ((char *)params - buf) + sizeof(struct tag_header); add_segment(info, buf, len, base, len); if (initrd) { *initrd_start = locate_hole(info, initrd_len, getpagesize(), initrd_off, ULONG_MAX, INT_MAX); if (*initrd_start == ULONG_MAX) return -1; add_segment(info, initrd, initrd_len, *initrd_start, initrd_len); } return 0; } static int setup_dtb_prop(char **bufp, off_t *sizep, const char *node_name, const char *prop_name, const void *val, int len) { char *dtb_buf; off_t dtb_size; int off; int prop_len = 0; const struct fdt_property *prop; if ((bufp == NULL) || (sizep == NULL) || (*bufp == NULL)) die("Internal error\n"); dtb_buf = *bufp; dtb_size = *sizep; /* check if the subnode has already exist */ off = fdt_path_offset(dtb_buf, node_name); if (off == -FDT_ERR_NOTFOUND) { dtb_size += fdt_node_len(node_name); fdt_set_totalsize(dtb_buf, dtb_size); dtb_buf = xrealloc(dtb_buf, dtb_size); if (dtb_buf == NULL) die("xrealloc failed\n"); off = fdt_add_subnode(dtb_buf, off, node_name); } if (off < 0) { fprintf(stderr, "FDT: Error adding %s node.\n", node_name); return -1; } prop = fdt_get_property(dtb_buf, off, prop_name, &prop_len); if ((prop == NULL) && (prop_len != -FDT_ERR_NOTFOUND)) { die("FDT: fdt_get_property"); } else if (prop == NULL) { /* prop_len == -FDT_ERR_NOTFOUND */ /* prop doesn't exist */ dtb_size += fdt_prop_len(prop_name, len); } else { if (prop_len < len) dtb_size += FDT_TAGALIGN(len - prop_len); } if (fdt_totalsize(dtb_buf) < dtb_size) { fdt_set_totalsize(dtb_buf, dtb_size); dtb_buf = xrealloc(dtb_buf, dtb_size); if (dtb_buf == NULL) die("xrealloc failed\n"); } if (fdt_setprop(dtb_buf, off, prop_name, val, len) != 0) { fprintf(stderr, "FDT: Error setting %s/%s property.\n", node_name, prop_name); return -1; } *bufp = dtb_buf; *sizep = dtb_size; return 0; } int zImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { unsigned long base; unsigned int atag_offset = 0x1000; /* 4k offset from memory start */ unsigned int extra_size = 0x8000; /* TEXT_OFFSET */ const char *command_line; char *modified_cmdline = NULL; off_t command_line_len; const char *ramdisk; char *ramdisk_buf; int opt; int use_atags; char *dtb_buf; off_t dtb_length; char *dtb_file; off_t dtb_offset; char *end; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "initrd", 1, 0, OPT_RAMDISK }, { "ramdisk", 1, 0, OPT_RAMDISK }, { "dtb", 1, 0, OPT_DTB }, { "atags", 0, 0, OPT_ATAGS }, { "image-size", 1, 0, OPT_IMAGE_SIZE }, { "page-offset", 1, 0, OPT_PAGE_OFFSET }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "a:r:"; /* * Parse the command line arguments */ command_line = 0; command_line_len = 0; ramdisk = 0; ramdisk_buf = 0; initrd_size = 0; use_atags = 0; dtb_file = NULL; while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case OPT_APPEND: command_line = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DTB: dtb_file = optarg; break; case OPT_ATAGS: use_atags = 1; break; case OPT_IMAGE_SIZE: kexec_arm_image_size = strtoul(optarg, &end, 0); break; case OPT_PAGE_OFFSET: user_page_offset = strtoull(optarg, &end, 0); break; } } if (use_atags && dtb_file) { fprintf(stderr, "You can only use ATAGs if you don't specify a " "dtb file.\n"); return -1; } if (command_line) { command_line_len = strlen(command_line) + 1; if (command_line_len > COMMAND_LINE_SIZE) command_line_len = COMMAND_LINE_SIZE; } if (ramdisk) ramdisk_buf = slurp_file(ramdisk, &initrd_size); if (dtb_file) dtb_buf = slurp_file(dtb_file, &dtb_length); /* * If we are loading a dump capture kernel, we need to update kernel * command line and also add some additional segments. */ if (info->kexec_flags & KEXEC_ON_CRASH) { uint64_t start, end; modified_cmdline = xmalloc(COMMAND_LINE_SIZE); if (!modified_cmdline) return -1; memset(modified_cmdline, '\0', COMMAND_LINE_SIZE); if (command_line) { (void) strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } if (load_crashdump_segments(info, modified_cmdline) < 0) { free(modified_cmdline); return -1; } command_line = modified_cmdline; command_line_len = strlen(command_line) + 1; /* * We put the dump capture kernel at the start of crashkernel * reserved memory. */ if (parse_iomem_single("Crash kernel\n", &start, &end)) { /* * No crash kernel memory reserved. We cannot do more * but just bail out. */ return -1; } base = start; } else { base = locate_hole(info, len + extra_size, 0, 0, ULONG_MAX, INT_MAX); } if (base == ULONG_MAX) return -1; if (kexec_arm_image_size) { /* If the image size was passed as command line argument, * use that value for determining the address for initrd, * atags and dtb images. page-align the given length.*/ initrd_base = base + _ALIGN(kexec_arm_image_size, getpagesize()); } else { /* Otherwise, assume the maximum kernel compression ratio * is 4, and just to be safe, place ramdisk after that */ initrd_base = base + _ALIGN(len * 4, getpagesize()); } if (use_atags) { /* * use ATAGs from /proc/atags */ if (atag_arm_load(info, base + atag_offset, command_line, command_line_len, ramdisk_buf, initrd_size, initrd_base) == -1) return -1; } else { /* * Read a user-specified DTB file. */ if (dtb_file) { if (fdt_check_header(dtb_buf) != 0) { fprintf(stderr, "Invalid FDT buffer.\n"); return -1; } if (command_line) { /* * Error should have been reported so * directly return -1 */ if (setup_dtb_prop(&dtb_buf, &dtb_length, "/chosen", "bootargs", command_line, strlen(command_line) + 1)) return -1; } } else { /* * Extract the DTB from /proc/device-tree. */ create_flatten_tree(&dtb_buf, &dtb_length, command_line); } /* * Search in memory to make sure there is enough memory * to hold initrd and dtb. * * Even if no initrd is used, this check is still * required for dtb. * * Crash kernel use fixed address, no check is ok. */ if ((info->kexec_flags & KEXEC_ON_CRASH) == 0) { unsigned long page_size = getpagesize(); /* * DTB size may be increase a little * when setup initrd size. Add a full page * for it is enough. */ unsigned long hole_size = _ALIGN_UP(initrd_size, page_size) + _ALIGN(dtb_length + page_size, page_size); unsigned long initrd_base_new = locate_hole(info, hole_size, page_size, initrd_base, ULONG_MAX, INT_MAX); if (base == ULONG_MAX) return -1; initrd_base = initrd_base_new; } if (ramdisk) { add_segment(info, ramdisk_buf, initrd_size, initrd_base, initrd_size); unsigned long start, end; start = cpu_to_be32((unsigned long)(initrd_base)); end = cpu_to_be32((unsigned long)(initrd_base + initrd_size)); if (setup_dtb_prop(&dtb_buf, &dtb_length, "/chosen", "linux,initrd-start", &start, sizeof(start))) return -1; if (setup_dtb_prop(&dtb_buf, &dtb_length, "/chosen", "linux,initrd-end", &end, sizeof(end))) return -1; } /* Stick the dtb at the end of the initrd and page * align it. */ dtb_offset = initrd_base + initrd_size + getpagesize(); dtb_offset = _ALIGN_DOWN(dtb_offset, getpagesize()); add_segment(info, dtb_buf, dtb_length, dtb_offset, dtb_length); } add_segment(info, buf, len, base + extra_size, len); info->entry = (void*)base + extra_size; return 0; } kexec-tools-2.0.10/kexec/arch/arm/kexec-uImage-arm.c0000644001567400156740000000107612242534555021150 0ustar hormshorms/* * uImage support added by Marc Andre Tanner */ #include #include #include #include #include #include "../../kexec.h" #include "kexec-arm.h" int uImage_arm_probe(const char *buf, off_t len) { return uImage_probe_kernel(buf, len, IH_ARCH_ARM); } int uImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { return zImage_arm_load(argc, argv, buf + sizeof(struct image_header), len - sizeof(struct image_header), info); } kexec-tools-2.0.10/kexec/arch/arm/kexec-arm.c0000644001567400156740000000512512417126536017742 0ustar hormshorms/* * kexec: Linux boots Linux * * modified from kexec-ppc.c * */ #define _GNU_SOURCE #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-arm.h" #include #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, unsigned long UNUSED(kexec_flags)) { 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 (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "reserved\n", 9) == 0) { type = RANGE_RESERVED; } else { continue; } memory_range[memory_ranges].start = start; memory_range[memory_ranges].end = end; memory_range[memory_ranges].type = type; memory_ranges++; } fclose(fp); *range = memory_range; *ranges = memory_ranges; return 0; } /* Supported file types and callbacks */ struct file_type file_type[] = { /* uImage is probed before zImage because the latter also accepts uncompressed images. */ {"uImage", uImage_arm_probe, uImage_arm_load, zImage_arm_usage}, {"zImage", zImage_arm_probe, zImage_arm_load, zImage_arm_usage}, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { printf(" --image-size=\n" " Specify the assumed total image size of\n" " the kernel that is about to be loaded,\n" " including the .bss section, as reported\n" " by 'arm-linux-size vmlinux'. If not\n" " specified, this value is implicitly set\n" " to the compressed images size * 4.\n"); } int arch_process_options(int argc, char **argv) { return 0; } const struct arch_map_entry arches[] = { { "arm", KEXEC_ARCH_ARM }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } kexec-tools-2.0.10/kexec/arch/arm/crashdump-arm.c0000644001567400156740000002671512417126536020641 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) Nokia Corporation, 2010. * Author: Mika Westerberg * * Based on x86 implementation * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../crashdump.h" #include "crashdump-arm.h" #if __BYTE_ORDER == __LITTLE_ENDIAN #define ELFDATANATIVE ELFDATA2LSB #elif __BYTE_ORDER == __BIG_ENDIAN #define ELFDATANATIVE ELFDATA2MSB #else #error "Unknown machine endian" #endif /* * Used to save various memory ranges/regions needed for the captured * kernel to boot. (lime memmap= option in other archs) */ static struct memory_range crash_memory_ranges[CRASH_MAX_MEMORY_RANGES]; struct memory_ranges usablemem_rgns = { .size = 0, .ranges = crash_memory_ranges, }; /* memory range reserved for crashkernel */ static struct memory_range crash_reserved_mem; static struct crash_elf_info elf_info = { .class = ELFCLASS32, .data = ELFDATANATIVE, .machine = EM_ARM, .page_offset = DEFAULT_PAGE_OFFSET, }; unsigned long phys_offset; extern unsigned long long user_page_offset; /* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */ static unsigned long long get_kernel_stext_sym(void) { const char *kallsyms = "/proc/kallsyms"; const char *stext = "_stext"; char sym[128]; char line[128]; FILE *fp; unsigned long long vaddr; char type; fp = fopen(kallsyms, "r"); if (!fp) { fprintf(stderr, "Cannot open %s\n", kallsyms); return 0; } while(fgets(line, sizeof(line), fp) != NULL) { if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3) continue; if (strcmp(sym, stext) == 0) { dbgprintf("kernel symbol %s vaddr = %16llx\n", stext, vaddr); return vaddr; } } fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); return 0; } static int get_kernel_page_offset(struct kexec_info *info, struct crash_elf_info *elf_info) { unsigned long long stext_sym_addr = get_kernel_stext_sym(); if (stext_sym_addr == 0) { if (user_page_offset != (-1ULL)) { elf_info->page_offset = user_page_offset; dbgprintf("Unable to get _stext symbol from /proc/kallsyms, " "use user provided vaule: %llx\n", elf_info->page_offset); return 0; } elf_info->page_offset = (unsigned long long)DEFAULT_PAGE_OFFSET; dbgprintf("Unable to get _stext symbol from /proc/kallsyms, " "use default: %llx\n", elf_info->page_offset); return 0; } else if ((user_page_offset != (-1ULL)) && (user_page_offset != stext_sym_addr)) { fprintf(stderr, "PAGE_OFFSET is set to %llx " "instead of user provided value %llx\n", stext_sym_addr & (~KVBASE_MASK), user_page_offset); } elf_info->page_offset = stext_sym_addr & (~KVBASE_MASK); dbgprintf("page_offset is set to %llx\n", elf_info->page_offset); return 0; } /** * crash_range_callback() - callback called for each iomem region * @data: not used * @nr: not used * @str: name of the memory region * @base: start address of the memory region * @length: size of the memory region * * This function is called once for each memory region found in /proc/iomem. It * locates system RAM and crashkernel reserved memory and places these to * variables: @crash_memory_ranges and @crash_reserved_mem. Number of memory * regions is placed in @crash_memory_nr_ranges. */ static int crash_range_callback(void *UNUSED(data), int UNUSED(nr), char *str, unsigned long long base, unsigned long long length) { struct memory_range *range; if (usablemem_rgns.size >= CRASH_MAX_MEMORY_RANGES) return 1; range = usablemem_rgns.ranges + usablemem_rgns.size; if (strncmp(str, "System RAM\n", 11) == 0) { range->start = base; range->end = base + length - 1; range->type = RANGE_RAM; usablemem_rgns.size++; } else if (strncmp(str, "Crash kernel\n", 13) == 0) { crash_reserved_mem.start = base; crash_reserved_mem.end = base + length - 1; crash_reserved_mem.type = RANGE_RAM; } return 0; } /** * crash_exclude_range() - excludes memory region reserved for crashkernel * * Function locates where crashkernel reserved memory is and removes that region * from the available memory regions. */ static void crash_exclude_range(void) { const struct memory_range *range = &crash_reserved_mem; int i; for (i = 0; i < usablemem_rgns.size; i++) { struct memory_range *r = usablemem_rgns.ranges + i; /* * We assume that crash area is fully contained in * some larger memory area. */ if (r->start <= range->start && r->end >= range->end) { struct memory_range *new; /* * Let's split this area into 2 smaller ones and * remove excluded range from between. First create * new entry for the remaining area. */ new = usablemem_rgns.ranges + usablemem_rgns.size; new->start = range->end + 1; new->end = r->end; usablemem_rgns.size++; /* * Next update this area to end before excluded range. */ r->end = range->start - 1; break; } } } static int range_cmp(const void *a1, const void *a2) { const struct memory_range *r1 = a1; const struct memory_range *r2 = a2; if (r1->start > r2->start) return 1; if (r1->start < r2->start) return -1; return 0; } /** * crash_get_memory_ranges() - read system physical memory * * Function reads through system physical memory and stores found memory regions * in @crash_memory_ranges. Number of memory regions found is placed in * @crash_memory_nr_ranges. Regions are sorted in ascending order. * * Returns %0 in case of success and %-1 otherwise (errno is set). */ static int crash_get_memory_ranges(void) { /* * First read all memory regions that can be considered as * system memory including the crash area. */ kexec_iomem_for_each_line(NULL, crash_range_callback, NULL); if (usablemem_rgns.size < 1) { errno = EINVAL; return -1; } /* * Exclude memory reserved for crashkernel (this may result a split memory * region). */ crash_exclude_range(); /* * Make sure that the memory regions are sorted. */ qsort(usablemem_rgns.ranges, usablemem_rgns.size, sizeof(*usablemem_rgns.ranges), range_cmp); return 0; } /** * cmdline_add_elfcorehdr() - adds elfcorehdr= to @cmdline * @cmdline: buffer where parameter is placed * @elfcorehdr: physical address of elfcorehdr * * Function appends 'elfcorehdr=start' at the end of the command line given in * @cmdline. Note that @cmdline must be at least %COMMAND_LINE_SIZE bytes long * (inclunding %NUL). */ static void cmdline_add_elfcorehdr(char *cmdline, unsigned long elfcorehdr) { char buf[COMMAND_LINE_SIZE]; int buflen; buflen = snprintf(buf, sizeof(buf), "%s elfcorehdr=%#lx", cmdline, elfcorehdr); if (buflen < 0) die("Failed to construct elfcorehdr= command line parameter\n"); if (buflen >= sizeof(buf)) die("Command line overflow\n"); (void) strncpy(cmdline, buf, COMMAND_LINE_SIZE); cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } /** * cmdline_add_mem() - adds mem= parameter to kernel command line * @cmdline: buffer where parameter is placed * @size: size of the kernel reserved memory (in bytes) * * This function appends 'mem=size' at the end of the command line given in * @cmdline. Note that @cmdline must be at least %COMMAND_LINE_SIZE bytes long * (including %NUL). */ static void cmdline_add_mem(char *cmdline, unsigned long size) { char buf[COMMAND_LINE_SIZE]; int buflen; buflen = snprintf(buf, sizeof(buf), "%s mem=%ldK", cmdline, size >> 10); if (buflen < 0) die("Failed to construct mem= command line parameter\n"); if (buflen >= sizeof(buf)) die("Command line overflow\n"); (void) strncpy(cmdline, buf, COMMAND_LINE_SIZE); cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } static unsigned long long range_size(const struct memory_range *r) { return r->end - r->start + 1; } static void dump_memory_ranges(void) { int i; if (!kexec_debug) return; dbgprintf("crashkernel: [%#llx - %#llx] (%ldM)\n", crash_reserved_mem.start, crash_reserved_mem.end, (unsigned long)range_size(&crash_reserved_mem) >> 20); for (i = 0; i < usablemem_rgns.size; i++) { struct memory_range *r = usablemem_rgns.ranges + i; dbgprintf("memory range: [%#llx - %#llx] (%ldM)\n", r->start, r->end, (unsigned long)range_size(r) >> 20); } } /** * load_crashdump_segments() - loads additional segments needed for kdump * @info: kexec info structure * @mod_cmdline: kernel command line * * This function loads additional segments which are needed for the dump capture * kernel. It also updates kernel command line passed in @mod_cmdline to have * right parameters for the dump capture kernel. * * Return %0 in case of success and %-1 in case of error. */ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline) { unsigned long elfcorehdr; unsigned long bufsz; void *buf; int err; int last_ranges; /* * First fetch all the memory (RAM) ranges that we are going to pass to * the crashdump kernel during panic. */ err = crash_get_memory_ranges(); if (err) return err; /* * Now that we have memory regions sorted, we can use first memory * region as PHYS_OFFSET. */ phys_offset = usablemem_rgns.ranges->start; dbgprintf("phys_offset: %#lx\n", phys_offset); if (get_kernel_page_offset(info, &elf_info)) return -1; last_ranges = usablemem_rgns.size - 1; if (last_ranges < 0) last_ranges = 0; if (crash_memory_ranges[last_ranges].end > ULONG_MAX) { /* for support LPAE enabled kernel*/ elf_info.class = ELFCLASS64; err = crash_create_elf64_headers(info, &elf_info, usablemem_rgns.ranges, usablemem_rgns.size, &buf, &bufsz, ELF_CORE_HEADER_ALIGN); } else { err = crash_create_elf32_headers(info, &elf_info, usablemem_rgns.ranges, usablemem_rgns.size, &buf, &bufsz, ELF_CORE_HEADER_ALIGN); } if (err) return err; /* * We allocate ELF core header from the end of the memory area reserved * for the crashkernel. We align the header to SECTION_SIZE (which is * 1MB) so that available memory passed in kernel command line will be * aligned to 1MB. This is because kernel create_mapping() wants memory * regions to be aligned to SECTION_SIZE. */ elfcorehdr = add_buffer_phys_virt(info, buf, bufsz, bufsz, 1 << 20, crash_reserved_mem.start, crash_reserved_mem.end, -1, 0); dbgprintf("elfcorehdr: %#lx\n", elfcorehdr); cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr); /* * Add 'mem=size' parameter to dump capture kernel command line. This * prevents the dump capture kernel from using any other memory regions * which belong to the primary kernel. */ cmdline_add_mem(mod_cmdline, elfcorehdr - crash_reserved_mem.start); dump_memory_ranges(); dbgprintf("kernel command line: \"%s\"\n", mod_cmdline); return 0; } int is_crashkernel_mem_reserved(void) { uint64_t start, end; if (parse_iomem_single("Crash kernel\n", &start, &end) == 0) return start != end; return 0; } kexec-tools-2.0.10/kexec/fs2dt.c0000644001567400156740000000000012471201644022626 1kexec-tools-2.0.10/kexec/fs2dt.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt.c0000644001567400156740000001237212242534555016415 0ustar hormshorms/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_check_header(const void *fdt) { if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION; if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION; } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { /* Unfinished sequential-write blob */ if (fdt_size_dt_struct(fdt) == 0) return -FDT_ERR_BADSTATE; } else { return -FDT_ERR_BADMAGIC; } return 0; } const void *fdt_offset_ptr(const void *fdt, int offset, int len) { const char *p; if (fdt_version(fdt) >= 0x11) if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; p = _fdt_offset_ptr(fdt, offset); if (p + len < p) return NULL; return p; } uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset) { const uint32_t *tagp, *lenp; uint32_t tag; const char *p; if (offset % FDT_TAGSIZE) return -1; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); if (! tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; switch (tag) { case FDT_BEGIN_NODE: /* skip name */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); if (! p) return FDT_END; break; case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (! lenp) return FDT_END; /* skip name offset, length and value */ offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); break; } if (nextoffset) *nextoffset = FDT_TAGALIGN(offset); return tag; } int _fdt_check_node_offset(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) return -FDT_ERR_BADOFFSET; return offset; } int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; uint32_t tag; if (offset >= 0) if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0) return nextoffset; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_PROP: case FDT_NOP: break; case FDT_BEGIN_NODE: if (depth) (*depth)++; break; case FDT_END_NODE: if (depth) (*depth)--; break; case FDT_END: return -FDT_ERR_NOTFOUND; default: return -FDT_ERR_BADSTRUCTURE; } } while (tag != FDT_BEGIN_NODE); return offset; } const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) { int len = strlen(s) + 1; const char *last = strtab + tabsize - len; const char *p; for (p = strtab; p <= last; p++) if (memcmp(p, s, len) == 0) return p; return NULL; } int fdt_move(const void *fdt, void *buf, int bufsize) { FDT_CHECK_HEADER(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; memmove(buf, fdt, fdt_totalsize(fdt)); return 0; } kexec-tools-2.0.10/kexec/libfdt/fdt_ro.c0000644001567400156740000002625212242534555017117 0ustar hormshorms/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int _fdt_nodename_eq(const void *fdt, int offset, const char *s, int len) { const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); if (! p) /* short match */ return 0; if (memcmp(p, s, len) != 0) return 0; if (p[len] == '\0') return 1; else if (!memchr(s, '@', len) && (p[len] == '@')) return 1; else return 0; } const char *fdt_string(const void *fdt, int stroffset) { return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; } int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); return 0; } int fdt_num_mem_rsv(const void *fdt) { int i = 0; while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) i++; return i; } int fdt_subnode_offset_namelen(const void *fdt, int offset, const char *name, int namelen) { int depth; FDT_CHECK_HEADER(fdt); for (depth = 0; offset >= 0; offset = fdt_next_node(fdt, offset, &depth)) { if (depth < 0) return -FDT_ERR_NOTFOUND; else if ((depth == 1) && _fdt_nodename_eq(fdt, offset, name, namelen)) return offset; } return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name) { return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_path_offset(const void *fdt, const char *path) { const char *end = path + strlen(path); const char *p = path; int offset = 0; FDT_CHECK_HEADER(fdt); if (*path != '/') return -FDT_ERR_BADPATH; while (*p) { const char *q; while (*p == '/') p++; if (! *p) return offset; q = strchr(p, '/'); if (! q) q = end; offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); if (offset < 0) return offset; p = q; } return offset; } const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) { const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); int err; if (((err = fdt_check_header(fdt)) != 0) || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) goto fail; if (len) *len = strlen(nh->name); return nh->name; fail: if (len) *len = err; return NULL; } const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp) { uint32_t tag; const struct fdt_property *prop; int namestroff; int offset, nextoffset; int err; if (((err = fdt_check_header(fdt)) != 0) || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) goto fail; nextoffset = err; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: err = -FDT_ERR_TRUNCATED; goto fail; case FDT_BEGIN_NODE: case FDT_END_NODE: case FDT_NOP: break; case FDT_PROP: err = -FDT_ERR_BADSTRUCTURE; prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); if (! prop) goto fail; namestroff = fdt32_to_cpu(prop->nameoff); if (strcmp(fdt_string(fdt, namestroff), name) == 0) { /* Found it! */ int len = fdt32_to_cpu(prop->len); prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)+len); if (! prop) goto fail; if (lenp) *lenp = len; return prop; } break; default: err = -FDT_ERR_BADSTRUCTURE; goto fail; } } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); err = -FDT_ERR_NOTFOUND; fail: if (lenp) *lenp = err; return NULL; } const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp) { const struct fdt_property *prop; prop = fdt_get_property(fdt, nodeoffset, name, lenp); if (! prop) return NULL; return prop->data; } uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { const uint32_t *php; int len; php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); if (!php || (len != sizeof(*php))) return 0; return fdt32_to_cpu(*php); } int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { int pdepth = 0, p = 0; int offset, depth, namelen; const char *name; FDT_CHECK_HEADER(fdt); if (buflen < 2) return -FDT_ERR_NOSPACE; for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { if (pdepth < depth) continue; /* overflowed buffer */ while (pdepth > depth) { do { p--; } while (buf[p-1] != '/'); pdepth--; } name = fdt_get_name(fdt, offset, &namelen); if (!name) return namelen; if ((p + namelen + 1) <= buflen) { memcpy(buf + p, name, namelen); p += namelen; buf[p++] = '/'; pdepth++; } if (offset == nodeoffset) { if (pdepth < (depth + 1)) return -FDT_ERR_NOSPACE; if (p > 1) /* special case so that root path is "/", not "" */ p--; buf[p] = '\0'; return p; } } if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) return -FDT_ERR_BADOFFSET; else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADSTRUCTURE; return offset; /* error from fdt_next_node() */ } int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth) { int offset, depth; int supernodeoffset = -FDT_ERR_INTERNAL; FDT_CHECK_HEADER(fdt); if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { if (depth == supernodedepth) supernodeoffset = offset; if (offset == nodeoffset) { if (nodedepth) *nodedepth = depth; if (supernodedepth > depth) return -FDT_ERR_NOTFOUND; else return supernodeoffset; } } if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) return -FDT_ERR_BADOFFSET; else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADSTRUCTURE; return offset; /* error from fdt_next_node() */ } int fdt_node_depth(const void *fdt, int nodeoffset) { int nodedepth; int err; err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); if (err) return (err < 0) ? err : -FDT_ERR_INTERNAL; return nodedepth; } int fdt_parent_offset(const void *fdt, int nodeoffset) { int nodedepth = fdt_node_depth(fdt, nodeoffset); if (nodedepth < 0) return nodedepth; return fdt_supernode_atdepth_offset(fdt, nodeoffset, nodedepth - 1, NULL); } int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen) { int offset; const void *val; int len; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't * find what we want, we scan over them again making our way * to the next node. Still it's the easiest to implement * approach; performance can come later. */ for (offset = fdt_next_node(fdt, startoffset, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { val = fdt_getprop(fdt, offset, propname, &len); if (val && (len == proplen) && (memcmp(val, propval, len) == 0)) return offset; } return offset; /* error from fdt_next_node() */ } int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; phandle = cpu_to_fdt32(phandle); return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", &phandle, sizeof(phandle)); } int _stringlist_contains(const char *strlist, int listlen, const char *str) { int len = strlen(str); const char *p; while (listlen >= len) { if (memcmp(str, strlist, len+1) == 0) return 1; p = memchr(strlist, '\0', listlen); if (!p) return 0; /* malformed strlist.. */ listlen -= (p-strlist) + 1; strlist = p + 1; } return 0; } int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible) { const void *prop; int len; prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; if (_stringlist_contains(prop, len, compatible)) return 0; else return 1; } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible) { int offset, err; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if * that didn't find what we want, we scan over them again * making our way to the next node. Still it's the easiest to * implement approach; performance can come later. */ for (offset = fdt_next_node(fdt, startoffset, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { err = fdt_node_check_compatible(fdt, offset, compatible); if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) return err; else if (err == 0) return offset; } return offset; /* error from fdt_next_node() */ } kexec-tools-2.0.10/kexec/libfdt/fdt_wip.c0000644001567400156740000000775212242534555017302 0ustar hormshorms/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len) { void *propval; int proplen; propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen); if (! propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; memcpy(propval, val, len); return 0; } static void _fdt_nop_region(void *start, int len) { uint32_t *p; for (p = start; (char *)p < ((char *)start + len); p++) *p = cpu_to_fdt32(FDT_NOP); } int fdt_nop_property(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; int len; prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (! prop) return len; _fdt_nop_region(prop, len + sizeof(*prop)); return 0; } int _fdt_node_end_offset(void *fdt, int nodeoffset) { int level = 0; uint32_t tag; int offset, nextoffset; tag = fdt_next_tag(fdt, nodeoffset, &nextoffset); if (tag != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: return offset; case FDT_BEGIN_NODE: level++; break; case FDT_END_NODE: level--; break; case FDT_PROP: case FDT_NOP: break; default: return -FDT_ERR_BADSTRUCTURE; } } while (level >= 0); return nextoffset; } int fdt_nop_node(void *fdt, int nodeoffset) { int endoffset; endoffset = _fdt_node_end_offset(fdt, nodeoffset); if (endoffset < 0) return endoffset; _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset); return 0; } kexec-tools-2.0.10/kexec/libfdt/fdt_sw.c0000644001567400156740000001600712242534555017125 0ustar hormshorms/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int _fdt_sw_check_header(void *fdt) { if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADMAGIC; /* FIXME: should check more details about the header state */ return 0; } #define FDT_SW_CHECK_HEADER(fdt) \ { \ int err; \ if ((err = _fdt_sw_check_header(fdt)) != 0) \ return err; \ } static void *_fdt_grab_space(void *fdt, int len) { int offset = fdt_size_dt_struct(fdt); int spaceleft; spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - fdt_size_dt_strings(fdt); if ((offset + len < offset) || (offset + len > spaceleft)) return NULL; fdt_set_size_dt_struct(fdt, offset + len); return fdt_offset_ptr_w(fdt, offset, len); } int fdt_create(void *buf, int bufsize) { void *fdt = buf; if (bufsize < sizeof(struct fdt_header)) return -FDT_ERR_NOSPACE; memset(buf, 0, bufsize); fdt_set_magic(fdt, FDT_SW_MAGIC); fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_totalsize(fdt, bufsize); fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), sizeof(struct fdt_reserve_entry))); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); fdt_set_off_dt_strings(fdt, bufsize); return 0; } int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; int offset; FDT_SW_CHECK_HEADER(fdt); if (fdt_size_dt_struct(fdt)) return -FDT_ERR_BADSTATE; offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; re = (struct fdt_reserve_entry *)((char *)fdt + offset); re->address = cpu_to_fdt64(addr); re->size = cpu_to_fdt64(size); fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); return 0; } int fdt_finish_reservemap(void *fdt) { return fdt_add_reservemap_entry(fdt, 0, 0); } int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; int namelen = strlen(name) + 1; FDT_SW_CHECK_HEADER(fdt); nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); if (! nh) return -FDT_ERR_NOSPACE; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memcpy(nh->name, name, namelen); return 0; } int fdt_end_node(void *fdt) { uint32_t *en; FDT_SW_CHECK_HEADER(fdt); en = _fdt_grab_space(fdt, FDT_TAGSIZE); if (! en) return -FDT_ERR_NOSPACE; *en = cpu_to_fdt32(FDT_END_NODE); return 0; } static int _fdt_find_add_string(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_totalsize(fdt); const char *p; int strtabsize = fdt_size_dt_strings(fdt); int len = strlen(s) + 1; int struct_top, offset; p = _fdt_find_string(strtab - strtabsize, strtabsize, s); if (p) return p - strtab; /* Add it */ offset = -strtabsize - len; struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); if (fdt_totalsize(fdt) + offset < struct_top) return 0; /* no more room :( */ memcpy(strtab + offset, s, len); fdt_set_size_dt_strings(fdt, strtabsize + len); return offset; } int fdt_property(void *fdt, const char *name, const void *val, int len) { struct fdt_property *prop; int nameoff; FDT_SW_CHECK_HEADER(fdt); nameoff = _fdt_find_add_string(fdt, name); if (nameoff == 0) return -FDT_ERR_NOSPACE; prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); if (! prop) return -FDT_ERR_NOSPACE; prop->tag = cpu_to_fdt32(FDT_PROP); prop->nameoff = cpu_to_fdt32(nameoff); prop->len = cpu_to_fdt32(len); memcpy(prop->data, val, len); return 0; } int fdt_finish(void *fdt) { char *p = (char *)fdt; uint32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; FDT_SW_CHECK_HEADER(fdt); /* Add terminator */ end = _fdt_grab_space(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); /* Relocate the string table */ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); fdt_set_off_dt_strings(fdt, newstroffset); /* Walk the structure, correcting string offsets */ offset = 0; while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = fdt_offset_ptr_w(fdt, offset, sizeof(*prop)); int nameoff; if (! prop) return -FDT_ERR_BADSTRUCTURE; nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } /* Finally, adjust the header */ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_magic(fdt, FDT_MAGIC); return 0; } kexec-tools-2.0.10/kexec/libfdt/fdt_rw.c0000644001567400156740000003000612242534555017117 0ustar hormshorms/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int _fdt_blocks_misordered(const void *fdt, int mem_rsv_size, int struct_size) { return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) || (fdt_off_dt_struct(fdt) < (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) || (fdt_off_dt_strings(fdt) < (fdt_off_dt_struct(fdt) + struct_size)) || (fdt_totalsize(fdt) < (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } static int _fdt_rw_check_header(void *fdt) { FDT_CHECK_HEADER(fdt); if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry), fdt_size_dt_struct(fdt))) return -FDT_ERR_BADLAYOUT; if (fdt_version(fdt) > 17) fdt_set_version(fdt, 17); return 0; } #define FDT_RW_CHECK_HEADER(fdt) \ { \ int err; \ if ((err = _fdt_rw_check_header(fdt)) != 0) \ return err; \ } static inline int _fdt_data_size(void *fdt) { return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen) { char *p = splicepoint; char *end = (char *)fdt + _fdt_data_size(fdt); if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; memmove(p + newlen, p + oldlen, end - p - oldlen); return 0; } static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p, int oldn, int newn) { int delta = (newn - oldn) * sizeof(*p); int err; err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); if (err) return err; fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } static int _fdt_splice_struct(void *fdt, void *p, int oldlen, int newlen) { int delta = newlen - oldlen; int err; if ((err = _fdt_splice(fdt, p, oldlen, newlen))) return err; fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } static int _fdt_splice_string(void *fdt, int newlen) { void *p = (char *)fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); int err; if ((err = _fdt_splice(fdt, p, 0, newlen))) return err; fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); return 0; } static int _fdt_find_add_string(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); const char *p; char *new; int len = strlen(s) + 1; int err; p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); if (p) /* found it */ return (p - strtab); new = strtab + fdt_size_dt_strings(fdt); err = _fdt_splice_string(fdt, len); if (err) return err; memcpy(new, s, len); return (new - strtab); } int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) { struct fdt_reserve_entry *re; int err; FDT_RW_CHECK_HEADER(fdt); re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt)); err = _fdt_splice_mem_rsv(fdt, re, 0, 1); if (err) return err; re->address = cpu_to_fdt64(address); re->size = cpu_to_fdt64(size); return 0; } int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n); int err; FDT_RW_CHECK_HEADER(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; err = _fdt_splice_mem_rsv(fdt, re, 1, 0); if (err) return err; return 0; } static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { int oldlen; int err; *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (! (*prop)) return oldlen; if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), FDT_TAGALIGN(len)))) return err; (*prop)->len = cpu_to_fdt32(len); return 0; } static int _fdt_add_property(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { int proplen; int nextoffset; int namestroff; int err; if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) return nextoffset; namestroff = _fdt_find_add_string(fdt, name); if (namestroff < 0) return namestroff; *prop = _fdt_offset_ptr_w(fdt, nextoffset); proplen = sizeof(**prop) + FDT_TAGALIGN(len); err = _fdt_splice_struct(fdt, *prop, 0, proplen); if (err) return err; (*prop)->tag = cpu_to_fdt32(FDT_PROP); (*prop)->nameoff = cpu_to_fdt32(namestroff); (*prop)->len = cpu_to_fdt32(len); return 0; } int fdt_set_name(void *fdt, int nodeoffset, const char *name) { char *namep; int oldlen, newlen; int err; FDT_RW_CHECK_HEADER(fdt); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); if (!namep) return oldlen; newlen = strlen(name); err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1), FDT_TAGALIGN(newlen+1)); if (err) return err; memcpy(namep, name, newlen+1); return 0; } int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len) { struct fdt_property *prop; int err; FDT_RW_CHECK_HEADER(fdt); err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop); if (err == -FDT_ERR_NOTFOUND) err = _fdt_add_property(fdt, nodeoffset, name, len, &prop); if (err) return err; memcpy(prop->data, val, len); return 0; } int fdt_delprop(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; int len, proplen; FDT_RW_CHECK_HEADER(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (! prop) return len; proplen = sizeof(*prop) + FDT_TAGALIGN(len); return _fdt_splice_struct(fdt, prop, proplen, 0); } int fdt_add_subnode_namelen(void *fdt, int parentoffset, const char *name, int namelen) { struct fdt_node_header *nh; int offset, nextoffset; int nodelen; int err; uint32_t tag; uint32_t *endtag; FDT_RW_CHECK_HEADER(fdt); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) return -FDT_ERR_EXISTS; else if (offset != -FDT_ERR_NOTFOUND) return offset; /* Try to place the new node after the parent's properties */ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); } while ((tag == FDT_PROP) || (tag == FDT_NOP)); nh = _fdt_offset_ptr_w(fdt, offset); nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; err = _fdt_splice_struct(fdt, nh, 0, nodelen); if (err) return err; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); memcpy(nh->name, name, namelen); endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE); *endtag = cpu_to_fdt32(FDT_END_NODE); return offset; } int fdt_add_subnode(void *fdt, int parentoffset, const char *name) { return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_del_node(void *fdt, int nodeoffset) { int endoffset; FDT_RW_CHECK_HEADER(fdt); endoffset = _fdt_node_end_offset(fdt, nodeoffset); if (endoffset < 0) return endoffset; return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset), endoffset - nodeoffset, 0); } static void _fdt_packblocks(const char *old, char *new, int mem_rsv_size, int struct_size) { int mem_rsv_off, struct_off, strings_off; mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); struct_off = mem_rsv_off + mem_rsv_size; strings_off = struct_off + struct_size; memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); fdt_set_off_mem_rsvmap(new, mem_rsv_off); memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); fdt_set_off_dt_struct(new, struct_off); fdt_set_size_dt_struct(new, struct_size); memmove(new + strings_off, old + fdt_off_dt_strings(old), fdt_size_dt_strings(old)); fdt_set_off_dt_strings(new, strings_off); fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } int fdt_open_into(const void *fdt, void *buf, int bufsize) { int err; int mem_rsv_size, struct_size; int newsize; const char *fdtstart = fdt; const char *fdtend = fdtstart + fdt_totalsize(fdt); char *tmp; FDT_CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); if (fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); } else { struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; } if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) { /* no further work necessary */ err = fdt_move(fdt, buf, bufsize); if (err) return err; fdt_set_version(buf, 17); fdt_set_size_dt_struct(buf, struct_size); fdt_set_totalsize(buf, bufsize); return 0; } /* Need to reorder */ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + struct_size + fdt_size_dt_strings(fdt); if (bufsize < newsize) return -FDT_ERR_NOSPACE; /* First attempt to build converted tree at beginning of buffer */ tmp = buf; /* But if that overlaps with the old tree... */ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { /* Try right after the old tree instead */ tmp = (char *)(uintptr_t)fdtend; if ((tmp + newsize) > ((char *)buf + bufsize)) return -FDT_ERR_NOSPACE; } _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size); memmove(buf, tmp, newsize); fdt_set_magic(buf, FDT_MAGIC); fdt_set_totalsize(buf, bufsize); fdt_set_version(buf, 17); fdt_set_last_comp_version(buf, 16); fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); return 0; } int fdt_pack(void *fdt) { int mem_rsv_size; FDT_RW_CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); fdt_set_totalsize(fdt, _fdt_data_size(fdt)); return 0; } kexec-tools-2.0.10/kexec/libfdt/fdt_strerror.c0000644001567400156740000000651112242534555020355 0ustar hormshorms/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" struct fdt_errtabent { const char *str; }; #define FDT_ERRTABENT(val) \ [(val)] = { .str = #val, } static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_NOTFOUND), FDT_ERRTABENT(FDT_ERR_EXISTS), FDT_ERRTABENT(FDT_ERR_NOSPACE), FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADPATH), FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_TRUNCATED), FDT_ERRTABENT(FDT_ERR_BADMAGIC), FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) const char *fdt_strerror(int errval) { if (errval > 0) return ""; else if (errval == 0) return ""; else if (errval > -FDT_ERRTABSIZE) { const char *s = fdt_errtable[-errval].str; if (s) return s; } return ""; } kexec-tools-2.0.10/kexec/libfdt/fdt.c0000644001567400156740000000000012242534555024632 1kexec-tools-2.0.10/kexec/libfdt/fdt.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_ro.c0000644001567400156740000000000012242534555026032 1kexec-tools-2.0.10/kexec/libfdt/fdt_ro.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_wip.c0000644001567400156740000000000012242534555026370 1kexec-tools-2.0.10/kexec/libfdt/fdt_wip.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_sw.c0000644001567400156740000000000012242534555026054 1kexec-tools-2.0.10/kexec/libfdt/fdt_sw.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_rw.c0000644001567400156740000000000012242534555026052 1kexec-tools-2.0.10/kexec/libfdt/fdt_rw.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_strerror.c0000644001567400156740000000000012242534555030536 1kexec-tools-2.0.10/kexec/libfdt/fdt_strerror.custar hormshormskexec-tools-2.0.10/kexec/arch/arm/phys_to_virt.c0000644001567400156740000000107011642166046020611 0ustar hormshorms#include "../../kexec.h" #include "../../crashdump.h" #include "crashdump-arm.h" /** * phys_to_virt() - translate physical address to virtual address * @paddr: physical address to translate * * For ARM we have following equation to translate from virtual address to * physical: * paddr = vaddr - PAGE_OFFSET + PHYS_OFFSET * * See also: * http://lists.arm.linux.org.uk/lurker/message/20010723.185051.94ce743c.en.html */ unsigned long phys_to_virt(struct crash_elf_info *elf_info, unsigned long paddr) { return paddr + elf_info->page_offset - phys_offset; } kexec-tools-2.0.10/kexec/arch/arm/crashdump-arm.h0000644001567400156740000000070612417126536020636 0ustar hormshorms#ifndef CRASHDUMP_ARM_H #define CRASHDUMP_ARM_H #ifdef __cplusplus extern "C" { #endif #define COMMAND_LINE_SIZE 1024 #define DEFAULT_PAGE_OFFSET (0xc0000000) #define KVBASE_MASK (0x1ffffff) #define CRASH_MAX_MEMORY_RANGES 32 extern struct memory_ranges usablemem_rgns; struct kexec_info; extern unsigned long phys_offset; extern int load_crashdump_segments(struct kexec_info *, char *); #ifdef __cplusplus } #endif #endif /* CRASHDUMP_ARM_H */ kexec-tools-2.0.10/kexec/arch/arm/kexec-arm.h0000644001567400156740000000104212242534555017741 0ustar hormshorms#ifndef KEXEC_ARM_H #define KEXEC_ARM_H #include #define BOOT_BLOCK_VERSION 17 #define BOOT_BLOCK_LAST_COMP_VERSION 16 extern off_t initrd_base, initrd_size; int zImage_arm_probe(const char *buf, off_t len); int zImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void zImage_arm_usage(void); int uImage_arm_probe(const char *buf, off_t len); int uImage_arm_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); #endif /* KEXEC_ARM_H */ kexec-tools-2.0.10/kexec/arch/arm/include/arch/options.h0000644001567400156740000000331312417126536022123 0ustar hormshorms#ifndef KEXEC_ARCH_ARM_OPTIONS_H #define KEXEC_ARCH_ARM_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) #define OPT_APPEND 'a' #define OPT_RAMDISK 'r' #define OPT_DTB (OPT_ARCH_MAX+0) #define OPT_ATAGS (OPT_ARCH_MAX+1) #define OPT_IMAGE_SIZE (OPT_ARCH_MAX+2) #define OPT_PAGE_OFFSET (OPT_ARCH_MAX+3) /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ { "command-line", 1, 0, OPT_APPEND }, \ { "append", 1, 0, OPT_APPEND }, \ { "initrd", 1, 0, OPT_RAMDISK }, \ { "ramdisk", 1, 0, OPT_RAMDISK }, \ { "dtb", 1, 0, OPT_DTB }, \ { "atags", 0, 0, OPT_ATAGS }, \ { "image-size", 1, 0, OPT_IMAGE_SIZE }, \ { "page-offset", 1, 0, OPT_PAGE_OFFSET }, #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR "a:r:s:" extern unsigned int kexec_arm_image_size; #endif /* KEXEC_ARCH_ARM_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/i386/Makefile0000644001567400156740000000137011424244110017254 0ustar hormshorms# # kexec i386 (linux booting linux) # i386_KEXEC_SRCS = kexec/arch/i386/kexec-x86.c i386_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-x86.c i386_KEXEC_SRCS += kexec/arch/i386/kexec-elf-rel-x86.c i386_KEXEC_SRCS += kexec/arch/i386/kexec-bzImage.c i386_KEXEC_SRCS += kexec/arch/i386/kexec-multiboot-x86.c i386_KEXEC_SRCS += kexec/arch/i386/kexec-beoboot-x86.c i386_KEXEC_SRCS += kexec/arch/i386/kexec-nbi.c i386_KEXEC_SRCS += kexec/arch/i386/x86-linux-setup.c i386_KEXEC_SRCS += kexec/arch/i386/crashdump-x86.c dist += kexec/arch/i386/Makefile $(i386_KEXEC_SRCS) \ kexec/arch/i386/kexec-x86.h kexec/arch/i386/crashdump-x86.h \ kexec/arch/i386/x86-linux-setup.h \ kexec/arch/i386/include/arch/options.h kexec-tools-2.0.10/kexec/arch/i386/kexec-x86.c0000644001567400156740000001406612417126536017526 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "../../firmware_memmap.h" #include "kexec-x86.h" #include "crashdump-x86.h" #include 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= Specify the serial port for debug output\n" " --serial-baud= Specify the serial port baud rate\n" " --console-vga Enable the vga console\n" " --console-serial Enable the serial console\n" " --elf32-core-headers Prepare core headers in ELF32 format\n" " --elf64-core-headers Prepare core headers in ELF64 format\n" " --pass-memmap-cmdline Pass memory map via command line in kexec on panic case\n" " --noefi Disable efi support\n" ); } struct arch_options_t arch_options = { .reset_vga = 0, .serial_base = 0x3f8, .serial_baud = 0, .console_vga = 0, .console_serial = 0, .core_header_type = CORE_TYPE_UNDEF, .pass_memmap_cmdline = 0, .noefi = 0, }; int arch_process_options(int argc, char **argv) { static const struct option options[] = { KEXEC_ALL_OPTIONS { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_ALL_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; case OPT_ELF32_CORE: arch_options.core_header_type = CORE_TYPE_ELF32; break; case OPT_ELF64_CORE: arch_options.core_header_type = CORE_TYPE_ELF64; break; case OPT_PASS_MEMMAP_CMDLINE: arch_options.pass_memmap_cmdline = 1; break; case OPT_NOEFI: arch_options.noefi = 1; break; } } /* Reset getopt for the next pass; called in other source modules */ opterr = 1; optind = 1; return 0; } const struct arch_map_entry arches[] = { /* For compatibility with older patches * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_386 here. */ { "i386", KEXEC_ARCH_DEFAULT }, { "i486", KEXEC_ARCH_DEFAULT }, { "i586", KEXEC_ARCH_DEFAULT }, { "i686", KEXEC_ARCH_DEFAULT }, { "x86_64", KEXEC_ARCH_X86_64 }, { 0, 0 }, }; int arch_compat_trampoline(struct kexec_info *info) { if ((info->kexec_flags & KEXEC_ARCH_MASK) == 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 = (void *)elf_rel_get_addr(&info->rhdr, "compat_x86_64"); } return 0; } void arch_update_purgatory(struct kexec_info *info) { uint8_t panic_kernel = 0; 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)); elf_rel_set_symbol(&info->rhdr, "backup_src_start", &info->backup_src_start, sizeof(info->backup_src_start)); elf_rel_set_symbol(&info->rhdr, "backup_src_size", &info->backup_src_size, sizeof(info->backup_src_size)); if (info->kexec_flags & KEXEC_ON_CRASH) { panic_kernel = 1; elf_rel_set_symbol(&info->rhdr, "backup_start", &info->backup_start, sizeof(info->backup_start)); } elf_rel_set_symbol(&info->rhdr, "panic_kernel", &panic_kernel, sizeof(panic_kernel)); } kexec-tools-2.0.10/kexec/arch/i386/kexec-x86-common.c0000644001567400156740000002237712502666571021023 0ustar hormshorms/* * 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 _XOPEN_SOURCE 600 #define _BSD_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../firmware_memmap.h" #include "../../crashdump.h" #include "kexec-x86.h" #ifdef HAVE_LIBXENCTRL #include #endif /* HAVE_LIBXENCTRL */ static struct memory_range memory_range[MAX_MEMORY_RANGES]; /** * The old /proc/iomem parsing code. * * @param[out] range pointer that will be set to an array that holds the * memory ranges * @param[out] ranges number of ranges valid in @p range * * @return 0 on success, any other value on failure. */ static int get_memory_ranges_proc_iomem(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; dbgprintf("%016Lx-%016Lx : %s", start, end, str); 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; dbgprintf("%016Lx-%016Lx : %x\n", start, end, type); memory_ranges++; } fclose(fp); *range = memory_range; *ranges = memory_ranges; return 0; } /** * Calls the architecture independent get_firmware_memmap_ranges() to parse * /sys/firmware/memmap and then do some x86 only modifications. * * @param[out] range pointer that will be set to an array that holds the * memory ranges * @param[out] ranges number of ranges valid in @p range * * @return 0 on success, any other value on failure. */ static int get_memory_ranges_sysfs(struct memory_range **range, int *ranges) { int ret; size_t range_number = MAX_MEMORY_RANGES; ret = get_firmware_memmap_ranges(memory_range, &range_number); if (ret != 0) { fprintf(stderr, "Parsing the /sys/firmware memory map failed. " "Falling back to /proc/iomem.\n"); return get_memory_ranges_proc_iomem(range, ranges); } *range = memory_range; *ranges = range_number; return 0; } #ifdef HAVE_LIBXENCTRL unsigned xen_e820_to_kexec_type(uint32_t type) { switch (type) { case E820_RAM: return RANGE_RAM; case E820_ACPI: return RANGE_ACPI; case E820_NVS: return RANGE_ACPI_NVS; case E820_RESERVED: default: return RANGE_RESERVED; } } /** * Memory map detection for Xen. * * @param[out] range pointer that will be set to an array that holds the * memory ranges * @param[out] ranges number of ranges valid in @p range * * @return 0 on success, any other value on failure. */ static int get_memory_ranges_xen(struct memory_range **range, int *ranges) { int rc, ret = -1; struct e820entry e820entries[MAX_MEMORY_RANGES]; unsigned int i; xc_interface *xc; xc = xc_interface_open(NULL, NULL, 0); if (!xc) { fprintf(stderr, "%s: Failed to open Xen control interface\n", __func__); return -1; } rc = xc_get_machine_memory_map(xc, e820entries, MAX_MEMORY_RANGES); if (rc < 0) { fprintf(stderr, "%s: xc_get_machine_memory_map: %s\n", __func__, strerror(rc)); goto err; } for (i = 0; i < rc; ++i) { memory_range[i].start = e820entries[i].addr; memory_range[i].end = e820entries[i].addr + e820entries[i].size - 1; memory_range[i].type = xen_e820_to_kexec_type(e820entries[i].type); } qsort(memory_range, rc, sizeof(struct memory_range), compare_ranges); *range = memory_range; *ranges = rc; ret = 0; err: xc_interface_close(xc); return ret; } #else static int get_memory_ranges_xen(struct memory_range **range, int *ranges) { return 0; } #endif /* HAVE_LIBXENCTRL */ static void remove_range(struct memory_range *range, int nr_ranges, int index) { int i, j; for (i = index; i < (nr_ranges-1); i++) { j = i+1; range[i] = range[j]; } } /** * Verifies and corrects any overlapping ranges. * The ranges array is assumed to be sorted already. * * @param[out] range pointer that will be set to an array that holds the * memory ranges * @param[out] ranges number of ranges valid in @p range * * @return 0 on success, any other value on failure. */ static int fixup_memory_ranges(struct memory_range **range, int *ranges) { int i; int j; int change_made; int nr_ranges = *ranges; struct memory_range *rp = *range; again: change_made = 0; for (i = 0; i < (nr_ranges-1); i++) { j = i+1; if (rp[i].start > rp[j].start) { fprintf(stderr, "memory out of order!!\n"); return 1; } if (rp[i].type != rp[j].type) continue; if (rp[i].start == rp[j].start) { if (rp[i].end >= rp[j].end) { remove_range(rp, nr_ranges, j); nr_ranges--; change_made++; } else { remove_range(rp, nr_ranges, i); nr_ranges--; change_made++; } } else { if (rp[i].end > rp[j].start) { if (rp[i].end < rp[j].end) { rp[j].start = rp[i].end; change_made++; } else if (rp[i].end >= rp[j].end) { remove_range(rp, nr_ranges, j); nr_ranges--; change_made++; } } } } /* fixing/removing an entry may make it wrong relative to the next */ if (change_made) goto again; *ranges = nr_ranges; return 0; } /** * Detect the add_efi_memmap kernel parameter. * * On some EFI-based systems, the e820 map is empty, or does not contain a * complete memory map. The add_efi_memmap parameter adds these entries to * the kernel's memory map, but does not add them under sysfs, which causes * kexec to fail in a way similar to how it does not work on Xen. * * @return 1 if parameter is present, 0 if not or if an error occurs. */ int efi_map_added( void ) { char buf[512]; FILE *fp = fopen( "/proc/cmdline", "r" ); if( fp ) { fgets( buf, 512, fp ); fclose( fp ); return strstr( buf, "add_efi_memmap" ) != NULL; } else { return 0; } } /** * Return a sorted list of memory ranges. * * If we have the /sys/firmware/memmap interface, then use that. If not, * or if parsing of that fails, use /proc/iomem as fallback. * * @param[out] range pointer that will be set to an array that holds the * memory ranges * @param[out] ranges number of ranges valid in @p range * @param[in] kexec_flags the kexec_flags to determine if we load a normal * or a crashdump kernel * * @return 0 on success, any other value on failure. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { int ret, i; if (!efi_map_added() && !xen_present() && have_sys_firmware_memmap()) { ret = get_memory_ranges_sysfs(range, ranges); if (!ret) ret = fixup_memory_ranges(range, ranges); } else if (xen_present()) { ret = get_memory_ranges_xen(range, ranges); if (!ret) ret = fixup_memory_ranges(range, ranges); } else ret = get_memory_ranges_proc_iomem(range, ranges); /* * get_memory_ranges_sysfs(), get_memory_ranges_proc_iomem() and * get_memory_ranges_xen() have already printed an error message, * so fail silently here. */ if (ret != 0) return ret; /* Don't report the interrupt table as ram */ for (i = 0; i < *ranges; i++) { if ((*range)[i].type == RANGE_RAM && ((*range)[i].start < 0x100)) { (*range)[i].start = 0x100; break; } } /* * Redefine the memory region boundaries if kernel * exports the limits and if it is panic kernel. * Override user values only if kernel exported values are * subset of user defined values. */ if ((kexec_flags & KEXEC_ON_CRASH) && !(kexec_flags & KEXEC_PRESERVE_CONTEXT)) { uint64_t start, end; ret = get_max_crash_kernel_limit(&start, &end); if (ret != 0) { fprintf(stderr, "get_max_crash_kernel_limit failed.\n"); return -1; } if (start > mem_min) mem_min = start; if (end < mem_max) mem_max = end; } dbgprint_mem_range("MEMORY RANGES", *range, *ranges); return ret; } kexec-tools-2.0.10/kexec/arch/i386/kexec-elf-x86.c0000644001567400156740000002041312473251104020253 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../kexec-elf.h" #include "../../kexec-elf-boot.h" #include "x86-linux-setup.h" #include "kexec-x86.h" #include "crashdump-x86.h" #include 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, 0); 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 i386 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" " --reuse-cmdline Use kernel command line from running system.\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; char *command_line = NULL, *modified_cmdline = NULL; const char *append = NULL; char *tmp_cmdline = NULL; char *error_msg = NULL; int result; 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; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, NULL, OPT_APPEND }, { "append", 1, NULL, OPT_APPEND }, { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, { "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; ramdisk = 0; result = 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 OPT_APPEND: append = optarg; break; case OPT_REUSE_CMDLINE: tmp_cmdline = get_command_line(); 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 = concat_cmdline(tmp_cmdline, append); if (tmp_cmdline) { free(tmp_cmdline); } command_line_len = 0; if (command_line) { command_line_len = strlen(command_line) +1; } else { command_line = strdup("\0"); command_line_len = 1; } /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & (KEXEC_ON_CRASH|KEXEC_PRESERVE_CONTEXT)) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (command_line) { strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } } /* Load the ELF executable */ elf_exec_build_load(info, &ehdr, buf, len, 0); 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, 0); } 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) { error_msg = "Ramdisks not supported with generic elf arguments"; goto out; } } else if (arg_style == ARG_STYLE_LINUX) { struct x86_linux_faked_param_header *hdr; unsigned long param_base; const char *ramdisk_buf; off_t ramdisk_length; struct entry32_regs regs; int rc = 0; /* Get the linux parameter header */ hdr = xmalloc(sizeof(*hdr)); /* Hack: With some ld versions, vmlinux program headers show * a gap of two pages between bss segment and data segment * but effectively kernel considers it as bss segment and * overwrites the any data placed there. Hence bloat the * memsz of parameter segment to 16K to avoid being placed * in such gaps. * This is a makeshift solution until it is fixed in kernel */ param_base = add_buffer(info, hdr, sizeof(*hdr), 16*1024, 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) { ramdisk_buf = slurp_file(ramdisk, &ramdisk_length); } /* If panic kernel is being loaded, additional segments need * to be created. */ if (info->kexec_flags & (KEXEC_ON_CRASH|KEXEC_PRESERVE_CONTEXT)) { rc = load_crashdump_segments(info, modified_cmdline, max_addr, 0); if (rc < 0) { result = -1; goto out; } /* Use new command line. */ free(command_line); command_line = modified_cmdline; command_line_len = strlen(modified_cmdline) + 1; modified_cmdline = NULL; } /* 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(info, &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 { error_msg = "Unknown argument style\n"; } out: free(command_line); free(modified_cmdline); if (error_msg) die(error_msg); return result; } kexec-tools-2.0.10/kexec/arch/i386/kexec-elf-rel-x86.c0000644001567400156740000000131011642166046021035 0ustar hormshorms#include #include #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 *UNUSED(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; } } kexec-tools-2.0.10/kexec/arch/i386/kexec-bzImage.c0000644001567400156740000003272312473250770020457 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) 2003-2010 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "kexec-x86.h" #include "x86-linux-setup.h" #include "crashdump-x86.h" #include static const int probe_debug = 0; int bzImage_support_efi_boot = 0; int bzImage_probe(const char *buf, off_t len) { const struct x86_linux_header *header; if ((uintmax_t)len < (uintmax_t)(2 * 512)) { if (probe_debug) { fprintf(stderr, "File is too short to be a bzImage!\n"); } return -1; } header = (const struct x86_linux_header *)buf; 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( " --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" " --reuse-cmdline Use kernel command line from running system.\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) { struct x86_linux_header setup_header; struct x86_linux_param_header *real_mode; int setup_sects; size_t size; int kern16_size; unsigned long setup_base, setup_size; struct entry32_regs regs32; struct entry16_regs regs16; unsigned int relocatable_kernel = 0; unsigned long kernel32_load_addr; char *modified_cmdline; unsigned long cmdline_end; unsigned long kern16_size_needed; unsigned long heap_size = 0; /* * Find out about the file I am about to load. */ if ((uintmax_t)kernel_len < (uintmax_t)(2 * 512)) { 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; if (kernel_len < kern16_size) { fprintf(stderr, "BzImage truncated?\n"); return -1; } if (setup_header.protocol_version >= 0x0206) { if ((uintmax_t)command_line_len > (uintmax_t)setup_header.cmdline_size) { dbgprintf("Kernel command line too long for kernel!\n"); return -1; } } else { if (command_line_len > 255) { dbgprintf("WARNING: This kernel may only support 255 byte command lines\n"); } } if (setup_header.protocol_version >= 0x0205) { relocatable_kernel = setup_header.relocatable_kernel; dbgprintf("bzImage is relocatable\n"); } /* Can't use bzImage for crash dump purposes with real mode entry */ if((info->kexec_flags & KEXEC_ON_CRASH) && real_mode_entry) { fprintf(stderr, "Can't use bzImage for crash dump purposes" " with real mode entry\n"); return -1; } if((info->kexec_flags & KEXEC_ON_CRASH) && !relocatable_kernel) { fprintf(stderr, "BzImage is not relocatable. Can't be used" " as capture kernel.\n"); return -1; } /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (command_line) { strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } /* If panic kernel is being loaded, additional segments need * to be created. load_crashdump_segments will take care of * loading the segments as high in memory as possible, hence * in turn as away as possible from kernel to avoid being * stomped by the kernel. */ if (load_crashdump_segments(info, modified_cmdline, -1, 0) < 0) return -1; /* Use new command line buffer */ command_line = modified_cmdline; command_line_len = strlen(command_line) +1; } /* Load the trampoline. This must load at a higher address * than the argument/parameter segment or the kernel will stomp * it's gdt. * * x86_64 purgatory code has got relocations type R_X86_64_32S * that means purgatory got to be loaded within first 2G otherwise * overflow takes place while applying relocations. */ if (!real_mode_entry && relocatable_kernel) elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0x3000, 0x7fffffff, -1, 0); else elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0x3000, 640*1024, -1, 0); dbgprintf("Loaded purgatory at addr 0x%lx\n", info->rhdr.rel_addr); /* The argument/parameter segment */ if (real_mode_entry) { /* need to include size for bss and heap etc */ if (setup_header.protocol_version >= 0x0201) kern16_size_needed = setup_header.heap_end_ptr; else kern16_size_needed = kern16_size + 8192; /* bss */ if (kern16_size_needed < kern16_size) kern16_size_needed = kern16_size; if (kern16_size_needed > 0xfffc) die("kern16_size_needed is more then 64k\n"); heap_size = 0xfffc - kern16_size_needed; /* less 64k */ heap_size = _ALIGN_DOWN(heap_size, 0x200); kern16_size_needed += heap_size; } else { kern16_size_needed = kern16_size; /* need to bigger than size of struct bootparams */ if (kern16_size_needed < 4096) kern16_size_needed = 4096; } setup_size = kern16_size_needed + command_line_len + PURGATORY_CMDLINE_SIZE; real_mode = xmalloc(setup_size); memset(real_mode, 0, setup_size); if (!real_mode_entry) { unsigned long setup_header_size = kernel[0x201] + 0x202 - 0x1f1; /* only copy setup_header */ if (setup_header_size > 0x7f) setup_header_size = 0x7f; memcpy((unsigned char *)real_mode + 0x1f1, kernel + 0x1f1, setup_header_size); } else { /* copy setup code and setup_header */ memcpy(real_mode, kernel, kern16_size); } if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) { /* If using bzImage for capture kernel, then we will not be * executing real mode code. setup segment can be loaded * anywhere as we will be just reading command line. */ setup_base = add_buffer(info, real_mode, setup_size, setup_size, 16, 0x3000, -1, -1); } else 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; } dbgprintf("Loaded real-mode code and command line at 0x%lx\n", 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; if (real_mode->protocol_version >=0x0205 && relocatable_kernel) { /* Relocatable bzImage */ unsigned long kern_align = real_mode->kernel_alignment; unsigned long kernel32_max_addr = DEFAULT_BZIMAGE_ADDR_MAX; if (kernel32_max_addr > real_mode->initrd_addr_max) kernel32_max_addr = real_mode->initrd_addr_max; kernel32_load_addr = add_buffer(info, kernel + kern16_size, size, size, kern_align, 0x100000, kernel32_max_addr, 1); } else { kernel32_load_addr = KERN32_BASE; add_segment(info, kernel + kern16_size, size, kernel32_load_addr, size); } dbgprintf("Loaded 32bit kernel at 0x%lx\n", kernel32_load_addr); /* Tell the kernel what is going on */ setup_linux_bootloader_parameters(info, real_mode, setup_base, kern16_size_needed, command_line, command_line_len, initrd, initrd_len); if (real_mode_entry && real_mode->protocol_version >= 0x0201) { real_mode->loader_flags |= 0x80; /* CAN_USE_HEAP */ real_mode->heap_end_ptr += heap_size - 0x200; /*stack*/ } /* Get the initial register values */ if (real_mode_entry) elf_rel_get_symbol(&info->rhdr, "entry16_regs", ®s16, sizeof(regs16)); /* * 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 = kernel32_load_addr; /* kernel entry point */ /* * Initialize the 16bit start information. */ if (real_mode_entry) { regs16.ds = regs16.es = regs16.fs = regs16.gs = setup_base >> 4; regs16.cs = regs16.ds + 0x20; regs16.ip = 0; /* XXX: Documentation/i386/boot.txt says 'ss' must equal 'ds' */ regs16.ss = (elf_rel_get_addr(&info->rhdr, "stack_end") - 64*1024) >> 4; /* XXX: Documentation/i386/boot.txt says 'sp' must equal heap_end */ regs16.esp = 0xFFFC; printf("Starting the kernel in real mode\n"); regs32.eip = elf_rel_get_addr(&info->rhdr, "entry16"); real_mode->kernel_start = kernel32_load_addr; } if (real_mode_entry && kexec_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; } if (real_mode_entry) { 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)); cmdline_end = setup_base + kern16_size_needed + command_line_len - 1; elf_rel_set_symbol(&info->rhdr, "cmdline_end", &cmdline_end, sizeof(unsigned long)); /* Fill in the information BIOS calls would normally provide. */ if (!real_mode_entry) { setup_linux_system_parameters(info, real_mode); } return 0; } int bzImage_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { char *command_line = NULL; char *tmp_cmdline = NULL; const char *ramdisk, *append = NULL; char *ramdisk_buf; off_t ramdisk_length; int command_line_len; int real_mode_entry; int opt; int result; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "reuse-cmdline", 0, 0, OPT_REUSE_CMDLINE }, { "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"; real_mode_entry = 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 OPT_APPEND: append = optarg; break; case OPT_REUSE_CMDLINE: tmp_cmdline = get_command_line(); break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_REAL_MODE: real_mode_entry = 1; break; } } command_line = concat_cmdline(tmp_cmdline, append); if (tmp_cmdline) { free(tmp_cmdline); } command_line_len = 0; if (command_line) { command_line_len = strlen(command_line) +1; } else { command_line = strdup("\0"); command_line_len = 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); free(command_line); return result; } kexec-tools-2.0.10/kexec/arch/i386/kexec-multiboot-x86.c0000644001567400156740000002647112466760044021547 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "kexec-x86.h" #include /* From GNU GRUB */ #include #include /* Static storage */ static char headerbuf[MULTIBOOT_SEARCH]; static struct multiboot_header *mbh = NULL; #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(" --reuse-cmdline Use kernel command line from running system.\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; char *command_line = NULL, *tmp_cmdline = NULL; char *imagename, *cp, *append = NULL;; struct memory_range *range; int ranges; struct AddrRangeDesc *mmap; int command_line_len; int i, result; uint32_t u; int opt; int modules, mod_command_line_space; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_CL }, { "append", 1, 0, OPT_CL }, { "reuse-cmdline", 0, 0, OPT_REUSE_CMDLINE }, { "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_len = 0; modules = 0; mod_command_line_space = 0; result = 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 OPT_CL: append = optarg; break; case OPT_REUSE_CMDLINE: command_line = get_command_line(); break; case OPT_MOD: modules++; mod_command_line_space += strlen(optarg) + 1; break; } } imagename = argv[optind]; /* Final command line = imagename + + */ tmp_cmdline = concat_cmdline(command_line, append); if (command_line) { free(command_line); } command_line = concat_cmdline(imagename, tmp_cmdline); if (tmp_cmdline) { free(tmp_cmdline); } command_line_len = strlen(command_line) + 1; /* Load the ELF executable */ elf_exec_build_load(info, &ehdr, buf, len, 0); /* Load the setup code */ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0, ULONG_MAX, 1, 0); /* The first segment will contain the multiboot headers: * ============= * multiboot information (mbi) * ------------- * kernel command line * ------------- * bootloader name * ------------- * module information entries * ------------- * module command lines * ============== */ mbi_bytes = _ALIGN(sizeof(*mbi) + command_line_len + strlen (BOOTLOADER " " BOOTLOADER_VERSION) + 1, 4); mbi_buf = xmalloc(mbi_bytes); mbi = mbi_buf; memset(mbi, 0, sizeof(*mbi)); sprintf(((char *)mbi) + sizeof(*mbi), "%s", 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 */ range = info->memory_range; ranges = info->memory_ranges; mmap = xmalloc(ranges * sizeof(*mmap)); for (i=0; i> 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? Can't just test * against zero, because Linux protects (and * hides) the first few pages of physical * memory. */ if ((range[i].start <= 64*1024) && (range[i].end > mem_lower)) { range[i].start = 0; 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, getpagesize(), 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) { result = -1; goto out; } 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 (u = 0; u < mbi->mods_count; u++) { modp[u].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)); out: free(command_line); return result; } /* * EOF (kexec-multiboot-x86.c) */ kexec-tools-2.0.10/kexec/arch/i386/kexec-beoboot-x86.c0000644001567400156740000000673612417126536021162 0ustar hormshorms/*------------------------------------------------------------ -*- C -*- * Eric Biederman * Erik Arjan Hendriks * * 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 #include #include #include #include #include #include "../../kexec.h" #include "kexec-x86.h" #include int beoboot_probe(const char *buf, off_t len) { struct beoboot_header bb_header; const char *cmdline, *kernel; int result; if ((uintmax_t)len < (uintmax_t)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( " --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 UNUSED(len), struct kexec_info *info) { struct beoboot_header bb_header; const char *command_line, *kernel, *initrd; int real_mode_entry; int opt; int result; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "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 */ 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 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); return result; } kexec-tools-2.0.10/kexec/arch/i386/kexec-nbi.c0000644001567400156740000001452712417126536017653 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-elf-boot.h" #include "kexec-x86.h" #include 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 (((uintmax_t)len < (uintmax_t)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 UNUSED(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; } } } /* 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; } else { printf("warning: unhandled segment of type %0x\n", seg.flags & NBI_SEG); continue; } 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; } kexec-tools-2.0.10/kexec/arch/i386/x86-linux-setup.c0000644001567400156740000005322512417126536020724 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "kexec-x86.h" #include "x86-linux-setup.h" #include "../../kexec/kexec-syscall.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 = 0x0206; real_mode->initrd_addr_max = DEFAULT_INITRD_ADDR_MAX; real_mode->cmdline_size = COMMAND_LINE_SIZE; } void setup_linux_bootloader_parameters_high( 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 char *initrd_buf, off_t initrd_size, int initrd_high) { char *cmdline_ptr; unsigned long initrd_base, initrd_addr_max; /* Say I'm a boot loader */ real_mode->loader_type = LOADER_TYPE_KEXEC << 4; /* No loader flags */ real_mode->loader_flags = 0; /* Find the maximum initial ramdisk address */ if (initrd_high) initrd_addr_max = ULONG_MAX; else { initrd_addr_max = DEFAULT_INITRD_ADDR_MAX; if (real_mode->protocol_version >= 0x0203) { initrd_addr_max = real_mode->initrd_addr_max; dbgprintf("initrd_addr_max is 0x%lx\n", 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); dbgprintf("Loaded initrd at 0x%lx size 0x%lx\n", initrd_base, initrd_size); } else { initrd_base = 0; initrd_size = 0; } /* Ramdisk address and size */ real_mode->initrd_start = initrd_base & 0xffffffffUL; real_mode->initrd_size = initrd_size & 0xffffffffUL; if (real_mode->protocol_version >= 0x020c && (initrd_base & 0xffffffffUL) != initrd_base) real_mode->ext_ramdisk_image = initrd_base >> 32; if (real_mode->protocol_version >= 0x020c && (initrd_size & 0xffffffffUL) != initrd_size) real_mode->ext_ramdisk_size = initrd_size >> 32; /* 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) { unsigned long cmd_line_ptr = real_mode_base + cmdline_offset; real_mode->cmd_line_ptr = cmd_line_ptr & 0xffffffffUL; if ((real_mode->protocol_version >= 0x020c) && ((cmd_line_ptr & 0xffffffffUL) != cmd_line_ptr)) real_mode->ext_cmd_line_ptr = cmd_line_ptr >> 32; } /* 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'; } int setup_linux_vesafb(struct x86_linux_param_header *real_mode) { struct fb_fix_screeninfo fix; struct fb_var_screeninfo var; int fd; fd = open("/dev/fb0", O_RDONLY); if (-1 == fd) return -1; if (-1 == ioctl(fd, FBIOGET_FSCREENINFO, &fix)) goto out; if (-1 == ioctl(fd, FBIOGET_VSCREENINFO, &var)) goto out; if (0 == strcmp(fix.id, "VESA VGA")) { /* VIDEO_TYPE_VLFB */ real_mode->orig_video_isVGA = 0x23; } else if (0 == strcmp(fix.id, "EFI VGA")) { /* VIDEO_TYPE_EFI */ real_mode->orig_video_isVGA = 0x70; } else { /* cannot handle and other types */ goto out; } close(fd); real_mode->lfb_width = var.xres; real_mode->lfb_height = var.yres; real_mode->lfb_depth = var.bits_per_pixel; real_mode->lfb_base = fix.smem_start; real_mode->lfb_linelength = fix.line_length; real_mode->vesapm_seg = 0; /* FIXME: better get size from the file returned by proc_iomem() */ real_mode->lfb_size = (fix.smem_len + 65535) / 65536; real_mode->pages = (fix.smem_len + 4095) / 4096; if (var.bits_per_pixel > 8) { real_mode->red_pos = var.red.offset; real_mode->red_size = var.red.length; real_mode->green_pos = var.green.offset; real_mode->green_size = var.green.length; real_mode->blue_pos = var.blue.offset; real_mode->blue_size = var.blue.length; real_mode->rsvd_pos = var.transp.offset; real_mode->rsvd_size = var.transp.length; } return 0; out: close(fd); return -1; } #define EDD_SYFS_DIR "/sys/firmware/edd" #define EDD_EXT_FIXED_DISK_ACCESS (1 << 0) #define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1) #define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2) #define EDD_EXT_64BIT_EXTENSIONS (1 << 3) /* * Scans one line from a given filename. Returns on success the number of * items written (same like scanf()). */ static int file_scanf(const char *dir, const char *file, const char *scanf_line, ...) { va_list argptr; FILE *fp; int retno; char filename[PATH_MAX]; snprintf(filename, PATH_MAX, "%s/%s", dir, file); filename[PATH_MAX-1] = 0; fp = fopen(filename, "r"); if (!fp) { return -errno; } va_start(argptr, scanf_line); retno = vfscanf(fp, scanf_line, argptr); va_end(argptr); fclose(fp); return retno; } static int parse_edd_extensions(const char *dir, struct edd_info *edd_info) { char filename[PATH_MAX]; char line[1024]; uint16_t flags = 0; FILE *fp; snprintf(filename, PATH_MAX, "%s/%s", dir, "extensions"); filename[PATH_MAX-1] = 0; fp = fopen(filename, "r"); if (!fp) { return -errno; } while (fgets(line, 1024, fp)) { /* * strings are in kernel source, function edd_show_extensions() * drivers/firmware/edd.c */ if (strstr(line, "Fixed disk access") == line) flags |= EDD_EXT_FIXED_DISK_ACCESS; else if (strstr(line, "Device locking and ejecting") == line) flags |= EDD_EXT_DEVICE_LOCKING_AND_EJECTING; else if (strstr(line, "Enhanced Disk Drive support") == line) flags |= EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT; else if (strstr(line, "64-bit extensions") == line) flags |= EDD_EXT_64BIT_EXTENSIONS; } fclose(fp); edd_info->interface_support = flags; return 0; } static int read_edd_raw_data(const char *dir, struct edd_info *edd_info) { char filename[PATH_MAX]; FILE *fp; size_t read_chars; uint16_t len; snprintf(filename, PATH_MAX, "%s/%s", dir, "raw_data"); filename[PATH_MAX-1] = 0; fp = fopen(filename, "r"); if (!fp) { return -errno; } memset(edd_info->edd_device_params, 0, EDD_DEVICE_PARAM_SIZE); read_chars = fread(edd_info->edd_device_params, sizeof(uint8_t), EDD_DEVICE_PARAM_SIZE, fp); fclose(fp); len = ((uint16_t *)edd_info->edd_device_params)[0]; dbgprintf("EDD raw data has length %d\n", len); if (read_chars < len) { fprintf(stderr, "BIOS reported EDD length of %hd but only " "%d chars read.\n", len, (int)read_chars); return -1; } return 0; } static int add_edd_entry(struct x86_linux_param_header *real_mode, const char *sysfs_name, int *current_edd, int *current_mbr) { uint8_t devnum, version; uint32_t mbr_sig; struct edd_info *edd_info; if (!current_mbr || !current_edd) { fprintf(stderr, "%s: current_edd and current_edd " "must not be NULL", __FUNCTION__); return -1; } edd_info = &real_mode->eddbuf[*current_edd]; memset(edd_info, 0, sizeof(struct edd_info)); /* extract the device number */ if (sscanf(basename(sysfs_name), "int13_dev%hhx", &devnum) != 1) { fprintf(stderr, "Invalid format of int13_dev dir " "entry: %s\n", basename(sysfs_name)); return -1; } /* if there's a MBR signature, then add it */ if (file_scanf(sysfs_name, "mbr_signature", "0x%x", &mbr_sig) == 1) { real_mode->edd_mbr_sig_buffer[*current_mbr] = mbr_sig; (*current_mbr)++; dbgprintf("EDD Device 0x%x: mbr_sig=0x%x\n", devnum, mbr_sig); } /* set the device number */ edd_info->device = devnum; /* set the version */ if (file_scanf(sysfs_name, "version", "0x%hhx", &version) != 1) return -1; edd_info->version = version; /* if version == 0, that's some kind of dummy entry */ if (version != 0) { /* legacy_max_cylinder */ if (file_scanf(sysfs_name, "legacy_max_cylinder", "%hu", &edd_info->legacy_max_cylinder) != 1) { fprintf(stderr, "Reading legacy_max_cylinder failed.\n"); return -1; } /* legacy_max_head */ if (file_scanf(sysfs_name, "legacy_max_head", "%hhu", &edd_info->legacy_max_head) != 1) { fprintf(stderr, "Reading legacy_max_head failed.\n"); return -1; } /* legacy_sectors_per_track */ if (file_scanf(sysfs_name, "legacy_sectors_per_track", "%hhu", &edd_info->legacy_sectors_per_track) != 1) { fprintf(stderr, "Reading legacy_sectors_per_track failed.\n"); return -1; } /* Parse the EDD extensions */ if (parse_edd_extensions(sysfs_name, edd_info) != 0) { fprintf(stderr, "Parsing EDD extensions failed.\n"); return -1; } /* Parse the raw info */ if (read_edd_raw_data(sysfs_name, edd_info) != 0) { fprintf(stderr, "Reading EDD raw data failed.\n"); return -1; } } (*current_edd)++; return 0; } static void zero_edd(struct x86_linux_param_header *real_mode) { real_mode->eddbuf_entries = 0; real_mode->edd_mbr_sig_buf_entries = 0; memset(real_mode->eddbuf, 0, EDDMAXNR * sizeof(struct edd_info)); memset(real_mode->edd_mbr_sig_buffer, 0, EDD_MBR_SIG_MAX * sizeof(uint32_t)); } void setup_edd_info(struct x86_linux_param_header *real_mode) { DIR *edd_dir; struct dirent *cursor; int current_edd = 0; int current_mbr = 0; edd_dir = opendir(EDD_SYFS_DIR); if (!edd_dir) { dbgprintf(EDD_SYFS_DIR " does not exist.\n"); return; } zero_edd(real_mode); while ((cursor = readdir(edd_dir))) { char full_dir_name[PATH_MAX]; /* only read the entries that start with "int13_dev" */ if (strstr(cursor->d_name, "int13_dev") != cursor->d_name) continue; snprintf(full_dir_name, PATH_MAX, "%s/%s", EDD_SYFS_DIR, cursor->d_name); full_dir_name[PATH_MAX-1] = 0; if (add_edd_entry(real_mode, full_dir_name, ¤t_edd, ¤t_mbr) != 0) { zero_edd(real_mode); goto out; } } real_mode->eddbuf_entries = current_edd; real_mode->edd_mbr_sig_buf_entries = current_mbr; out: closedir(edd_dir); dbgprintf("Added %d EDD MBR entries and %d EDD entries.\n", real_mode->edd_mbr_sig_buf_entries, real_mode->eddbuf_entries); } /* * This really only makes sense for virtual filesystems that are only expected * to be mounted once (sysfs, debugsfs, proc), as it will return the first * instance listed in mtab. */ char *find_mnt_by_fsname(char *fsname) { FILE *mtab; struct mntent *mnt; char *mntdir; mtab = setmntent("/etc/mtab", "r"); if (!mtab) return NULL; for(mnt = getmntent(mtab); mnt; mnt = getmntent(mtab)) { if (strcmp(mnt->mnt_fsname, fsname) == 0) break; } mntdir = mnt ? strdup(mnt->mnt_dir) : NULL; endmntent(mtab); return mntdir; } static int get_bootparam(void *buf, off_t offset, size_t size) { int data_file; char *debugfs_mnt, *sysfs_mnt; char filename[PATH_MAX]; int err, has_sysfs_params = 0; sysfs_mnt = find_mnt_by_fsname("sysfs"); if (sysfs_mnt) { snprintf(filename, PATH_MAX, "%s/%s", sysfs_mnt, "kernel/boot_params/data"); free(sysfs_mnt); err = access(filename, F_OK); if (!err) has_sysfs_params = 1; } if (!has_sysfs_params) { debugfs_mnt = find_mnt_by_fsname("debugfs"); if (!debugfs_mnt) return 1; snprintf(filename, PATH_MAX, "%s/%s", debugfs_mnt, "boot_params/data"); free(debugfs_mnt); } data_file = open(filename, O_RDONLY); if (data_file < 0) return 1; if (lseek(data_file, offset, SEEK_SET) < 0) goto close; read(data_file, buf, size); close: close(data_file); return 0; } void setup_subarch(struct x86_linux_param_header *real_mode) { off_t offset = offsetof(typeof(*real_mode), hardware_subarch); get_bootparam(&real_mode->hardware_subarch, offset, sizeof(uint32_t)); } struct efi_mem_descriptor { uint32_t type; uint32_t pad; uint64_t phys_addr; uint64_t virt_addr; uint64_t num_pages; uint64_t attribute; }; struct efi_setup_data { uint64_t fw_vendor; uint64_t runtime; uint64_t tables; uint64_t smbios; uint64_t reserved[8]; }; struct setup_data { uint64_t next; uint32_t type; #define SETUP_NONE 0 #define SETUP_E820_EXT 1 #define SETUP_DTB 2 #define SETUP_PCI 3 #define SETUP_EFI 4 uint32_t len; uint8_t data[0]; } __attribute__((packed)); static int get_efi_value(const char *filename, const char *pattern, uint64_t *val) { FILE *fp; char line[1024], *s, *end; fp = fopen(filename, "r"); if (!fp) return 1; while (fgets(line, sizeof(line), fp) != 0) { s = strstr(line, pattern); if (!s) continue; *val = strtoull(s + strlen(pattern), &end, 16); if (*val == ULLONG_MAX) { fclose(fp); return 2; } break; } fclose(fp); return 0; } static int get_efi_values(struct efi_setup_data *esd) { int ret = 0; ret = get_efi_value("/sys/firmware/efi/systab", "SMBIOS=0x", &esd->smbios); ret |= get_efi_value("/sys/firmware/efi/fw_vendor", "0x", &esd->fw_vendor); ret |= get_efi_value("/sys/firmware/efi/runtime", "0x", &esd->runtime); ret |= get_efi_value("/sys/firmware/efi/config_table", "0x", &esd->tables); return ret; } static int get_efi_runtime_map(struct efi_mem_descriptor **map) { DIR *dirp; struct dirent *entry; char filename[1024]; struct efi_mem_descriptor md, *p = NULL; int nr_maps = 0; dirp = opendir("/sys/firmware/efi/runtime-map"); if (!dirp) return 0; while ((entry = readdir(dirp)) != NULL) { sprintf(filename, "/sys/firmware/efi/runtime-map/%s", (char *)entry->d_name); if (*entry->d_name == '.') continue; file_scanf(filename, "type", "0x%x", (unsigned int *)&md.type); file_scanf(filename, "phys_addr", "0x%llx", (unsigned long long *)&md.phys_addr); file_scanf(filename, "virt_addr", "0x%llx", (unsigned long long *)&md.virt_addr); file_scanf(filename, "num_pages", "0x%llx", (unsigned long long *)&md.num_pages); file_scanf(filename, "attribute", "0x%llx", (unsigned long long *)&md.attribute); p = realloc(p, (nr_maps + 1) * sizeof(md)); if (!p) goto err_out; *(p + nr_maps) = md; *map = p; nr_maps++; } closedir(dirp); return nr_maps; err_out: if (map) free(map); closedir(dirp); return 0; } struct efi_info { uint32_t efi_loader_signature; uint32_t efi_systab; uint32_t efi_memdesc_size; uint32_t efi_memdesc_version; uint32_t efi_memmap; uint32_t efi_memmap_size; uint32_t efi_systab_hi; uint32_t efi_memmap_hi; }; /* * Add another instance to single linked list of struct setup_data. * Please refer to kernel Documentation/x86/boot.txt for more details * about setup_data structure. */ static void add_setup_data(struct kexec_info *info, struct x86_linux_param_header *real_mode, struct setup_data *sd) { int sdsize = sizeof(struct setup_data) + sd->len; sd->next = real_mode->setup_data; real_mode->setup_data = add_buffer(info, sd, sdsize, sdsize, getpagesize(), 0x100000, ULONG_MAX, INT_MAX); } /* * setup_efi_data will collect below data and pass them to 2nd kernel. * 1) SMBIOS, fw_vendor, runtime, config_table, they are passed via x86 * setup_data. * 2) runtime memory regions, set the memmap related fields in efi_info. */ static int setup_efi_data(struct kexec_info *info, struct x86_linux_param_header *real_mode) { int64_t memmap_paddr; struct setup_data *sd; struct efi_setup_data *esd; struct efi_mem_descriptor *maps; int nr_maps, size, ret = 0; struct efi_info *ei = (struct efi_info *)real_mode->efi_info; ret = access("/sys/firmware/efi/systab", F_OK); if (ret < 0) goto out; esd = malloc(sizeof(struct efi_setup_data)); if (!esd) { ret = 1; goto out; } memset(esd, 0, sizeof(struct efi_setup_data)); ret = get_efi_values(esd); if (ret) goto free_esd; nr_maps = get_efi_runtime_map(&maps); if (!nr_maps) { ret = 2; goto free_esd; } sd = malloc(sizeof(struct setup_data) + sizeof(*esd)); if (!sd) { ret = 3; goto free_maps; } memset(sd, 0, sizeof(struct setup_data) + sizeof(*esd)); sd->next = 0; sd->type = SETUP_EFI; sd->len = sizeof(*esd); memcpy(sd->data, esd, sizeof(*esd)); free(esd); add_setup_data(info, real_mode, sd); size = nr_maps * sizeof(struct efi_mem_descriptor); memmap_paddr = add_buffer(info, maps, size, size, getpagesize(), 0x100000, ULONG_MAX, INT_MAX); ei->efi_memmap = memmap_paddr & 0xffffffff; ei->efi_memmap_hi = memmap_paddr >> 32; ei->efi_memmap_size = size; ei->efi_memdesc_size = sizeof(struct efi_mem_descriptor); return 0; free_maps: free(maps); free_esd: free(esd); out: return ret; } static void add_e820_map_from_mr(struct x86_linux_param_header *real_mode, struct e820entry *e820, struct memory_range *range, int nr_range) { int i; for (i = 0; i < nr_range; i++) { e820[i].addr = range[i].start; e820[i].size = range[i].end - range[i].start + 1; switch (range[i].type) { case RANGE_RAM: e820[i].type = E820_RAM; break; case RANGE_ACPI: e820[i].type = E820_ACPI; break; case RANGE_ACPI_NVS: e820[i].type = E820_NVS; break; default: case RANGE_RESERVED: e820[i].type = E820_RESERVED; break; } dbgprintf("%016lx-%016lx (%d)\n", e820[i].addr, e820[i].addr + e820[i].size - 1, e820[i].type); 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 >> 10); 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; } } } } static void setup_e820_ext(struct kexec_info *info, struct x86_linux_param_header *real_mode, struct memory_range *range, int nr_range) { struct setup_data *sd; struct e820entry *e820; int nr_range_ext; nr_range_ext = nr_range - E820MAX; sd = xmalloc(sizeof(struct setup_data) + nr_range_ext * sizeof(struct e820entry)); sd->next = 0; sd->len = nr_range_ext * sizeof(struct e820entry); sd->type = SETUP_E820_EXT; e820 = (struct e820entry *) sd->data; dbgprintf("Extended E820 via setup_data:\n"); add_e820_map_from_mr(real_mode, e820, range + E820MAX, nr_range_ext); add_setup_data(info, real_mode, sd); } static void setup_e820(struct kexec_info *info, struct x86_linux_param_header *real_mode) { struct memory_range *range; int nr_range, nr_range_saved; if (info->kexec_flags & KEXEC_ON_CRASH && !arch_options.pass_memmap_cmdline) { range = info->crash_range; nr_range = info->nr_crash_ranges; } else { range = info->memory_range; nr_range = info->memory_ranges; } nr_range_saved = nr_range; if (nr_range > E820MAX) { nr_range = E820MAX; } real_mode->e820_map_nr = nr_range; dbgprintf("E820 memmap:\n"); add_e820_map_from_mr(real_mode, real_mode->e820_map, range, nr_range); if (nr_range_saved > E820MAX) { dbgprintf("extra E820 memmap are passed via setup_data\n"); setup_e820_ext(info, real_mode, range, nr_range_saved); } } static int get_efi_mem_desc_version(struct x86_linux_param_header *real_mode) { struct efi_info *ei = (struct efi_info *)real_mode->efi_info; return ei->efi_memdesc_version; } static void setup_efi_info(struct kexec_info *info, struct x86_linux_param_header *real_mode) { int ret, desc_version; off_t offset = offsetof(typeof(*real_mode), efi_info); ret = get_bootparam(&real_mode->efi_info, offset, 32); if (ret) return; if (((struct efi_info *)real_mode->efi_info)->efi_memmap_size == 0) /* zero filled efi_info */ goto out; desc_version = get_efi_mem_desc_version(real_mode); if (desc_version != 1) { fprintf(stderr, "efi memory descriptor version %d is not supported!\n", desc_version); goto out; } ret = setup_efi_data(info, real_mode); if (ret) goto out; return; out: memset(&real_mode->efi_info, 0, 32); return; } void setup_linux_system_parameters(struct kexec_info *info, struct x86_linux_param_header *real_mode) { /* get subarch from running kernel */ setup_subarch(real_mode); if (bzImage_support_efi_boot && !arch_options.noefi) setup_efi_info(info, real_mode); /* 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; setup_linux_vesafb(real_mode); /* 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; setup_e820(info, real_mode); /* fill the EDD information */ setup_edd_info(real_mode); } kexec-tools-2.0.10/kexec/arch/i386/crashdump-x86.c0000644001567400156740000007323012473251174020412 0ustar hormshorms/* * kexec: Linux boots Linux * * Created by: Vivek Goyal (vgoyal@in.ibm.com) * old x86_64 version Created by: Murali M Chakravarthy (muralim@in.ibm.com) * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 _XOPEN_SOURCE 600 #define _BSD_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "../../firmware_memmap.h" #include "../../crashdump.h" #include "kexec-x86.h" #include "crashdump-x86.h" #ifdef HAVE_LIBXENCTRL #include #endif /* HAVE_LIBXENCTRL */ #include "x86-linux-setup.h" #include extern struct arch_options_t arch_options; static int get_kernel_page_offset(struct kexec_info *UNUSED(info), struct crash_elf_info *elf_info) { int kv; if (elf_info->machine == EM_X86_64) { kv = kernel_version(); if (kv < 0) return -1; if (kv < KERNEL_VERSION(2, 6, 27)) elf_info->page_offset = X86_64_PAGE_OFFSET_PRE_2_6_27; else elf_info->page_offset = X86_64_PAGE_OFFSET; } else if (elf_info->machine == EM_386) { elf_info->page_offset = X86_PAGE_OFFSET; } return 0; } #define X86_64_KERN_VADDR_ALIGN 0x100000 /* 1MB */ /* Read kernel physical load addr from the file returned by proc_iomem() * (Kernel Code) and store in kexec_info */ static int get_kernel_paddr(struct kexec_info *UNUSED(info), struct crash_elf_info *elf_info) { uint64_t start; if (elf_info->machine != EM_X86_64) return 0; if (xen_present()) /* Kernel not entity mapped under Xen */ return 0; if (parse_iomem_single("Kernel code\n", &start, NULL) == 0) { elf_info->kern_paddr_start = start; dbgprintf("kernel load physical addr start = 0x%016Lx\n", (unsigned long long)start); return 0; } fprintf(stderr, "Cannot determine kernel physical load addr\n"); return -1; } /* Retrieve kernel _stext symbol virtual address from /proc/kallsyms */ static unsigned long long get_kernel_stext_sym(void) { const char *kallsyms = "/proc/kallsyms"; const char *stext = "_stext"; char sym[128]; char line[128]; FILE *fp; unsigned long long vaddr; char type; fp = fopen(kallsyms, "r"); if (!fp) { fprintf(stderr, "Cannot open %s\n", kallsyms); return 0; } while(fgets(line, sizeof(line), fp) != NULL) { if (sscanf(line, "%Lx %c %s", &vaddr, &type, sym) != 3) continue; if (strcmp(sym, stext) == 0) { dbgprintf("kernel symbol %s vaddr = %16llx\n", stext, vaddr); return vaddr; } } fprintf(stderr, "Cannot get kernel %s symbol address\n", stext); return 0; } /* Retrieve info regarding virtual address kernel has been compiled for and * size of the kernel from /proc/kcore. Current /proc/kcore parsing from * from kexec-tools fails because of malformed elf notes. A kernel patch has * been submitted. For the folks using older kernels, this function * hard codes the values to remain backward compatible. Once things stablize * we should get rid of backward compatible code. */ static int get_kernel_vaddr_and_size(struct kexec_info *UNUSED(info), struct crash_elf_info *elf_info) { int result; const char kcore[] = "/proc/kcore"; char *buf; struct mem_ehdr ehdr; struct mem_phdr *phdr, *end_phdr; int align; off_t size; uint32_t elf_flags = 0; uint64_t stext_sym; if (elf_info->machine != EM_X86_64) return 0; if (xen_present()) /* Kernel not entity mapped under Xen */ return 0; align = getpagesize(); buf = slurp_file_len(kcore, KCORE_ELF_HEADERS_SIZE, &size); if (!buf) { fprintf(stderr, "Cannot read %s: %s\n", kcore, strerror(errno)); return -1; } /* Don't perform checks to make sure stated phdrs and shdrs are * actually present in the core file. It is not practical * to read the GB size file into a user space buffer, Given the * fact that we don't use any info from that. */ elf_flags |= ELF_SKIP_FILESZ_CHECK; result = build_elf_core_info(buf, size, &ehdr, elf_flags); if (result < 0) { /* Perhaps KCORE_ELF_HEADERS_SIZE is too small? */ fprintf(stderr, "ELF core (kcore) parse failed\n"); return -1; } end_phdr = &ehdr.e_phdr[ehdr.e_phnum]; /* Traverse through the Elf headers and find the region where * _stext symbol is located in. That's where kernel is mapped */ stext_sym = get_kernel_stext_sym(); for(phdr = ehdr.e_phdr; stext_sym && phdr != end_phdr; phdr++) { if (phdr->p_type == PT_LOAD) { unsigned long long saddr = phdr->p_vaddr; unsigned long long eaddr = phdr->p_vaddr + phdr->p_memsz; unsigned long long size; /* Look for kernel text mapping header. */ if (saddr < stext_sym && eaddr > stext_sym) { saddr = _ALIGN_DOWN(saddr, X86_64_KERN_VADDR_ALIGN); elf_info->kern_vaddr_start = saddr; size = eaddr - saddr; /* Align size to page size boundary. */ size = _ALIGN(size, align); elf_info->kern_size = size; dbgprintf("kernel vaddr = 0x%llx size = 0x%llx\n", saddr, size); return 0; } } } /* If failed to retrieve kernel text mapping through * /proc/kallsyms, Traverse through the Elf headers again and * find the region where kernel is mapped using hard-coded * kernel mapping boundries */ for(phdr = ehdr.e_phdr; phdr != end_phdr; phdr++) { if (phdr->p_type == PT_LOAD) { unsigned long long saddr = phdr->p_vaddr; unsigned long long eaddr = phdr->p_vaddr + phdr->p_memsz; unsigned long long size; /* Look for kernel text mapping header. */ if ((saddr >= X86_64__START_KERNEL_map) && (eaddr <= X86_64__START_KERNEL_map + X86_64_KERNEL_TEXT_SIZE)) { saddr = _ALIGN_DOWN(saddr, X86_64_KERN_VADDR_ALIGN); elf_info->kern_vaddr_start = saddr; size = eaddr - saddr; /* Align size to page size boundary. */ size = _ALIGN(size, align); elf_info->kern_size = size; dbgprintf("kernel vaddr = 0x%llx size = 0x%llx\n", saddr, size); return 0; } } } fprintf(stderr, "Can't find kernel text map area from kcore\n"); return -1; } /* Forward Declaration. */ static void segregate_lowmem_region(int *nr_ranges, unsigned long lowmem_limit); static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end); /* Stores a sorted list of RAM memory ranges for which to create elf headers. * A separate program header is created for backup region */ static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES]; /* Memory region reserved for storing panic kernel and other data. */ #define CRASH_RESERVED_MEM_NR 8 static struct memory_range crash_reserved_mem[CRASH_RESERVED_MEM_NR]; static int crash_reserved_mem_nr; /* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to * create Elf headers. Keeping it separate from get_memory_ranges() as * requirements are different in the case of normal kexec and crashdumps. * * Normal kexec needs to look at all of available physical memory irrespective * of the fact how much of it is being used by currently running kernel. * Crashdumps need to have access to memory regions actually being used by * running kernel. Expecting a different file/data structure than /proc/iomem * to look into down the line. May be something like /proc/kernelmem or may * be zone data structures exported from kernel. */ static int get_crash_memory_ranges(struct memory_range **range, int *ranges, int kexec_flags, unsigned long lowmem_limit) { const char *iomem = proc_iomem(); int memory_ranges = 0, gart = 0, i; char line[MAX_LINE]; FILE *fp; unsigned long long start, end; uint64_t gart_start = 0, gart_end = 0; 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) { char *str; int type, consumed, count; if (memory_ranges >= CRASH_MAX_MEMORY_RANGES) break; count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed); if (count != 2) continue; str = line + consumed; dbgprintf("%016Lx-%016Lx : %s", start, end, str); /* Only Dumping memory of type System RAM. */ if (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "ACPI Tables\n", 12) == 0) { /* * ACPI Tables area need to be passed to new * kernel with appropriate memmap= option. This * is needed so that x86_64 kernel creates linear * mapping for this region which is required for * initializing acpi tables in second kernel. */ type = RANGE_ACPI; } else if(memcmp(str,"ACPI Non-volatile Storage\n",26) == 0 ) { type = RANGE_ACPI_NVS; } else if(memcmp(str,"reserved\n",9) == 0 ) { type = RANGE_RESERVED; } else if (memcmp(str, "GART\n", 5) == 0) { gart_start = start; gart_end = end; gart = 1; continue; } else { continue; } crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; segregate_lowmem_region(&memory_ranges, lowmem_limit); memory_ranges++; } fclose(fp); if (kexec_flags & KEXEC_PRESERVE_CONTEXT) { for (i = 0; i < memory_ranges; i++) { if (crash_memory_range[i].end > 0x0009ffff) { crash_reserved_mem[0].start = \ crash_memory_range[i].start; break; } } if (crash_reserved_mem[0].start >= mem_max) { fprintf(stderr, "Too small mem_max: 0x%llx.\n", mem_max); return -1; } crash_reserved_mem[0].end = mem_max; crash_reserved_mem[0].type = RANGE_RAM; crash_reserved_mem_nr = 1; } for (i = 0; i < crash_reserved_mem_nr; i++) if (exclude_region(&memory_ranges, crash_reserved_mem[i].start, crash_reserved_mem[i].end) < 0) return -1; if (gart) { /* exclude GART region if the system has one */ if (exclude_region(&memory_ranges, gart_start, gart_end) < 0) return -1; } *range = crash_memory_range; *ranges = memory_ranges; return 0; } #ifdef HAVE_LIBXENCTRL static int get_crash_memory_ranges_xen(struct memory_range **range, int *ranges, unsigned long lowmem_limit) { int j, rc, ret = -1; struct e820entry e820entries[CRASH_MAX_MEMORY_RANGES]; unsigned int i; xc_interface *xc; xc = xc_interface_open(NULL, NULL, 0); if (!xc) { fprintf(stderr, "%s: Failed to open Xen control interface\n", __func__); return -1; } rc = xc_get_machine_memory_map(xc, e820entries, CRASH_MAX_MEMORY_RANGES); if (rc < 0) { fprintf(stderr, "%s: xc_get_machine_memory_map: %s\n", __func__, strerror(-rc)); goto err; } for (i = 0, j = 0; i < rc && j < CRASH_MAX_MEMORY_RANGES; ++i, ++j) { crash_memory_range[j].start = e820entries[i].addr; crash_memory_range[j].end = e820entries[i].addr + e820entries[i].size - 1; crash_memory_range[j].type = xen_e820_to_kexec_type(e820entries[i].type); segregate_lowmem_region(&j, lowmem_limit); } *range = crash_memory_range; *ranges = j; qsort(*range, *ranges, sizeof(struct memory_range), compare_ranges); for (i = 0; i < crash_reserved_mem_nr; i++) if (exclude_region(ranges, crash_reserved_mem[i].start, crash_reserved_mem[i].end) < 0) goto err; ret = 0; err: xc_interface_close(xc); return ret; } #else static int get_crash_memory_ranges_xen(struct memory_range **range, int *ranges, unsigned long lowmem_limit) { return 0; } #endif /* HAVE_LIBXENCTRL */ static void segregate_lowmem_region(int *nr_ranges, unsigned long lowmem_limit) { unsigned long long end, start; unsigned type; start = crash_memory_range[*nr_ranges].start; end = crash_memory_range[*nr_ranges].end; type = crash_memory_range[*nr_ranges].type; if (!(lowmem_limit && lowmem_limit > start && lowmem_limit < end)) return; crash_memory_range[*nr_ranges].end = lowmem_limit - 1; if (*nr_ranges >= CRASH_MAX_MEMORY_RANGES - 1) return; ++*nr_ranges; crash_memory_range[*nr_ranges].start = lowmem_limit; crash_memory_range[*nr_ranges].end = end; crash_memory_range[*nr_ranges].type = type; } /* Removes crash reserve region from list of memory chunks for whom elf program * headers have to be created. Assuming crash reserve region to be a single * continuous area fully contained inside one of the memory chunks */ static int exclude_region(int *nr_ranges, uint64_t start, uint64_t end) { int i, j, tidx = -1; struct memory_range temp_region = {0, 0, 0}; for (i = 0; i < (*nr_ranges); i++) { unsigned long long mstart, mend; mstart = crash_memory_range[i].start; mend = crash_memory_range[i].end; if (start < mend && end > mstart) { if (start != mstart && end != mend) { /* Split memory region */ crash_memory_range[i].end = start - 1; temp_region.start = end + 1; temp_region.end = mend; temp_region.type = RANGE_RAM; tidx = i+1; } else if (start != mstart) crash_memory_range[i].end = start - 1; else crash_memory_range[i].start = end + 1; } } /* Insert split memory region, if any. */ if (tidx >= 0) { if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) { /* No space to insert another element. */ fprintf(stderr, "Error: Number of crash memory ranges" " excedeed the max limit\n"); return -1; } for (j = (*nr_ranges - 1); j >= tidx; j--) crash_memory_range[j+1] = crash_memory_range[j]; crash_memory_range[tidx] = temp_region; (*nr_ranges)++; } return 0; } /* Adds a segment from list of memory regions which new kernel can use to * boot. Segment start and end should be aligned to 1K boundary. */ static int add_memmap(struct memory_range *memmap_p, int *nr_memmap, unsigned long long addr, size_t size, int type) { int i, j, nr_entries = 0, tidx = 0, align = 1024; unsigned long long mstart, mend; /* Do alignment check if it's RANGE_RAM */ if ((type == RANGE_RAM) && ((addr%align) || (size%align))) return -1; /* Make sure at least one entry in list is free. */ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { mstart = memmap_p[i].start; mend = memmap_p[i].end; if (!mstart && !mend) break; else nr_entries++; } if (nr_entries == CRASH_MAX_MEMMAP_NR) return -1; for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { mstart = memmap_p[i].start; mend = memmap_p[i].end; if (mstart == 0 && mend == 0) break; if (mstart <= (addr+size-1) && mend >=addr) /* Overlapping region. */ return -1; else if (addr > mend) tidx = i+1; } /* Insert the memory region. */ for (j = nr_entries-1; j >= tidx; j--) memmap_p[j+1] = memmap_p[j]; memmap_p[tidx].start = addr; memmap_p[tidx].end = addr + size - 1; memmap_p[tidx].type = type; *nr_memmap = nr_entries + 1; dbgprint_mem_range("Memmap after adding segment", memmap_p, *nr_memmap); return 0; } /* Removes a segment from list of memory regions which new kernel can use to * boot. Segment start and end should be aligned to 1K boundary. */ static int delete_memmap(struct memory_range *memmap_p, int *nr_memmap, unsigned long long addr, size_t size) { int i, j, nr_entries = 0, tidx = -1, operation = 0, align = 1024; unsigned long long mstart, mend; struct memory_range temp_region; /* Do alignment check. */ if ((addr%align) || (size%align)) return -1; /* Make sure at least one entry in list is free. */ for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { mstart = memmap_p[i].start; mend = memmap_p[i].end; if (!mstart && !mend) break; else nr_entries++; } if (nr_entries == CRASH_MAX_MEMMAP_NR) /* List if full */ return -1; for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { mstart = memmap_p[i].start; mend = memmap_p[i].end; if (mstart == 0 && mend == 0) /* Did not find the segment in the list. */ return -1; if (mstart <= addr && mend >= (addr + size - 1)) { if (mstart == addr && mend == (addr + size - 1)) { /* Exact match. Delete region */ operation = -1; tidx = i; break; } if (mstart != addr && mend != (addr + size - 1)) { /* Split in two */ memmap_p[i].end = addr - 1; temp_region.start = addr + size; temp_region.end = mend; temp_region.type = memmap_p[i].type; operation = 1; tidx = i; break; } /* No addition/deletion required. Adjust the existing.*/ if (mstart != addr) { memmap_p[i].end = addr - 1; break; } else { memmap_p[i].start = addr + size; break; } } } if ((operation == 1) && tidx >=0) { /* Insert the split memory region. */ for (j = nr_entries-1; j > tidx; j--) memmap_p[j+1] = memmap_p[j]; memmap_p[tidx+1] = temp_region; *nr_memmap = nr_entries + 1; } if ((operation == -1) && tidx >=0) { /* Delete the exact match memory region. */ for (j = i+1; j < CRASH_MAX_MEMMAP_NR; j++) memmap_p[j-1] = memmap_p[j]; memmap_p[j-1].start = memmap_p[j-1].end = 0; *nr_memmap = nr_entries - 1; } dbgprint_mem_range("Memmap after deleting segment", memmap_p, *nr_memmap); return 0; } /* Converts unsigned long to ascii string. */ static void ultoa(unsigned long i, char *str) { int j = 0, k; char tmp; do { str[j++] = i % 10 + '0'; } while ((i /=10) > 0); str[j] = '\0'; /* Reverse the string. */ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { tmp = str[k]; str[k] = str[j]; str[j] = tmp; } } static void cmdline_add_memmap_internal(char *cmdline, unsigned long startk, unsigned long endk, int type) { int cmdlen, len; char str_mmap[256], str_tmp[20]; strcpy (str_mmap, " memmap="); ultoa((endk-startk), str_tmp); strcat (str_mmap, str_tmp); if (type == RANGE_RAM) strcat (str_mmap, "K@"); else if (type == RANGE_RESERVED) strcat (str_mmap, "K$"); else if (type == RANGE_ACPI || type == RANGE_ACPI_NVS) strcat (str_mmap, "K#"); ultoa(startk, str_tmp); strcat (str_mmap, str_tmp); strcat (str_mmap, "K"); len = strlen(str_mmap); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str_mmap); } /* Adds the appropriate memmap= options to command line, indicating the * memory regions the new kernel can use to boot into. */ static int cmdline_add_memmap(char *cmdline, struct memory_range *memmap_p) { int i, cmdlen, len; unsigned long min_sizek = 100; char str_mmap[256]; /* Exact map */ strcpy(str_mmap, " memmap=exactmap"); len = strlen(str_mmap); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str_mmap); for (i = 0; i < CRASH_MAX_MEMMAP_NR; i++) { unsigned long startk, endk, type; startk = memmap_p[i].start/1024; endk = (memmap_p[i].end + 1)/1024; type = memmap_p[i].type; /* Only adding memory regions of RAM and ACPI */ if (type != RANGE_RAM && type != RANGE_ACPI && type != RANGE_ACPI_NVS) continue; if (type == RANGE_ACPI || type == RANGE_ACPI_NVS) endk = _ALIGN_UP(memmap_p[i].end + 1, 1024)/1024; if (!startk && !endk) /* All regions traversed. */ break; /* A RAM region is not worth adding if region size < 100K. * It eats up precious command line length. */ if (type == RANGE_RAM && (endk - startk) < min_sizek) continue; /* And do not add e820 reserved region either */ cmdline_add_memmap_internal(cmdline, startk, endk, type); } dbgprintf("Command line after adding memmap\n"); dbgprintf("%s\n", cmdline); return 0; } /* Adds the elfcorehdr= command line parameter to command line. */ static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr) { int cmdlen, len, align = 1024; char str[30], *ptr; /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline. * Ensure 1K alignment*/ if (addr%align) return -1; addr = addr/align; ptr = str; strcpy(str, " elfcorehdr="); ptr += strlen(str); ultoa(addr, ptr); strcat(str, "K"); len = strlen(str); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str); dbgprintf("Command line after adding elfcorehdr\n"); dbgprintf("%s\n", cmdline); return 0; } /* * This routine is specific to i386 architecture to maintain the * backward compatibility, other architectures can use the per * cpu version get_crash_notes_per_cpu() directly. */ static int get_crash_notes(int cpu, uint64_t *addr, uint64_t *len) { const char *crash_notes = "/sys/kernel/crash_notes"; char line[MAX_LINE]; FILE *fp; unsigned long vaddr; int count; fp = fopen(crash_notes, "r"); if (fp) { if (fgets(line, sizeof(line), fp) != 0) { count = sscanf(line, "%lx", &vaddr); if (count != 1) die("Cannot parse %s: %s\n", crash_notes, strerror(errno)); } *addr = x86__pa(vaddr + (cpu * MAX_NOTE_BYTES)); *len = MAX_NOTE_BYTES; dbgprintf("crash_notes addr = %Lx\n", (unsigned long long)*addr); fclose(fp); return 0; } else return get_crash_notes_per_cpu(cpu, addr, len); } static enum coretype get_core_type(struct crash_elf_info *elf_info, struct memory_range *range, int ranges) { if ((elf_info->machine) == EM_X86_64) return CORE_TYPE_ELF64; else { /* fall back to default */ if (ranges == 0) return CORE_TYPE_ELF64; if (range[ranges - 1].end > 0xFFFFFFFFUL) return CORE_TYPE_ELF64; else return CORE_TYPE_ELF32; } } static int sysfs_efi_runtime_map_exist(void) { DIR *dir; dir = opendir("/sys/firmware/efi/runtime-map"); if (!dir) return 0; closedir(dir); return 1; } /* Appends 'acpi_rsdp=' commandline for efi boot crash dump */ static void cmdline_add_efi(char *cmdline) { FILE *fp; int cmdlen, len; char line[MAX_LINE], *s; const char *acpis = " acpi_rsdp="; fp = fopen("/sys/firmware/efi/systab", "r"); if (!fp) return; while(fgets(line, sizeof(line), fp) != 0) { /* ACPI20= always goes before ACPI= */ if ((strstr(line, "ACPI20=")) || (strstr(line, "ACPI="))) { line[strlen(line) - 1] = '\0'; s = strchr(line, '='); s += 1; len = strlen(s) + strlen(acpis); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, acpis); strcat(cmdline, s); dbgprintf("Command line after adding efi\n"); dbgprintf("%s\n", cmdline); break; } } fclose(fp); } static void get_backup_area(struct kexec_info *info, struct memory_range *range, int ranges) { int i; /* Look for first 640 KiB RAM region. */ for (i = 0; i < ranges; ++i) { if (range[i].type != RANGE_RAM || range[i].end > 0xa0000) continue; info->backup_src_start = range[i].start; info->backup_src_size = range[i].end - range[i].start + 1; dbgprintf("%s: %016llx-%016llx : System RAM\n", __func__, range[i].start, range[i].end); return; } /* First 640 KiB RAM region not found. Assume defaults. */ info->backup_src_start = BACKUP_SRC_START; info->backup_src_size = BACKUP_SRC_END - BACKUP_SRC_START + 1; } /* Loads additional segments in case of a panic kernel is being loaded. * One segment for backup region, another segment for storing elf headers * for crash memory image. */ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, unsigned long max_addr, unsigned long min_base) { void *tmp; unsigned long sz, bufsz, memsz, elfcorehdr; int nr_ranges = 0, nr_memmap = 0, align = 1024, i; struct memory_range *mem_range, *memmap_p; struct crash_elf_info elf_info; unsigned kexec_arch; memset(&elf_info, 0x0, sizeof(elf_info)); /* Constant parts of the elf_info */ memset(&elf_info, 0, sizeof(elf_info)); elf_info.data = ELFDATA2LSB; /* Get the architecture of the running kernel */ kexec_arch = info->kexec_flags & KEXEC_ARCH_MASK; if (kexec_arch == KEXEC_ARCH_DEFAULT) kexec_arch = KEXEC_ARCH_NATIVE; /* Get the elf architecture of the running kernel */ switch(kexec_arch) { case KEXEC_ARCH_X86_64: elf_info.machine = EM_X86_64; break; case KEXEC_ARCH_386: elf_info.machine = EM_386; elf_info.lowmem_limit = X86_MAXMEM; elf_info.get_note_info = get_crash_notes; break; default: fprintf(stderr, "unsupported crashdump architecture: %04x\n", kexec_arch); return -1; } if (xen_present()) { if (get_crash_memory_ranges_xen(&mem_range, &nr_ranges, elf_info.lowmem_limit) < 0) return -1; } else if (get_crash_memory_ranges(&mem_range, &nr_ranges, info->kexec_flags, elf_info.lowmem_limit) < 0) return -1; get_backup_area(info, mem_range, nr_ranges); dbgprint_mem_range("CRASH MEMORY RANGES", mem_range, nr_ranges); /* * if the core type has not been set on command line, set it here * automatically */ if (arch_options.core_header_type == CORE_TYPE_UNDEF) { arch_options.core_header_type = get_core_type(&elf_info, mem_range, nr_ranges); } /* Get the elf class... */ elf_info.class = ELFCLASS32; if (arch_options.core_header_type == CORE_TYPE_ELF64) { elf_info.class = ELFCLASS64; } if (get_kernel_page_offset(info, &elf_info)) return -1; if (get_kernel_paddr(info, &elf_info)) return -1; if (get_kernel_vaddr_and_size(info, &elf_info)) return -1; /* Memory regions which panic kernel can safely use to boot into */ sz = (sizeof(struct memory_range) * CRASH_MAX_MEMMAP_NR); memmap_p = xmalloc(sz); memset(memmap_p, 0, sz); add_memmap(memmap_p, &nr_memmap, info->backup_src_start, info->backup_src_size, RANGE_RAM); for (i = 0; i < crash_reserved_mem_nr; i++) { sz = crash_reserved_mem[i].end - crash_reserved_mem[i].start +1; if (add_memmap(memmap_p, &nr_memmap, crash_reserved_mem[i].start, sz, RANGE_RAM) < 0) return ENOCRASHKERNEL; } /* Create a backup region segment to store backup data*/ if (!(info->kexec_flags & KEXEC_PRESERVE_CONTEXT)) { sz = _ALIGN(info->backup_src_size, align); tmp = xmalloc(sz); memset(tmp, 0, sz); info->backup_start = add_buffer(info, tmp, sz, sz, align, 0, max_addr, -1); dbgprintf("Created backup segment at 0x%lx\n", info->backup_start); if (delete_memmap(memmap_p, &nr_memmap, info->backup_start, sz) < 0) return EFAILED; } /* Create elf header segment and store crash image data. */ if (arch_options.core_header_type == CORE_TYPE_ELF64) { if (crash_create_elf64_headers(info, &elf_info, mem_range, nr_ranges, &tmp, &bufsz, ELF_CORE_HEADER_ALIGN) < 0) return EFAILED; } else { if (crash_create_elf32_headers(info, &elf_info, mem_range, nr_ranges, &tmp, &bufsz, ELF_CORE_HEADER_ALIGN) < 0) return EFAILED; } /* the size of the elf headers allocated is returned in 'bufsz' */ /* Hack: With some ld versions (GNU ld version 2.14.90.0.4 20030523), * vmlinux program headers show a gap of two pages between bss segment * and data segment but effectively kernel considers it as bss segment * and overwrites the any data placed there. Hence bloat the memsz of * elf core header segment to 16K to avoid being placed in such gaps. * This is a makeshift solution until it is fixed in kernel. */ if (bufsz < (16*1024)) { /* bufsize is big enough for all the PT_NOTE's and PT_LOAD's */ memsz = 16*1024; /* memsz will be the size of the memory hole we look for */ } else { memsz = bufsz; } elfcorehdr = add_buffer(info, tmp, bufsz, memsz, align, min_base, max_addr, -1); dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr); if (delete_memmap(memmap_p, &nr_memmap, elfcorehdr, memsz) < 0) return -1; if (!bzImage_support_efi_boot || arch_options.noefi || !sysfs_efi_runtime_map_exist()) cmdline_add_efi(mod_cmdline); cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr); /* Inform second kernel about the presence of ACPI tables. */ for (i = 0; i < CRASH_MAX_MEMORY_RANGES; i++) { unsigned long start, end, size, type; if ( !( mem_range[i].type == RANGE_ACPI || mem_range[i].type == RANGE_ACPI_NVS || mem_range[i].type == RANGE_RESERVED)) continue; start = mem_range[i].start; end = mem_range[i].end; type = mem_range[i].type; size = end - start + 1; add_memmap(memmap_p, &nr_memmap, start, size, type); } if (arch_options.pass_memmap_cmdline) cmdline_add_memmap(mod_cmdline, memmap_p); /* Store 2nd kernel boot memory ranges for later reference in * x86-setup-linux.c: setup_linux_system_parameters() */ info->crash_range = memmap_p; info->nr_crash_ranges = nr_memmap; return 0; } int get_max_crash_kernel_limit(uint64_t *start, uint64_t *end) { int i, idx = -1; unsigned long sz_max = 0, sz; if (!crash_reserved_mem_nr) return -1; for (i = crash_reserved_mem_nr - 1; i >= 0; i--) { sz = crash_reserved_mem[i].end - crash_reserved_mem[i].start +1; if (sz <= sz_max) continue; sz_max = sz; idx = i; } *start = crash_reserved_mem[idx].start; *end = crash_reserved_mem[idx].end; return 0; } static int crashkernel_mem_callback(void *UNUSED(data), int nr, char *UNUSED(str), unsigned long long base, unsigned long long length) { if (nr >= CRASH_RESERVED_MEM_NR) return 1; crash_reserved_mem[nr].start = base; crash_reserved_mem[nr].end = base + length - 1; crash_reserved_mem[nr].type = RANGE_RAM; return 0; } int is_crashkernel_mem_reserved(void) { int ret; if (xen_present()) { uint64_t start, end; ret = xen_get_crashkernel_region(&start, &end); if (ret < 0) return 0; crash_reserved_mem[0].start = start; crash_reserved_mem[0].end = end; crash_reserved_mem[0].type = RANGE_RAM; crash_reserved_mem_nr = 1; } else { ret = kexec_iomem_for_each_line("Crash kernel\n", crashkernel_mem_callback, NULL); crash_reserved_mem_nr = ret; } return !!crash_reserved_mem_nr; } kexec-tools-2.0.10/kexec/arch/i386/kexec-x86.h0000644001567400156740000000376412417126536017536 0ustar hormshorms#ifndef KEXEC_X86_H #define KEXEC_X86_H #define MAX_MEMORY_RANGES 1024 enum coretype { CORE_TYPE_UNDEF = 0, CORE_TYPE_ELF32 = 1, CORE_TYPE_ELF64 = 2 }; 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; }; struct arch_options_t { uint8_t reset_vga; uint16_t serial_base; uint32_t serial_baud; uint8_t console_vga; uint8_t console_serial; enum coretype core_header_type; uint8_t pass_memmap_cmdline; uint8_t noefi; }; 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 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); extern unsigned xen_e820_to_kexec_type(uint32_t type); #endif /* KEXEC_X86_H */ kexec-tools-2.0.10/kexec/arch/i386/crashdump-x86.h0000644001567400156740000000175312417126536020421 0ustar hormshorms#ifndef CRASHDUMP_X86_H #define CRASHDUMP_X86_H struct kexec_info; int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline, unsigned long max_addr, unsigned long min_base); #define X86_PAGE_OFFSET 0xc0000000 #define x86__pa(x) ((unsigned long)(x)-X86_PAGE_OFFSET) #define X86__VMALLOC_RESERVE (128 << 20) #define X86_MAXMEM (-X86_PAGE_OFFSET-X86__VMALLOC_RESERVE) #define X86_64__START_KERNEL_map 0xffffffff80000000ULL #define X86_64_PAGE_OFFSET_PRE_2_6_27 0xffff810000000000ULL #define X86_64_PAGE_OFFSET 0xffff880000000000ULL #define X86_64_MAXMEM 0x3fffffffffffUL /* Kernel text size */ #define X86_64_KERNEL_TEXT_SIZE (512UL*1024*1024) #define CRASH_MAX_MEMMAP_NR 1024 #define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2) /* Backup Region, First 640K of System RAM. */ #define BACKUP_SRC_START 0x00000000 #define BACKUP_SRC_END 0x0009ffff #define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1) #endif /* CRASHDUMP_X86_H */ kexec-tools-2.0.10/kexec/arch/i386/x86-linux-setup.h0000644001567400156740000000236612417126536020731 0ustar hormshorms#ifndef X86_LINUX_SETUP_H #define X86_LINUX_SETUP_H #include void init_linux_parameters(struct x86_linux_param_header *real_mode); void setup_linux_bootloader_parameters_high( 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 char *initrd_buf, off_t initrd_size, int initrd_high); static inline 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 char *initrd_buf, off_t initrd_size) { setup_linux_bootloader_parameters_high(info, real_mode, real_mode_base, cmdline_offset, cmdline, cmdline_len, initrd_buf, initrd_size, 0); } void setup_linux_system_parameters(struct kexec_info *info, struct x86_linux_param_header *real_mode); #define SETUP_BASE 0x90000 #define KERN32_BASE 0x100000 /* 1MB */ #define INITRD_BASE 0x1000000 /* 16MB */ /* command line parameter may be appended by purgatory */ #define PURGATORY_CMDLINE_SIZE 64 extern int bzImage_support_efi_boot; extern struct arch_options_t arch_options; #endif /* X86_LINUX_SETUP_H */ kexec-tools-2.0.10/kexec/arch/i386/include/arch/options.h0000644001567400156740000000621712417126536022043 0ustar hormshorms#ifndef KEXEC_ARCH_I386_OPTIONS_H #define KEXEC_ARCH_I386_OPTIONS_H /* ************************************************************************* * NOTE NOTE NOTE * This file is included for i386 builds *and* x86_64 builds (which build * both x86_64 and i386 loaders). * It contains the combined set of options used by i386 and x86_64. ************************************************************************* */ #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_ELF32_CORE (OPT_MAX+5) #define OPT_ELF64_CORE (OPT_MAX+6) #define OPT_ARCH_MAX (OPT_MAX+7) #define OPT_APPEND (OPT_ARCH_MAX+0) #define OPT_REUSE_CMDLINE (OPT_ARCH_MAX+1) #define OPT_RAMDISK (OPT_ARCH_MAX+2) #define OPT_ARGS_ELF (OPT_ARCH_MAX+3) #define OPT_ARGS_LINUX (OPT_ARCH_MAX+4) #define OPT_ARGS_NONE (OPT_ARCH_MAX+5) #define OPT_CL (OPT_ARCH_MAX+6) #define OPT_MOD (OPT_ARCH_MAX+7) #define OPT_VGA (OPT_ARCH_MAX+8) #define OPT_REAL_MODE (OPT_ARCH_MAX+9) #define OPT_ENTRY_32BIT (OPT_ARCH_MAX+10) #define OPT_PASS_MEMMAP_CMDLINE (OPT_ARCH_MAX+11) #define OPT_NOEFI (OPT_ARCH_MAX+12) /* Options relevant to the architecture (excluding loader-specific ones): */ #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 }, \ { "elf32-core-headers", 0, 0, OPT_ELF32_CORE }, \ { "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \ { "pass-memmap-cmdline", 0, 0, OPT_PASS_MEMMAP_CMDLINE }, \ { "noefi", 0, 0, OPT_NOEFI}, \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ { "command-line", 1, NULL, OPT_APPEND }, \ { "append", 1, NULL, OPT_APPEND }, \ { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ { "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 }, \ { "module", 1, 0, OPT_MOD }, \ { "real-mode", 0, NULL, OPT_REAL_MODE }, \ { "entry-32bit", 0, NULL, OPT_ENTRY_32BIT }, #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR #endif /* KEXEC_ARCH_I386_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/ia64/Makefile0000644001567400156740000000073711424244110017334 0ustar hormshorms# # kexec ia64 (linux booting linux) # ia64_KEXEC_SRCS = kexec/arch/ia64/kexec-iomem.c ia64_KEXEC_SRCS += kexec/arch/ia64/kexec-ia64.c ia64_KEXEC_SRCS += kexec/arch/ia64/kexec-elf-ia64.c ia64_KEXEC_SRCS += kexec/arch/ia64/kexec-elf-rel-ia64.c ia64_KEXEC_SRCS += kexec/arch/ia64/crashdump-ia64.c ia64_PROC_IOMEM = dist += kexec/arch/ia64/Makefile $(ia64_KEXEC_SRCS) \ kexec/arch/ia64/kexec-ia64.h kexec/arch/ia64/crashdump-ia64.h \ kexec/arch/ia64/include/arch/options.h kexec-tools-2.0.10/kexec/arch/ia64/kexec-iomem.c0000644001567400156740000000140011424244110020227 0ustar hormshorms#include #include #include "../../kexec.h" #include "../../crashdump.h" static const char proc_iomem_str[]= "/proc/iomem"; static const char proc_iomem_machine_str[]= "/proc/iomem_machine"; /* * On IA64 XEN the EFI tables are virtualised. * For this reason on such systems /proc/iomem_machine is provided, * which is based on the hypervisor's (machine's) EFI tables. * If Xen is in use, then /proc/iomem is used for memory regions relating * to the currently running dom0 kernel, and /proc/iomem_machine is used * for regions relating to the machine itself or the hypervisor. * If Xen is not in used, then /proc/iomem used. */ const char *proc_iomem(void) { if (xen_present()) return proc_iomem_machine_str; return proc_iomem_str; } kexec-tools-2.0.10/kexec/arch/ia64/kexec-ia64.c0000644001567400156740000001450712242534555017716 0ustar hormshorms/* * 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 * * 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 #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "elf.h" #include "kexec-ia64.h" #include /* The number of entries in memory_range array is always smaller than * the number of entries in the file returned by proc_iomem(), * stored in max_memory_ranges. */ static struct memory_range *memory_range; int max_memory_ranges; static int memory_ranges; unsigned long saved_efi_memmap_size; /* Reserve range for EFI memmap and Boot parameter */ static int split_range(int range, unsigned long start, unsigned long end) { unsigned long ram_end = memory_range[range - 1].end; unsigned int type = memory_range[range - 1].type; int i; //align end and start to page size of EFI start = _ALIGN_DOWN(start, 1UL<<12); end = _ALIGN(end, 1UL<<12); for (i = 0; i < range; i++) if(memory_range[i].start <= start && memory_range[i].end >=end) break; if (i >= range) return range; range = i; if (memory_range[range].start < start) { memory_range[range].end = start; range++; } memory_range[range].start = start; memory_range[range].end = end; memory_range[range].type = RANGE_RESERVED; range++; if (end < ram_end) { memory_range[range].start = end; memory_range[range].end = ram_end; memory_range[range].type = type; range++; } return range; } /* Return a sorted list of available memory ranges. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { const char *iomem = proc_iomem(); char line[MAX_LINE]; FILE *fp; fp = fopen(iomem, "r"); if (!fp) { fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); return -1; } /* allocate memory_range dynamically */ max_memory_ranges = 0; while(fgets(line, sizeof(line), fp) != 0) { max_memory_ranges++; } memory_range = xmalloc(sizeof(struct memory_range) * max_memory_ranges); rewind(fp); while(fgets(line, sizeof(line), fp) != 0) { unsigned long start, end; char *str; unsigned 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 (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, "Crash kernel\n", 13) == 0) { /* Redefine the memory region boundaries if kernel * exports the limits and if it is panic kernel. * Override user values only if kernel exported * values are subset of user defined values. */ if (kexec_flags & KEXEC_ON_CRASH) { if (start > mem_min) mem_min = start; if (end < mem_max) mem_max = end; } continue; } else if (memcmp(str, "Boot parameter\n", 14) == 0) { memory_ranges = split_range(memory_ranges, start, end); continue; } else if (memcmp(str, "EFI Memory Map\n", 14) == 0) { memory_ranges = split_range(memory_ranges, start, end); saved_efi_memmap_size = end - start; continue; } else if (memcmp(str, "Uncached RAM\n", 13) == 0) { type = RANGE_UNCACHED; } else { continue; } /* * Check if this memory range can be coalesced with * the previous range */ if ((memory_ranges > 0) && (start == memory_range[memory_ranges-1].end) && (type == memory_range[memory_ranges-1].type)) { memory_range[memory_ranges-1].end = end; } else { memory_range[memory_ranges].start = start; memory_range[memory_ranges].end = end; memory_range[memory_ranges].type = type; memory_ranges++; } } fclose(fp); *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) { } int arch_process_options(int argc, char **argv) { /* This doesn't belong here! Some sort of arch_init() ? */ /* execute from monarch processor */ cpu_set_t affinity; CPU_ZERO(&affinity); CPU_SET(0, &affinity); sched_setaffinity(0, sizeof(affinity), &affinity); return 0; } const struct arch_map_entry arches[] = { { "ia64", KEXEC_ARCH_IA_64 }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } int update_loaded_segments(struct mem_ehdr *ehdr) { int i; unsigned u; struct mem_phdr *phdr; unsigned long start_addr = ULONG_MAX, end_addr = 0; unsigned long align = 1UL<<26; /* 64M */ unsigned long start, end; for (u = 0; u < ehdr->e_phnum; u++) { phdr = &ehdr->e_phdr[u]; if (phdr->p_type != PT_LOAD) continue; if (phdr->p_paddr < start_addr) start_addr = phdr->p_paddr; if ((phdr->p_paddr + phdr->p_memsz) > end_addr) end_addr = phdr->p_paddr + phdr->p_memsz; } for (i = 0; i < memory_ranges && memory_range[i].start <= start_addr; i++) { if (memory_range[i].type == RANGE_RAM && memory_range[i].end > end_addr) return 0; } for (i = 0; i < memory_ranges; i++) { if (memory_range[i].type != RANGE_RAM) continue; start = _ALIGN(memory_range[i].start, align); end = memory_range[i].end; if (end > start && (end - start) > (end_addr - start_addr)) { move_loaded_segments(ehdr, start); return 0; } } return -1; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } kexec-tools-2.0.10/kexec/arch/ia64/kexec-elf-ia64.c0000644001567400156740000002044312417126536020456 0ustar hormshorms/* * 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 * Copyright (C) 2004 Khalid Aziz Hewlett Packard Co * Copyright (C) 2005 Zou Nan hai Intel 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../kexec-elf.h" #include "kexec-ia64.h" #include "crashdump-ia64.h" #include static const int probe_debug = 0; extern unsigned long saved_efi_memmap_size; /* * 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, 0); 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" " --initrd=FILE Use FILE as the kernel's initial " "ramdisk.\n" " --noio Disable I/O in purgatory code.\n" " --vmm=FILE Use FILE as the kernel image for a\n" " virtual machine monitor " "(aka hypervisor)\n"); } /* Move the crash kerenl physical offset to reserved region */ void move_loaded_segments(struct mem_ehdr *ehdr, unsigned long addr) { unsigned i; long offset = 0; int found = 0; struct mem_phdr *phdr; for(i = 0; i < ehdr->e_phnum; i++) { phdr = &ehdr->e_phdr[i]; if (phdr->p_type == PT_LOAD) { offset = addr - phdr->p_paddr; found++; break; } } if (!found) die("move_loaded_segments: no PT_LOAD region 0x%016x\n", addr); ehdr->e_entry += offset; for(i = 0; i < ehdr->e_phnum; i++) { phdr = &ehdr->e_phdr[i]; if (phdr->p_type == PT_LOAD) phdr->p_paddr += offset; } } 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, *ramdisk=0, *vmm=0, *kernel_buf; char *ramdisk_buf = NULL; off_t ramdisk_size = 0, kernel_size; unsigned long command_line_len; unsigned long entry, max_addr, gp_value; unsigned long command_line_base, ramdisk_base, image_base; unsigned long efi_memmap_base, efi_memmap_size; unsigned long boot_param_base; unsigned long noio=0; int result; int opt; char *efi_memmap_buf, *boot_param; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS {"command-line", 1, 0, OPT_APPEND}, {"append", 1, 0, OPT_APPEND}, {"initrd", 1, 0, OPT_RAMDISK}, {"noio", 0, 0, OPT_NOIO}, {"vmm", 1, 0, OPT_VMM}, {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 OPT_APPEND: command_line = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_NOIO: /* disable PIO and MMIO in purgatory code*/ noio = 1; break; case OPT_VMM: vmm = optarg; break; } } command_line_len = 0; if (command_line) { command_line_len = strlen(command_line) + 16; } if (vmm) kernel_buf = slurp_decompress_file(vmm, &kernel_size); else { kernel_buf = buf; kernel_size = len; } /* Parse the Elf file */ result = build_elf_exec_info(kernel_buf, kernel_size, &ehdr, 0); if (result < 0) { fprintf(stderr, "ELF parse failed\n"); free_elf_info(&ehdr); return result; } if (info->kexec_flags & KEXEC_ON_CRASH ) { if ((mem_min == 0x00) && (mem_max == ULONG_MAX)) { fprintf(stderr, "Failed to find crash kernel region " "in %s\n", proc_iomem()); free_elf_info(&ehdr); return -1; } move_loaded_segments(&ehdr, mem_min); } else if (update_loaded_segments(&ehdr) < 0) { fprintf(stderr, "Failed to place kernel\n"); return -1; } entry = ehdr.e_entry; max_addr = elf_max_addr(&ehdr); /* Load the Elf data */ result = elf_exec_load(&ehdr, info); if (result < 0) { fprintf(stderr, "ELF load failed\n"); free_elf_info(&ehdr); return result; } /* Load the setup code */ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0x0, ULONG_MAX, -1, 0); if (load_crashdump_segments(info, &ehdr, max_addr, 0, &command_line) < 0) return -1; // reverve 4k for ia64_boot_param boot_param = xmalloc(4096); boot_param_base = add_buffer(info, boot_param, 4096, 4096, 4096, 0, max_addr, -1); elf_rel_set_symbol(&info->rhdr, "__noio", &noio, sizeof(long)); elf_rel_set_symbol(&info->rhdr, "__boot_param_base", &boot_param_base, sizeof(long)); // reserve efi_memmap of actual size allocated in production kernel efi_memmap_size = saved_efi_memmap_size; efi_memmap_buf = xmalloc(efi_memmap_size); efi_memmap_base = add_buffer(info, efi_memmap_buf, efi_memmap_size, efi_memmap_size, 4096, 0, max_addr, -1); elf_rel_set_symbol(&info->rhdr, "__efi_memmap_base", &efi_memmap_base, sizeof(long)); elf_rel_set_symbol(&info->rhdr, "__efi_memmap_size", &efi_memmap_size, sizeof(long)); if (command_line) { command_line_len = strlen(command_line) + 1; } if (command_line_len || (info->kexec_flags & KEXEC_ON_CRASH )) { char *cmdline = xmalloc(command_line_len); strcpy(cmdline, command_line); if (info->kexec_flags & KEXEC_ON_CRASH) { char buf[128]; sprintf(buf," max_addr=%lluM min_addr=%lluM", mem_max>>20, mem_min>>20); command_line_len = strlen(cmdline) + strlen(buf) + 1; cmdline = xrealloc(cmdline, command_line_len); strcat(cmdline, buf); } command_line_len = _ALIGN(command_line_len, 16); command_line_base = add_buffer(info, cmdline, command_line_len, command_line_len, getpagesize(), 0UL, max_addr, -1); elf_rel_set_symbol(&info->rhdr, "__command_line_len", &command_line_len, sizeof(long)); elf_rel_set_symbol(&info->rhdr, "__command_line", &command_line_base, sizeof(long)); } if (ramdisk) { ramdisk_buf = slurp_file(ramdisk, &ramdisk_size); ramdisk_base = add_buffer(info, ramdisk_buf, ramdisk_size, ramdisk_size, getpagesize(), 0, max_addr, -1); elf_rel_set_symbol(&info->rhdr, "__ramdisk_base", &ramdisk_base, sizeof(long)); elf_rel_set_symbol(&info->rhdr, "__ramdisk_size", &ramdisk_size, sizeof(long)); } if (vmm) { image_base = add_buffer(info, buf, len, len, getpagesize(), 0, max_addr, -1); elf_rel_set_symbol(&info->rhdr, "__vmcode_base", &image_base, sizeof(long)); elf_rel_set_symbol(&info->rhdr, "__vmcode_size", &len, sizeof(long)); } gp_value = info->rhdr.rel_addr + 0x200000; elf_rel_set_symbol(&info->rhdr, "__gp_value", &gp_value, sizeof(gp_value)); elf_rel_set_symbol(&info->rhdr, "__kernel_entry", &entry, sizeof(entry)); free_elf_info(&ehdr); return 0; } kexec-tools-2.0.10/kexec/arch/ia64/kexec-elf-rel-ia64.c0000644001567400156740000001126511424244110021222 0ustar hormshorms/* * Copyright (C) 2005-2006 Zou Nan hai (nanhai.zou@intel.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. */ /* pugatory relocation code * Most of the code in this file is * based on arch/ia64/kernel/module.c in Linux kernel */ /* Most of the code in this file is * based on arch/ia64/kernel/module.c in Linux kernel */ #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #define MAX_LTOFF ((uint64_t) (1 << 22)) 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; } static void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val) { uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16); # define insn_mask ((1UL << 41) - 1) unsigned long shift; b0 = b[0]; b1 = b[1]; shift = 5 + 41 * (insn_addr % 16); /* 5 bits of template, then 3 x 41-bit instructions */ if (shift >= 64) { m1 = mask << (shift - 64); v1 = val << (shift - 64); } else { m0 = mask << shift; m1 = mask >> (64 - shift); v0 = val << shift; v1 = val >> (64 - shift); b[0] = (b0 & ~m0) | (v0 & m0); } b[1] = (b1 & ~m1) | (v1 & m1); } static inline uint64_t bundle (const uint64_t insn) { return insn & ~0xfUL; } void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, void *location, unsigned long address, unsigned long value) { uint64_t gp_value = ehdr->rel_addr + 0x200000; switch(r_type) { case R_IA64_NONE: break; case R_IA64_SEGREL64LSB: 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_IMM64: ia64_patch((uint64_t)location, 0x01fffefe000UL, /* bit 63 -> 36 */ (((value & 0x8000000000000000UL) >> 27) /* bit 21 -> 21 */ | ((value & 0x0000000000200000UL) << 0) /* bit 16 -> 22 */ | ((value & 0x00000000001f0000UL) << 6) /* bit 7 -> 27 */ | ((value & 0x000000000000ff80UL) << 20) /* bit 0 -> 13 */ | ((value & 0x000000000000007fUL) << 13))); ia64_patch((uint64_t)location - 1, 0x1ffffffffffUL, value>>22); break; case R_IA64_IMM22: if (value + (1 << 21) >= (1 << 22)) die("value out of IMM22 range\n"); ia64_patch((uint64_t)location, 0x01fffcfe000UL, /* bit 21 -> 36 */ (((value & 0x200000UL) << 15) /* bit 16 -> 22 */ | ((value & 0x1f0000UL) << 6) /* bit 7 -> 27 */ | ((value & 0x00ff80UL) << 20) /* bit 0 -> 13 */ | ((value & 0x00007fUL) << 13) )); break; case R_IA64_PCREL21B: { uint64_t delta = ((int64_t)value - (int64_t)address)/16; if (delta + (1 << 20) >= (1 << 21)) die("value out of IMM21B range\n"); value = ((int64_t)(value - bundle(address)))/16; ia64_patch((uint64_t)location, 0x11ffffe000UL, (((value & 0x100000UL) << 16) /* bit 20 -> 36 */ | ((value & 0x0fffffUL) << 13) /* bit 0 -> 13 */)); } break; case R_IA64_PCREL64LSB: { value = value - address; put_unaligned(value, (uint64_t *)location); } break; case R_IA64_GPREL22: case R_IA64_LTOFF22X: if (value - gp_value + MAX_LTOFF/2 >= MAX_LTOFF) die("value out of gp relative range"); value -= gp_value; ia64_patch((uint64_t)location, 0x01fffcfe000UL, (((value & 0x200000UL) << 15) /* bit 21 -> 36 */ |((value & 0x1f0000UL) << 6) /* bit 16 -> 22 */ |((value & 0x00ff80UL) << 20) /* bit 7 -> 27 */ |((value & 0x00007fUL) << 13) /* bit 0 -> 13 */)); break; case R_IA64_LDXMOV: if (value - gp_value + MAX_LTOFF/2 >= MAX_LTOFF) die("value out of gp relative range"); ia64_patch((uint64_t)location, 0x1fff80fe000UL, 0x10000000000UL); break; case R_IA64_LTOFF22: default: die("Unknown rela relocation: 0x%lx 0x%lx\n", r_type, address); break; } return; overflow: die("overflow in relocation type %lu val %Lx\n", r_type, value); } kexec-tools-2.0.10/kexec/arch/ia64/crashdump-ia64.c0000644001567400156740000002130612242534555020600 0ustar hormshorms/* * kexec: crashdump support * Copyright (C) 2005-2006 Zou Nan hai Intel 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. */ #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "kexec-ia64.h" #include "crashdump-ia64.h" #include "../kexec/crashdump.h" int memory_ranges = 0; #define LOAD_OFFSET (0xa000000000000000UL + 0x100000000UL - \ kernel_code_start) static struct crash_elf_info elf_info = { class: ELFCLASS64, data: ELFDATA2LSB, machine: EM_IA_64, page_offset: PAGE_OFFSET, }; /* Stores a sorted list of RAM memory ranges for which to create elf headers. * A separate program header is created for backup region. * The number of entries in memory_range array is always smaller than * the number of entries in the file returned by proc_iomem(), * stored in max_memory_ranges. */ static struct memory_range *crash_memory_range; /* Memory region reserved for storing panic kernel and other data. */ static struct memory_range crash_reserved_mem; unsigned long elfcorehdr; static unsigned long kernel_code_start; static unsigned long kernel_code_end; struct loaded_segment { unsigned long start; unsigned long end; }; #define MAX_LOAD_SEGMENTS 128 struct loaded_segment loaded_segments[MAX_LOAD_SEGMENTS]; unsigned long loaded_segments_num, loaded_segments_base; static int seg_comp(const void *a, const void *b) { const struct loaded_segment *x = a, *y = b; /* avoid overflow */ if (x->start > y->start) return 1; if (x->start < y->start) return -1; return 0; } /* purgatory code need this info to patch the EFI memmap */ static void add_loaded_segments_info(struct mem_ehdr *ehdr) { unsigned i = 0; while(i < ehdr->e_phnum) { struct mem_phdr *phdr; phdr = &ehdr->e_phdr[i]; if (phdr->p_type != PT_LOAD) { i++; continue; } loaded_segments[loaded_segments_num].start = _ALIGN_DOWN(phdr->p_paddr, ELF_PAGE_SIZE); loaded_segments[loaded_segments_num].end = loaded_segments[loaded_segments_num].start; /* Consolidate consecutive PL_LOAD segments into one. * The end addr of the last PL_LOAD segment, calculated by * adding p_memsz to p_paddr & rounded up to ELF_PAGE_SIZE, * will be the end address of this loaded_segments entry. */ while (i < ehdr->e_phnum) { phdr = &ehdr->e_phdr[i]; if (phdr->p_type != PT_LOAD) break; loaded_segments[loaded_segments_num].end = _ALIGN(phdr->p_paddr + phdr->p_memsz, ELF_PAGE_SIZE); i++; } loaded_segments_num++; } } /* Removes crash reserve region from list of memory chunks for whom elf program * headers have to be created. Assuming crash reserve region to be a single * continuous area fully contained inside one of the memory chunks */ static int exclude_crash_reserve_region(int *nr_ranges) { int i, j, tidx = -1; unsigned long cstart, cend; struct memory_range temp_region; /* Crash reserved region. */ cstart = crash_reserved_mem.start; cend = crash_reserved_mem.end; for (i = 0; i < (*nr_ranges); i++) { unsigned long mstart, mend; mstart = crash_memory_range[i].start; mend = crash_memory_range[i].end; if (cstart < mend && cend > mstart) { if (cstart != mstart && cend != mend) { /* Split memory region */ crash_memory_range[i].end = cstart - 1; temp_region.start = cend + 1; temp_region.end = mend; temp_region.type = RANGE_RAM; tidx = i+1; } else if (cstart != mstart) crash_memory_range[i].end = cstart - 1; else crash_memory_range[i].start = cend + 1; } } /* Insert split memory region, if any. */ if (tidx >= 0) { if (*nr_ranges == max_memory_ranges) { /* No space to insert another element. */ fprintf(stderr, "Error: Number of crash memory ranges" " excedeed the max limit\n"); return -1; } for (j = (*nr_ranges - 1); j >= tidx; j--) crash_memory_range[j+1] = crash_memory_range[j]; crash_memory_range[tidx].start = temp_region.start; crash_memory_range[tidx].end = temp_region.end; crash_memory_range[tidx].type = temp_region.type; (*nr_ranges)++; } return 0; } static int get_crash_memory_ranges(int *ranges) { const char *iomem = proc_iomem(); char line[MAX_LINE]; FILE *fp; unsigned long start, end; crash_memory_range = xmalloc(sizeof(struct memory_range) * max_memory_ranges); 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) { char *str; int type, consumed, count; if (memory_ranges >= max_memory_ranges) break; count = sscanf(line, "%lx-%lx : %n", &start, &end, &consumed); str = line + consumed; if (count != 2) continue; if (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "Crash kernel\n", 13) == 0) { /* Reserved memory region. New kernel can * use this region to boot into. */ crash_reserved_mem.start = start; crash_reserved_mem.end = end; crash_reserved_mem.type = RANGE_RAM; continue; } else if (memcmp(str, "Kernel code\n", 12) == 0) { kernel_code_start = start; kernel_code_end = end; continue; } else if (memcmp(str, "Uncached RAM\n", 13) == 0) { type = RANGE_UNCACHED; } else { continue; } crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; } fclose(fp); if (exclude_crash_reserve_region(&memory_ranges) < 0) return -1; *ranges = memory_ranges; return 0; } /* * Note that this assignes a malloced pointer to *cmdline, * which is likely never freed by the caller */ static void cmdline_add_elfcorehdr(const char **cmdline, unsigned long addr) { char *str; char buf[64]; size_t len; sprintf(buf, " elfcorehdr=%ldK", addr/1024); len = strlen(*cmdline) + strlen(buf) + 1; str = xmalloc(len); sprintf(str, "%s%s", *cmdline, buf); *cmdline = str; } int load_crashdump_segments(struct kexec_info *info, struct mem_ehdr *ehdr, unsigned long max_addr, unsigned long min_base, const char **cmdline) { int nr_ranges; unsigned long sz; size_t size; void *tmp; if (info->kexec_flags & KEXEC_ON_CRASH && get_crash_memory_ranges(&nr_ranges) == 0) { int i; elf_info.kern_paddr_start = kernel_code_start; for (i=0; i < nr_ranges; i++) { unsigned long long mstart = crash_memory_range[i].start; unsigned long long mend = crash_memory_range[i].end; if (!mstart && !mend) continue; if (kernel_code_start >= mstart && kernel_code_start < mend) { elf_info.kern_vaddr_start = mstart + LOAD_OFFSET; break; } } elf_info.kern_size = kernel_code_end - kernel_code_start + 1; if (crash_create_elf64_headers(info, &elf_info, crash_memory_range, nr_ranges, &tmp, &sz, EFI_PAGE_SIZE) < 0) return -1; elfcorehdr = add_buffer(info, tmp, sz, sz, EFI_PAGE_SIZE, min_base, max_addr, -1); loaded_segments[loaded_segments_num].start = elfcorehdr; loaded_segments[loaded_segments_num].end = elfcorehdr + sz; loaded_segments_num++; cmdline_add_elfcorehdr(cmdline, elfcorehdr); } add_loaded_segments_info(ehdr); size = sizeof(struct loaded_segment) * loaded_segments_num; qsort(loaded_segments, loaded_segments_num, sizeof(struct loaded_segment), seg_comp); loaded_segments_base = add_buffer(info, loaded_segments, size, size, 16, 0, max_addr, -1); elf_rel_set_symbol(&info->rhdr, "__loaded_segments", &loaded_segments_base, sizeof(long)); elf_rel_set_symbol(&info->rhdr, "__loaded_segments_num", &loaded_segments_num, sizeof(long)); return 0; } int is_crashkernel_mem_reserved(void) { uint64_t start, end; return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ? (start != end) : 0; } kexec-tools-2.0.10/kexec/arch/ia64/kexec-ia64.h0000644001567400156740000000071411642166046017715 0ustar hormshorms#ifndef KEXEC_IA64_H #define KEXEC_IA64_H extern int max_memory_ranges; 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); int update_loaded_segments(struct mem_ehdr *ehdr); void move_loaded_segments(struct mem_ehdr *ehdr, unsigned long addr); #define EFI_PAGE_SIZE (1UL<<12) #define ELF_PAGE_SIZE (1UL<<16) #endif /* KEXEC_IA64_H */ kexec-tools-2.0.10/kexec/arch/ia64/crashdump-ia64.h0000644001567400156740000000057311424244110020572 0ustar hormshorms#ifndef CRASHDUMP_IA64_H #define CRASHDUMP_IA64_H #define PAGE_OFFSET 0xe000000000000000UL #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) extern int load_crashdump_segments(struct kexec_info *info, struct mem_ehdr *ehdr, unsigned long max_addr, unsigned long min_base, const char **cmdline); #define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1) #endif kexec-tools-2.0.10/kexec/arch/ia64/include/arch/options.h0000644001567400156740000000271711642166046022115 0ustar hormshorms#ifndef KEXEC_ARCH_IA64_OPTIONS_H #define KEXEC_ARCH_IA64_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) #define OPT_APPEND (OPT_ARCH_MAX+0) #define OPT_RAMDISK (OPT_ARCH_MAX+1) #define OPT_NOIO (OPT_ARCH_MAX+2) #define OPT_VMM (OPT_ARCH_MAX+3) /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ {"command-line", 1, 0, OPT_APPEND}, \ {"append", 1, 0, OPT_APPEND}, \ {"initrd", 1, 0, OPT_RAMDISK}, \ {"noio", 0, 0, OPT_NOIO}, \ {"vmm", 1, 0, OPT_VMM}, \ #define KEXEC_ALL_OPT_STR KEXEC_OPT_STR #endif /* KEXEC_ARCH_IA64_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/m68k/Makefile0000644001567400156740000000070012417127312017353 0ustar hormshorms# # kexec m68k (linux booting linux) # m68k_KEXEC_SRCS = kexec/arch/m68k/kexec-m68k.c m68k_KEXEC_SRCS += kexec/arch/m68k/kexec-elf-m68k.c m68k_KEXEC_SRCS += kexec/arch/m68k/kexec-elf-rel-m68k.c m68k_KEXEC_SRCS += kexec/arch/m68k/bootinfo.c m68k_ADD_SEGMENT = m68k_VIRT_TO_PHYS = dist += kexec/arch/m68k/Makefile $(m68k_KEXEC_SRCS) \ kexec/arch/m68k/bootinfo.h \ kexec/arch/m68k/kexec-m68k.h \ kexec/arch/m68k/include/arch/options.h kexec-tools-2.0.10/kexec/arch/m68k/kexec-m68k.c0000644001567400156740000000425212417126536017756 0ustar hormshorms/* * kexec-m68k.c - kexec for m68k * * Copyright (C) 2013 Geert Uytterhoeven * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-m68k.h" #include "bootinfo.h" #include static unsigned long m68k_memoffset; /* Return a sorted list of memory ranges. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { bootinfo_load(); *ranges = bootinfo_get_memory_ranges(range); m68k_memoffset = (*range)[0].start; return 0; } struct file_type file_type[] = { {"elf-m68k", elf_m68k_probe, elf_m68k_load, elf_m68k_usage}, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { } int arch_process_options(int argc, char **argv) { static const struct option options[] = { KEXEC_ALL_OPTIONS { "bootinfo", 1, NULL, OPT_BOOTINFO }, { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_ALL_OPT_STR; int opt; 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_BOOTINFO: bootinfo_file = optarg; break; } } /* Reset getopt for the next pass; called in other source modules */ opterr = 1; optind = 1; return 0; } const struct arch_map_entry arches[] = { { "m68k", KEXEC_ARCH_68K }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } int is_crashkernel_mem_reserved(void) { return 0; } unsigned long virt_to_phys(unsigned long addr) { return addr + m68k_memoffset; } /* * add_segment() should convert base to a physical address on m68k, * while the default is just to work with base as is */ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz) { add_segment_phys_virt(info, buf, bufsz, base, memsz, 1); } kexec-tools-2.0.10/kexec/arch/m68k/kexec-elf-m68k.c0000644001567400156740000001136112417126536020521 0ustar hormshorms/* * kexec-elf-m68k.c - kexec Elf loader for m68k * * Copyright (C) 2013 Geert Uytterhoeven * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "kexec-m68k.h" #include "bootinfo.h" #include #define KiB * 1024 #define MiB * 1024 KiB #define PAGE_SIZE 4 KiB int elf_m68k_probe(const char *buf, off_t len) { struct mem_ehdr ehdr; int result; result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) goto out; /* Verify the architecuture specific bits */ if (ehdr.e_machine != EM_68K) { /* for a different architecture */ fprintf(stderr, "Not for this architecture.\n"); result = -1; goto out; } result = 0; out: free_elf_info(&ehdr); return result; } void elf_m68k_usage(void) { printf(" --command-line=STRING Set the kernel command line to STRING\n" " --append=STRING Set the kernel command line to STRING\n" " --reuse-cmdline Use kernel command line from running system.\n" " --ramdisk=FILE Use FILE as the kernel's initial ramdisk.\n" " --initrd=FILE Use FILE as the kernel's initial ramdisk.\n" " --bootinfo=FILE Use FILE as the kernel's bootinfo\n" ); } static unsigned long segment_end(const struct kexec_info *info, int i) { return (unsigned long)info->segment[i].mem + info->segment[i].memsz - 1; } int elf_m68k_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; const char *cmdline = NULL, *ramdisk_file = NULL; int opt, result, i; unsigned long bootinfo_addr, ramdisk_addr = 0; off_t ramdisk_size = 0; /* See options.h if adding any more options. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, NULL, OPT_APPEND }, { "append", 1, NULL, OPT_APPEND }, { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, { "ramdisk", 1, NULL, OPT_RAMDISK }, { "initrd", 1, NULL, OPT_RAMDISK }, { "bootinfo", 1, NULL, OPT_BOOTINFO }, { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "d"; while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch (opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) break; case OPT_APPEND: cmdline = optarg; break; case OPT_REUSE_CMDLINE: cmdline = get_command_line(); break; case OPT_RAMDISK: ramdisk_file = optarg; break; case OPT_BOOTINFO: break; } } result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) die("ELF exec parse failed\n"); /* Fixup PT_LOAD segments that include the ELF header (offset zero) */ for (i = 0; i < ehdr.e_phnum; i++) { struct mem_phdr *phdr; phdr = &ehdr.e_phdr[i]; if (phdr->p_type != PT_LOAD || phdr->p_offset) continue; dbgprintf("Removing ELF header from segment %d\n", i); phdr->p_paddr += PAGE_SIZE; phdr->p_vaddr += PAGE_SIZE; phdr->p_filesz -= PAGE_SIZE; phdr->p_memsz -= PAGE_SIZE; phdr->p_offset += PAGE_SIZE; phdr->p_data += PAGE_SIZE; } /* Load the ELF data */ result = elf_exec_load(&ehdr, info); if (result < 0) die("ELF exec load failed\n"); info->entry = (void *)virt_to_phys(ehdr.e_entry); /* Bootinfo must be stored right after the kernel */ bootinfo_addr = segment_end(info, info->nr_segments - 1) + 1; /* Load ramdisk */ if (ramdisk_file) { void *ramdisk = slurp_decompress_file(ramdisk_file, &ramdisk_size); /* Store ramdisk at top of first memory chunk */ ramdisk_addr = _ALIGN_DOWN(info->memory_range[0].end - ramdisk_size + 1, PAGE_SIZE); if (!buf) die("Ramdisk load failed\n"); add_buffer(info, ramdisk, ramdisk_size, ramdisk_size, PAGE_SIZE, ramdisk_addr, info->memory_range[0].end, 1); } /* Update and add bootinfo */ bootinfo_set_cmdline(cmdline); bootinfo_set_ramdisk(ramdisk_addr, ramdisk_size); if (kexec_debug) bootinfo_print(); add_bootinfo(info, bootinfo_addr); /* * Check if the kernel (and bootinfo) exceed 4 MiB, as current kernels * don't support that. * As the segments are still unsorted, the bootinfo is located in the * last segment. */ if (segment_end(info, info->nr_segments - 1) >= virt_to_phys(4 MiB - 1)) printf("WARNING: Kernel is larger than 4 MiB\n"); /* Check struct bootversion at start of kernel */ bootinfo_check_bootversion(info); return 0; } kexec-tools-2.0.10/kexec/arch/m68k/kexec-elf-rel-m68k.c0000644001567400156740000000145612417126536021305 0ustar hormshorms/* * kexec-elf-rel-m68k.c - kexec Elf relocation routines * * Copyright (C) 2013 Geert Uytterhoeven * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #include #include #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_68K) return 0; return 1; } void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), unsigned long r_type, void *UNUSED(location), unsigned long UNUSED(address), unsigned long UNUSED(value)) { switch (r_type) { default: die("Unknown rela relocation: %lu\n", r_type); break; } return; } kexec-tools-2.0.10/kexec/arch/m68k/bootinfo.c0000644001567400156740000001264012417126536017713 0ustar hormshorms #include #include #include #include "../../kexec.h" #include "bootinfo.h" const char *bootinfo_file = DEFAULT_BOOTINFO_FILE; static struct bi_rec *bootinfo; static off_t bootinfo_size; static unsigned int num_memchunks; static struct bi_rec *bi_next(struct bi_rec *bi, uint16_t size) { return (void *)((unsigned long)bi + size); } static struct bi_rec *bi_find(struct bi_rec *prev, uint16_t tag) { struct bi_rec *bi = prev ? bi_next(prev, prev->size) : bootinfo; for (bi = prev ? bi_next(prev, prev->size) : bootinfo; bi->tag != BI_LAST; bi = bi_next(bi, bi->size)) if (bi->tag == tag) return bi; return NULL; } static void bi_remove(uint16_t tag) { struct bi_rec *bi; off_t rem; uint16_t size; bi = bootinfo; rem = bootinfo_size; while (1) { if (bi->tag == BI_LAST) break; size = bi->size; if (bi->tag == tag) { memmove(bi, bi_next(bi, size), rem - size); bootinfo_size -= size; rem -= size; continue; } bi = bi_next(bi, size); rem -= size; } } static struct bi_rec *bi_add(uint16_t tag, uint16_t size) { struct bi_rec *bi; /* Add 4-byte header and round up to multiple of 4 bytes */ size = _ALIGN_UP(4 + size, 4); bootinfo = xrealloc(bootinfo, bootinfo_size + size); /* Replace old sentinel by new record */ bi = bi_next(bootinfo, bootinfo_size - 2); bootinfo_size += size; memset(bi, 0, size); bi->tag = tag; bi->size = size; /* Re-add sentinel */ bi_next(bi, size)->tag = BI_LAST; return bi; } void bootinfo_load(void) { struct bi_rec *bi; off_t rem; uint16_t tag, size; dbgprintf("Loading bootinfo from %s\n", bootinfo_file); bootinfo = (void *)slurp_file_len(bootinfo_file, MAX_BOOTINFO_SIZE, &bootinfo_size); if (!bootinfo) die("No bootinfo\n"); bi = bootinfo; rem = bootinfo_size; while (1) { if (rem < 2) die("Unexpected end of bootinfo\n"); tag = bi->tag; if (tag == BI_LAST) { rem -= 2; break; } if (rem < 4) die("Unexpected end of bootinfo\n"); size = bi->size; if (size < 4 || size % 4) die("Invalid tag size\n"); if (rem < size) die("Unexpected end of bootinfo\n"); if (tag == BI_MEMCHUNK) num_memchunks++; bi = bi_next(bi, size); rem -= size; } if (rem) die("Trailing data at end of bootinfo\n"); } void bootinfo_print(void) { struct bi_rec *bi = bootinfo; uint16_t tag, size; while (1) { tag = bi->tag; if (tag == BI_LAST) { puts("BI_LAST"); break; } size = bi->size; switch (tag) { case BI_MACHTYPE: printf("BI_MACHTYPE: 0x%08x\n", bi->machtype); break; case BI_MEMCHUNK: printf("BI_MEMCHUNK: 0x%08x bytes at 0x%08x\n", bi->mem_info.size, bi->mem_info.addr); break; case BI_RAMDISK: printf("BI_RAMDISK: 0x%08x bytes at 0x%08x\n", bi->mem_info.size, bi->mem_info.addr); break; case BI_COMMAND_LINE: printf("BI_COMMAND_LINE: %s\n", bi->string); break; default: printf("BI tag 0x%04x size %u\n", tag, size); break; } bi = bi_next(bi, size); } } int bootinfo_get_memory_ranges(struct memory_range **range) { struct memory_range *ranges; unsigned int i; struct bi_rec *bi; ranges = xmalloc(num_memchunks * sizeof(struct memory_range)); for (i = 0, bi = NULL; i < num_memchunks && (bi = bi_find(bi, BI_MEMCHUNK)); i++) { ranges[i].start = bi->mem_info.addr; ranges[i].end = bi->mem_info.addr + bi->mem_info.size - 1; ranges[i].type = RANGE_RAM; } *range = ranges; return i; } void bootinfo_set_cmdline(const char *cmdline) { struct bi_rec *bi; uint16_t size; /* Remove existing command line records */ bi_remove(BI_COMMAND_LINE); if (!cmdline) return; /* Add new command line record */ size = strlen(cmdline) + 1; bi = bi_add(BI_COMMAND_LINE, size); memcpy(bi->string, cmdline, size); } void bootinfo_set_ramdisk(unsigned long ramdisk_addr, unsigned long ramdisk_size) { struct bi_rec *bi; /* Remove existing ramdisk records */ bi_remove(BI_RAMDISK); if (!ramdisk_size) return; /* Add new ramdisk record */ bi = bi_add(BI_RAMDISK, sizeof(bi->mem_info)); bi->mem_info.addr = ramdisk_addr; bi->mem_info.size = ramdisk_size; } /* * Check the bootinfo version in the kernel image * All failures are non-fatal, as kexec may be used to load * non-Linux images */ void bootinfo_check_bootversion(const struct kexec_info *info) { struct bi_rec *bi; const struct bootversion *bv; uint16_t major, minor; unsigned int i; bv = info->segment[0].buf; if (bv->magic != BOOTINFOV_MAGIC) { printf("WARNING: No bootversion in kernel image\n"); return; } bi = bi_find(NULL, BI_MACHTYPE); if (!bi) { printf("WARNING: No machtype in bootinfo\n"); return; } for (i = 0; bv->machversions[i].machtype != bi->machtype; i++) if (!bv->machversions[i].machtype) { printf("WARNING: Machtype 0x%08x not in kernel bootversion\n", bi->machtype); return; } major = BI_VERSION_MAJOR(bv->machversions[i].version); minor = BI_VERSION_MINOR(bv->machversions[i].version); dbgprintf("Kernel uses bootversion %u.%u\n", major, minor); if (major != SUPPORTED_BOOTINFO_VERSION) printf("WARNING: Kernel bootversion %u.%u is too %s for this kexec (expected %u.x)\n", major, minor, major < SUPPORTED_BOOTINFO_VERSION ? "old" : "new", SUPPORTED_BOOTINFO_VERSION); } void add_bootinfo(struct kexec_info *info, unsigned long addr) { add_buffer(info, bootinfo, bootinfo_size, bootinfo_size, sizeof(void *), addr, 0x0fffffff, 1); } kexec-tools-2.0.10/kexec/arch/m68k/bootinfo.h0000644001567400156740000000171512417126536017721 0ustar hormshorms#include #define DEFAULT_BOOTINFO_FILE "/proc/bootinfo" #define MAX_BOOTINFO_SIZE 1536 /* * Convenience overlay of several struct bi_record variants */ struct bi_rec { __be16 tag; __be16 size; union { __be32 data[0]; /* shorthands for the types we use */ __be32 machtype; struct { __be32 addr; __be32 size; } mem_info; char string[0]; }; }; /* * We only support the "new" tagged bootinfo (v2) */ #define SUPPORTED_BOOTINFO_VERSION 2 extern const char *bootinfo_file; extern void bootinfo_load(void); extern void bootinfo_print(void); extern int bootinfo_get_memory_ranges(struct memory_range **range); extern void bootinfo_set_cmdline(const char *cmdline); extern void bootinfo_set_ramdisk(unsigned long ramdisk_addr, unsigned long ramdisk_size); extern void bootinfo_check_bootversion(const struct kexec_info *info); extern void add_bootinfo(struct kexec_info *info, unsigned long addr); kexec-tools-2.0.10/kexec/arch/m68k/kexec-m68k.h0000644001567400156740000000036412417126536017763 0ustar hormshorms#ifndef KEXEC_M68K_H #define KEXEC_M68K_H int elf_m68k_probe(const char *buf, off_t len); int elf_m68k_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void elf_m68k_usage(void); #endif /* KEXEC_M68K_H */ kexec-tools-2.0.10/kexec/arch/m68k/include/arch/options.h0000644001567400156740000000315212417126536022132 0ustar hormshorms#ifndef KEXEC_ARCH_M68K_OPTIONS_H #define KEXEC_ARCH_M68K_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) /* All 'local' loader options: */ #define OPT_APPEND (OPT_ARCH_MAX+0) #define OPT_REUSE_CMDLINE (OPT_ARCH_MAX+1) #define OPT_RAMDISK (OPT_ARCH_MAX+2) #define OPT_BOOTINFO (OPT_ARCH_MAX+3) /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ { "command-line", 1, NULL, OPT_APPEND }, \ { "append", 1, NULL, OPT_APPEND }, \ { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \ { "ramdisk", 1, NULL, OPT_RAMDISK }, \ { "initrd", 1, NULL, OPT_RAMDISK }, \ { "bootinfo", 1, NULL, OPT_BOOTINFO }, #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR #endif /* KEXEC_ARCH_M68K_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/mips/Makefile0000644001567400156740000000073511642166046017554 0ustar hormshorms# # kexec mips (linux booting linux) # mips_KEXEC_SRCS = kexec/arch/mips/kexec-mips.c mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-mips.c mips_KEXEC_SRCS += kexec/arch/mips/kexec-elf-rel-mips.c mips_KEXEC_SRCS += kexec/arch/mips/crashdump-mips.c mips_ADD_BUFFER = mips_ADD_SEGMENT = mips_VIRT_TO_PHYS = dist += kexec/arch/mips/Makefile $(mips_KEXEC_SRCS) \ kexec/arch/mips/kexec-mips.h \ kexec/arch/mips/crashdump-mips.h \ kexec/arch/mips/include/arch/options.h kexec-tools-2.0.10/kexec/arch/mips/kexec-mips.c0000644001567400156740000000646311642166046020331 0ustar hormshorms/* * kexec-mips.c - kexec for mips * Copyright (C) 2007 Francesco Chiechi, Alessandro Rubini * Copyright (C) 2007 Tvblob s.r.l. * * derived from ../ppc/kexec-mips.c * 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 #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-mips.h" #include 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, unsigned long UNUSED(kexec_flags)) { int memory_ranges = 0; 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 (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "reserved\n", 9) == 0) { type = RANGE_RESERVED; } else { continue; } memory_range[memory_ranges].start = start; memory_range[memory_ranges].end = end; memory_range[memory_ranges].type = type; memory_ranges++; } fclose(fp); *range = memory_range; *ranges = memory_ranges; return 0; } struct file_type file_type[] = { {"elf-mips", elf_mips_probe, elf_mips_load, elf_mips_usage}, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { #ifdef __mips64 fprintf(stderr, " --elf32-core-headers Prepare core headers in " "ELF32 format\n"); #endif } #ifdef __mips64 struct arch_options_t arch_options = { .core_header_type = CORE_TYPE_ELF64 }; #endif int arch_process_options(int argc, char **argv) { return 0; } const struct arch_map_entry arches[] = { /* For compatibility with older patches * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_MIPS here. */ { "mips", KEXEC_ARCH_MIPS }, { "mips64", KEXEC_ARCH_MIPS }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } unsigned long virt_to_phys(unsigned long addr) { return addr & 0x7fffffff; } /* * add_segment() should convert base to a physical address on mips, * while the default is just to work with base as is */ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz) { add_segment_phys_virt(info, buf, bufsz, virt_to_phys(base), memsz, 1); } /* * add_buffer() should convert base to a physical address on mips, * while the default is just to work with base as is */ 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) { return add_buffer_phys_virt(info, buf, bufsz, memsz, buf_align, buf_min, buf_max, buf_end, 1); } kexec-tools-2.0.10/kexec/arch/mips/kexec-elf-mips.c0000644001567400156740000000771712466760572021111 0ustar hormshorms/* * kexec-elf-mips.c - kexec Elf loader for mips * Copyright (C) 2007 Francesco Chiechi, Alessandro Rubini * Copyright (C) 2007 Tvblob s.r.l. * * derived from ../ppc/kexec-elf-ppc.c * 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 #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "kexec-mips.h" #include "crashdump-mips.h" #include static const int probe_debug = 0; #define BOOTLOADER "kexec" #define MAX_COMMAND_LINE 256 #define UPSZ(X) _ALIGN_UP(sizeof(X), 4) static char cmdline_buf[256] = "kexec "; int elf_mips_probe(const char *buf, off_t len) { struct mem_ehdr ehdr; int result; result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) { goto out; } /* Verify the architecuture specific bits */ if (ehdr.e_machine != EM_MIPS) { /* 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_mips_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_mips_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; char *crash_cmdline; int opt; int result; unsigned long cmdline_addr; size_t i; /* See options.h if adding any more options. */ 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 "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 OPT_APPEND: command_line = optarg; break; } } command_line_len = 0; /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & KEXEC_ON_CRASH) { crash_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE); } else crash_cmdline = NULL; result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) die("ELF exec parse failed\n"); /* Read in the PT_LOAD segments and remove CKSEG0 mask from address*/ for (i = 0; i < ehdr.e_phnum; i++) { struct mem_phdr *phdr; phdr = &ehdr.e_phdr[i]; if (phdr->p_type == PT_LOAD) phdr->p_paddr = virt_to_phys(phdr->p_paddr); } /* Load the Elf data */ result = elf_exec_load(&ehdr, info); if (result < 0) die("ELF exec load failed\n"); info->entry = (void *)virt_to_phys(ehdr.e_entry); if (command_line) command_line_len = strlen(command_line) + 1; if (info->kexec_flags & KEXEC_ON_CRASH) { result = load_crashdump_segments(info, crash_cmdline, 0, 0); if (result < 0) { free(crash_cmdline); return -1; } } if (command_line) strncat(cmdline_buf, command_line, command_line_len); if (crash_cmdline) strncat(cmdline_buf, crash_cmdline, sizeof(crash_cmdline) - strlen(crash_cmdline) - 1); if (info->kexec_flags & KEXEC_ON_CRASH) /* In case of crashdump segment[0] is kernel. * Put cmdline just after it. */ cmdline_addr = (unsigned long)info->segment[0].mem + info->segment[0].memsz; else cmdline_addr = 0; add_buffer(info, cmdline_buf, sizeof(cmdline_buf), sizeof(cmdline_buf), sizeof(void *), cmdline_addr, 0x0fffffff, 1); return 0; } kexec-tools-2.0.10/kexec/arch/mips/kexec-elf-rel-mips.c0000644001567400156740000000170411642166046021646 0ustar hormshorms/* * kexec-elf-rel-mips.c - kexec Elf relocation routines * Copyright (C) 2007 Francesco Chiechi, Alessandro Rubini * Copyright (C) 2007 Tvblob s.r.l. * * derived from ../ppc/kexec-elf-rel-ppc.c * 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 #include #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_MIPS) { return 0; } return 1; } void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), unsigned long r_type, void *UNUSED(location), unsigned long UNUSED(address), unsigned long UNUSED(value)) { switch(r_type) { default: die("Unknown rela relocation: %lu\n", r_type); break; } return; } kexec-tools-2.0.10/kexec/arch/mips/crashdump-mips.c0000644001567400156740000002525412466760660021226 0ustar hormshorms/* * kexec: Linux boots Linux * * 2005 (C) IBM Corporation. * 2008 (C) MontaVista Software, 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 (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 #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "../../crashdump.h" #include "kexec-mips.h" #include "crashdump-mips.h" #include "unused.h" /* Stores a sorted list of RAM memory ranges for which to create elf headers. * A separate program header is created for backup region */ static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES]; /* Memory region reserved for storing panic kernel and other data. */ static struct memory_range crash_reserved_mem; /* Read kernel physical load addr from the file returned by proc_iomem() * (Kernel Code) and store in kexec_info */ static int get_kernel_paddr(struct crash_elf_info *elf_info) { uint64_t start; if (xen_present()) /* Kernel not entity mapped under Xen */ return 0; if (parse_iomem_single("Kernel code\n", &start, NULL) == 0) { elf_info->kern_paddr_start = start; dbgprintf("kernel load physical addr start = 0x%" PRIu64 "\n", start); return 0; } fprintf(stderr, "Cannot determine kernel physical load addr\n"); return -1; } static int get_kernel_vaddr_and_size(struct crash_elf_info *elf_info, unsigned long start_offset) { uint64_t end; if (!elf_info->kern_paddr_start) return -1; elf_info->kern_vaddr_start = elf_info->kern_paddr_start | start_offset; if (parse_iomem_single("Kernel data\n", NULL, &end) == 0) { elf_info->kern_size = end - elf_info->kern_paddr_start; dbgprintf("kernel_vaddr= 0x%llx paddr %llx\n", elf_info->kern_vaddr_start, elf_info->kern_paddr_start); dbgprintf("kernel size = 0x%lx\n", elf_info->kern_size); return 0; } fprintf(stderr, "Cannot determine kernel virtual load addr and size\n"); return -1; } /* Removes crash reserve region from list of memory chunks for whom elf program * headers have to be created. Assuming crash reserve region to be a single * continuous area fully contained inside one of the memory chunks */ static int exclude_crash_reserve_region(int *nr_ranges) { int i, j, tidx = -1; unsigned long long cstart, cend; struct memory_range temp_region = { .start = 0, .end = 0 }; /* Crash reserved region. */ cstart = crash_reserved_mem.start; cend = crash_reserved_mem.end; for (i = 0; i < (*nr_ranges); i++) { unsigned long long mstart, mend; mstart = crash_memory_range[i].start; mend = crash_memory_range[i].end; if (cstart < mend && cend > mstart) { if (cstart != mstart && cend != mend) { /* Split memory region */ crash_memory_range[i].end = cstart - 1; temp_region.start = cend + 1; temp_region.end = mend; temp_region.type = RANGE_RAM; tidx = i+1; } else if (cstart != mstart) crash_memory_range[i].end = cstart - 1; else crash_memory_range[i].start = cend + 1; } } /* Insert split memory region, if any. */ if (tidx >= 0) { if (*nr_ranges == CRASH_MAX_MEMORY_RANGES) { /* No space to insert another element. */ fprintf(stderr, "Error: Number of crash memory ranges" " excedeed the max limit\n"); return -1; } for (j = (*nr_ranges - 1); j >= tidx; j--) crash_memory_range[j+1] = crash_memory_range[j]; crash_memory_range[tidx].start = temp_region.start; crash_memory_range[tidx].end = temp_region.end; crash_memory_range[tidx].type = temp_region.type; (*nr_ranges)++; } return 0; } /* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to * create Elf headers. Keeping it separate from get_memory_ranges() as * requirements are different in the case of normal kexec and crashdumps. * * Normal kexec needs to look at all of available physical memory irrespective * of the fact how much of it is being used by currently running kernel. * Crashdumps need to have access to memory regions actually being used by * running kernel. Expecting a different file/data structure than /proc/iomem * to look into down the line. May be something like /proc/kernelmem or may * be zone data structures exported from kernel. */ static int get_crash_memory_ranges(struct memory_range **range, int *ranges) { const char iomem[] = "/proc/iomem"; int memory_ranges = 0; char line[MAX_LINE]; FILE *fp; unsigned long long start, end; fp = fopen(iomem, "r"); if (!fp) { fprintf(stderr, "Cannot open %s: %s\n", iomem, strerror(errno)); return -1; } /* Separate segment for backup region */ crash_memory_range[0].start = BACKUP_SRC_START; crash_memory_range[0].end = BACKUP_SRC_END; crash_memory_range[0].type = RANGE_RAM; memory_ranges++; while (fgets(line, sizeof(line), fp) != 0) { char *str; int type, consumed, count; if (memory_ranges >= CRASH_MAX_MEMORY_RANGES) break; count = sscanf(line, "%Lx-%Lx : %n", &start, &end, &consumed); if (count != 2) continue; str = line + consumed; /* Only Dumping memory of type System RAM. */ if (memcmp(str, "System RAM\n", 11) == 0) { type = RANGE_RAM; } else if (memcmp(str, "Crash kernel\n", 13) == 0) { /* Reserved memory region. New kernel can * use this region to boot into. */ crash_reserved_mem.start = start; crash_reserved_mem.end = end; crash_reserved_mem.type = RANGE_RAM; continue; } else continue; if (start == BACKUP_SRC_START && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; /* Segregate linearly mapped region. */ if ((MAXMEM - 1) >= start && (MAXMEM - 1) <= end) { crash_memory_range[memory_ranges - 1].end = MAXMEM - 1; /* Add segregated region. */ crash_memory_range[memory_ranges].start = MAXMEM; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = type; memory_ranges++; } } fclose(fp); if (exclude_crash_reserve_region(&memory_ranges) < 0) return -1; *range = crash_memory_range; *ranges = memory_ranges; return 0; } /* Converts unsigned long to ascii string. */ static void ultoa(unsigned long i, char *str) { int j = 0, k; char tmp; do { str[j++] = i % 10 + '0'; } while ((i /= 10) > 0); str[j] = '\0'; /* Reverse the string. */ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { tmp = str[k]; str[k] = str[j]; str[j] = tmp; } } /* Adds the appropriate mem= options to command line, indicating the * memory region the new kernel can use to boot into. */ static int cmdline_add_mem(char *cmdline, unsigned long addr, unsigned long size) { int cmdlen, len; char str[50], *ptr; addr = addr/1024; size = size/1024; ptr = str; strcpy(str, " mem="); ptr += strlen(str); ultoa(size, ptr); strcat(str, "K@"); ptr = str + strlen(str); ultoa(addr, ptr); strcat(str, "K"); len = strlen(str); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str); return 0; } /* Adds the elfcorehdr= command line parameter to command line. */ static int cmdline_add_elfcorehdr(char *cmdline, unsigned long addr) { int cmdlen, len, align = 1024; char str[30], *ptr; /* Passing in elfcorehdr=xxxK format. Saves space required in cmdline. * Ensure 1K alignment*/ if (addr%align) return -1; addr = addr/align; ptr = str; strcpy(str, " elfcorehdr="); ptr += strlen(str); ultoa(addr, ptr); strcat(str, "K"); len = strlen(str); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str); return 0; } #ifdef __mips64 static struct crash_elf_info elf_info64 = { class: ELFCLASS64, data : ELFDATA2MSB, machine : EM_MIPS, page_offset : PAGE_OFFSET, lowmem_limit : MAXMEM, }; #endif static struct crash_elf_info elf_info32 = { class: ELFCLASS32, data : ELFDATA2MSB, machine : EM_MIPS, page_offset : PAGE_OFFSET, lowmem_limit : MAXMEM, }; /* Loads additional segments in case of a panic kernel is being loaded. * One segment for backup region, another segment for storing elf headers * for crash memory image. */ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, unsigned long UNUSED(max_addr), unsigned long UNUSED(min_base)) { void *tmp; unsigned long sz, elfcorehdr; int nr_ranges, align = 1024; struct memory_range *mem_range; crash_create_elf_headers_func crash_create = crash_create_elf32_headers; struct crash_elf_info *elf_info = &elf_info32; unsigned long start_offset = 0x80000000UL; #ifdef __mips64 if (arch_options.core_header_type == CORE_TYPE_ELF64) { elf_info = &elf_info64; crash_create = crash_create_elf64_headers; start_offset = 0xffffffff80000000UL; } #endif if (get_kernel_paddr(elf_info)) return -1; if (get_kernel_vaddr_and_size(elf_info, start_offset)) return -1; if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0) return -1; info->backup_src_start = BACKUP_SRC_START; info->backup_src_size = BACKUP_SRC_SIZE; /* Create a backup region segment to store backup data*/ sz = _ALIGN(BACKUP_SRC_SIZE, align); tmp = xmalloc(sz); memset(tmp, 0, sz); info->backup_start = add_buffer(info, tmp, sz, sz, align, crash_reserved_mem.start, crash_reserved_mem.end, -1); if (crash_create(info, elf_info, crash_memory_range, nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) return -1; elfcorehdr = add_buffer(info, tmp, sz, sz, align, crash_reserved_mem.start, crash_reserved_mem.end, -1); /* * backup segment is after elfcorehdr, so use elfcorehdr as top of * kernel's available memory */ cmdline_add_mem(mod_cmdline, crash_reserved_mem.start, elfcorehdr - crash_reserved_mem.start); cmdline_add_elfcorehdr(mod_cmdline, elfcorehdr); dbgprintf("CRASH MEMORY RANGES:\n"); dbgprintf("%016Lx-%016Lx\n", crash_reserved_mem.start, crash_reserved_mem.end); return 0; } int is_crashkernel_mem_reserved(void) { uint64_t start, end; return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ? (start != end) : 0; } kexec-tools-2.0.10/kexec/arch/mips/kexec-mips.h0000644001567400156740000000063312417126536020330 0ustar hormshorms#ifndef KEXEC_MIPS_H #define KEXEC_MIPS_H #define MAX_MEMORY_RANGES 64 #define MAX_LINE 160 #define CORE_TYPE_ELF32 1 #define CORE_TYPE_ELF64 2 int elf_mips_probe(const char *buf, off_t len); int elf_mips_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void elf_mips_usage(void); struct arch_options_t { int core_header_type; }; #endif /* KEXEC_MIPS_H */ kexec-tools-2.0.10/kexec/arch/mips/crashdump-mips.h0000644001567400156740000000140411642166046021213 0ustar hormshorms#ifndef CRASHDUMP_MIPS_H #define CRASHDUMP_MIPS_H struct kexec_info; int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline, unsigned long max_addr, unsigned long min_base); #ifdef __mips64 #define PAGE_OFFSET 0xa800000000000000ULL #else #define PAGE_OFFSET 0x80000000 #endif #define __pa(x) ((unsigned long)(X) & 0x7fffffff) #define MAXMEM 0x80000000 #define CRASH_MAX_MEMMAP_NR (KEXEC_MAX_SEGMENTS + 1) #define CRASH_MAX_MEMORY_RANGES (MAX_MEMORY_RANGES + 2) #define COMMAND_LINE_SIZE 512 /* Backup Region, First 1M of System RAM. */ #define BACKUP_SRC_START 0x00000000 #define BACKUP_SRC_END 0x000fffff #define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1) extern struct arch_options_t arch_options; #endif /* CRASHDUMP_MIPS_H */ kexec-tools-2.0.10/kexec/arch/mips/include/arch/options.h0000644001567400156740000000242211642166046022313 0ustar hormshorms#ifndef KEXEC_ARCH_MIPS_OPTIONS_H #define KEXEC_ARCH_MIPS_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) #define OPT_APPEND (OPT_ARCH_MAX+0) /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ {"command-line", 1, 0, OPT_APPEND}, \ {"append", 1, 0, OPT_APPEND}, #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR #endif /* KEXEC_ARCH_MIPS_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/cris/Makefile0000644001567400156740000000062311424244110017523 0ustar hormshormscris_KEXEC_SRCS = kexec/arch/cris/kexec-cris.c cris_KEXEC_SRCS += kexec/arch/cris/kexec-elf-cris.c cris_KEXEC_SRCS += kexec/arch/cris/cris-setup-simple.S cris_KEXEC_SRCS += kexec/arch/cris/kexec-elf-rel-cris.c cris_ADD_BUFFER = cris_ADD_SEGMENT = cris_VIRT_TO_PHYS = dist += kexec/arch/cris/Makefile $(cris_KEXEC_SRCS) \ kexec/arch/cris/kexec-cris.h \ kexec/arch/cris/include/arch/options.h kexec-tools-2.0.10/kexec/arch/cris/kexec-cris.c0000644001567400156740000000513012417126536020300 0ustar hormshorms/* * kexec-cris.c * Copyright (C) 2008 AXIS Communications AB * Written by Edgar E. Iglesias * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-cris.h" #include #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, unsigned long UNUSED(kexec_flags)) { int memory_ranges = 0; memory_range[memory_ranges].start = 0x40000000; memory_range[memory_ranges].end = 0x41000000; memory_range[memory_ranges].type = RANGE_RAM; memory_ranges++; memory_range[memory_ranges].start = 0xc0000000; memory_range[memory_ranges].end = 0xc1000000; memory_range[memory_ranges].type = RANGE_RAM; memory_ranges++; *range = memory_range; *ranges = memory_ranges; return 0; } struct file_type file_type[] = { {"elf-cris", elf_cris_probe, elf_cris_load, elf_cris_usage}, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { } int arch_process_options(int argc, char **argv) { return 0; } const struct arch_map_entry arches[] = { { "cris", KEXEC_ARCH_CRIS }, { "crisv32", KEXEC_ARCH_CRIS }, { 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } int is_crashkernel_mem_reserved(void) { return 0; } unsigned long virt_to_phys(unsigned long addr) { return (addr) & 0x7fffffff; } /* * add_segment() should convert base to a physical address on cris, * while the default is just to work with base as is */ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz) { add_segment_phys_virt(info, buf, bufsz, base, memsz, 1); } /* * add_buffer() should convert base to a physical address on cris, * while the default is just to work with base as is */ 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) { return add_buffer_phys_virt(info, buf, bufsz, memsz, buf_align, buf_min, buf_max, buf_end, 1); } kexec-tools-2.0.10/kexec/arch/cris/kexec-elf-cris.c0000644001567400156740000000645012417126536021052 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) 2008 AXIS Communications AB * Written by Edgar E. Iglesias * * Based on x86 implementation, * 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 #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../kexec-elf.h" #include "../../kexec-elf-boot.h" #include #include "kexec-cris.h" int elf_cris_probe(const char *buf, off_t len) { struct mem_ehdr ehdr; int result; result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) goto out; /* Verify the architecuture specific bits */ if (ehdr.e_machine != EM_CRIS) { result = -1; goto out; } result = 0; out: free_elf_info(&ehdr); return result; } void elf_cris_usage(void) { printf(" --append=STRING Set the kernel command line to STRING\n" ); } #define CRAMFS_MAGIC 0x28cd3d45 #define JHEAD_MAGIC 0x1FF528A6 #define JHEAD_SIZE 8 #define RAM_INIT_MAGIC 0x56902387 #define COMMAND_LINE_MAGIC 0x87109563 #define NAND_BOOT_MAGIC 0x9a9db001 int elf_cris_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; char *command_line; unsigned int *trampoline_buf; unsigned long trampoline_base; int opt; extern void cris_trampoline(void); extern unsigned long cris_trampoline_size; extern struct regframe_t { unsigned int regs[16]; } cris_regframe; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS {"append", 1, 0, OPT_APPEND}, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_OPT_STR ""; /* * Parse the command line arguments */ 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 OPT_APPEND: command_line = optarg; break; } } /* Load the ELF executable */ elf_exec_build_load(info, &ehdr, buf, len, 0); cris_regframe.regs[0] = virt_to_phys(ehdr.e_entry); cris_regframe.regs[8] = RAM_INIT_MAGIC; cris_regframe.regs[12] = NAND_BOOT_MAGIC; trampoline_buf = xmalloc(cris_trampoline_size); trampoline_base = add_buffer_virt(info, trampoline_buf, cris_trampoline_size, cris_trampoline_size, 4, 0, elf_max_addr(&ehdr), 1); memcpy(trampoline_buf, cris_trampoline, cris_trampoline_size); info->entry = (void *)trampoline_base; return 0; } kexec-tools-2.0.10/kexec/arch/cris/cris-setup-simple.S0000644001567400156740000000116011424244110021571 0ustar hormshorms/* * cris-setup-simple.S - code to execute before stepping into the new kernel. * Copyright (C) 2008 AXIS Communications AB * Written by Edgar E. Iglesias * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ .data .globl cris_trampoline cris_trampoline: .balign 4 lapc cris_regframe, $sp moveq 0, $r0 move $r0, $pid movem [$sp+], $r14 jump $r0 nop .globl cris_regframe cris_regframe: .balign 4 .fill 16, 4, 0 cris_trampoline_end: .globl cris_trampoline_size cris_trampoline_size: .long cris_trampoline_end - cris_trampoline kexec-tools-2.0.10/kexec/arch/cris/kexec-elf-rel-cris.c0000644001567400156740000000160111424244110021605 0ustar hormshorms/* * kexec-elf-rel-cris.c - kexec Elf relocation routines * Copyright (C) 2008 AXIS Communications AB * Written by Edgar E. Iglesias * * derived from ../ppc/kexec-elf-rel-ppc.c * 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 #include #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_CRIS) { 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) { default: die("Unknown rela relocation: %lu\n", r_type); break; } return; } kexec-tools-2.0.10/kexec/arch/cris/kexec-cris.h0000644001567400156740000000036112417126536020306 0ustar hormshorms#ifndef KEXEC_CRIS_H #define KEXEC_CRIS_H int elf_cris_probe(const char *buf, off_t len); int elf_cris_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void elf_cris_usage(void); #endif /* KEXEC_CRIS_H */ kexec-tools-2.0.10/kexec/arch/cris/include/arch/options.h0000644001567400156740000000233711642166046022310 0ustar hormshorms#ifndef KEXEC_ARCH_CRIS_OPTIONS_H #define KEXEC_ARCH_CRIS_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) #define OPT_APPEND (OPT_ARCH_MAX+0) /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ {"append", 1, 0, OPT_APPEND}, #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR #endif /* KEXEC_ARCH_CRIS_OPTIONS_H */ kexec-tools-2.0.10/kexec/libfdt/Makefile.libfdt0000644001567400156740000000000012242534555030576 1kexec-tools-2.0.10/kexec/libfdt/Makefile.libfdtustar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt.h0000644001567400156740000000000012242534555024644 1kexec-tools-2.0.10/kexec/libfdt/fdt.hustar hormshormskexec-tools-2.0.10/kexec/libfdt/libfdt.h0000644001567400156740000000000012417126536026022 1kexec-tools-2.0.10/kexec/libfdt/libfdt.hustar hormshormskexec-tools-2.0.10/kexec/libfdt/libfdt_env.h0000644001567400156740000000000012242534555027542 1kexec-tools-2.0.10/kexec/libfdt/libfdt_env.hustar hormshormskexec-tools-2.0.10/kexec/libfdt/libfdt_internal.h0000644001567400156740000000000012417126536031612 1kexec-tools-2.0.10/kexec/libfdt/libfdt_internal.hustar hormshormskexec-tools-2.0.10/kexec/arch/ppc/Makefile0000644001567400156740000000221612242534555017363 0ustar hormshorms# # kexec ppc (linux booting linux) # include $(srcdir)/kexec/libfdt/Makefile.libfdt ppc_KEXEC_SRCS = kexec/arch/ppc/kexec-ppc.c ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-ppc.c ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-elf-rel-ppc.c ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-dol-ppc.c ppc_KEXEC_SRCS += kexec/arch/ppc/kexec-uImage-ppc.c ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-simple.S ppc_KEXEC_SRCS += kexec/arch/ppc/ppc-setup-dol.S ppc_KEXEC_SRCS += kexec/arch/ppc/fixup_dtb.c ppc_KEXEC_SRCS += kexec/arch/ppc/fs2dt.c ppc_KEXEC_SRCS += kexec/arch/ppc/crashdump-powerpc.c ppc_UIMAGE = kexec/kexec-uImage.c ppc_libfdt_SRCS = kexec/arch/ppc/libfdt-wrapper.c libfdt_SRCS += $(LIBFDT_SRCS:%=kexec/libfdt/%) ppc_ARCH_REUSE_INITRD = ppc_CPPFLAGS = -I$(srcdir)/kexec/libfdt ppc_KEXEC_SRCS += $(libfdt_SRCS) $(ppc_libfdt_SRCS) ppc_ASFLAGS = -Wa,--noexecstack dist += kexec/arch/ppc/Makefile $(ppc_KEXEC_SRCS) \ kexec/arch/ppc/crashdump-powerpc.h kexec/arch/ppc/fixup_dtb.h \ kexec/arch/ppc/kexec-ppc.h kexec/arch/ppc/ops.h \ kexec/arch/ppc/ppc_asm.h \ kexec/arch/ppc/include/page.h kexec/arch/ppc/include/types.h \ kexec/arch/ppc/include/arch/options.h kexec-tools-2.0.10/kexec/arch/ppc/kexec-ppc.c0000644001567400156740000005526612417126536017763 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-ppc.h" #include "crashdump-powerpc.h" #include #include "config.h" unsigned long dt_address_cells = 0, dt_size_cells = 0; uint64_t rmo_top; uint64_t memory_limit; unsigned long long crash_base = 0, crash_size = 0; unsigned long long initrd_base = 0, initrd_size = 0; unsigned long long ramdisk_base = 0, ramdisk_size = 0; unsigned int rtas_base, rtas_size; int max_memory_ranges; const char *ramdisk; /* * Reads the #address-cells and #size-cells on this platform. * This is used to parse the memory/reg info from the device-tree */ int init_memory_region_info() { size_t res = 0; int fd; char *file; file = "/proc/device-tree/#address-cells"; fd = open(file, O_RDONLY); if (fd < 0) { fprintf(stderr, "Unable to open %s\n", file); return -1; } res = read(fd, &dt_address_cells, sizeof(dt_address_cells)); if (res != sizeof(dt_address_cells)) { fprintf(stderr, "Error reading %s\n", file); return -1; } close(fd); file = "/proc/device-tree/#size-cells"; fd = open(file, O_RDONLY); if (fd < 0) { fprintf(stderr, "Unable to open %s\n", file); return -1; } res = read(fd, &dt_size_cells, sizeof(dt_size_cells)); if (res != sizeof(dt_size_cells)) { fprintf(stderr, "Error reading %s\n", file); return -1; } close(fd); /* Convert the sizes into bytes */ dt_size_cells *= sizeof(unsigned long); dt_address_cells *= sizeof(unsigned long); return 0; } #define MAXBYTES 128 /* * Reads the memory region info from the device-tree node pointed * by @fd and fills the *start, *end with the boundaries of the region */ int read_memory_region_limits(int fd, unsigned long long *start, unsigned long long *end) { char buf[MAXBYTES]; unsigned long *p; unsigned long nbytes = dt_address_cells + dt_size_cells; if (lseek(fd, 0, SEEK_SET) == -1) { fprintf(stderr, "Error in file seek\n"); return -1; } if (read(fd, buf, nbytes) != nbytes) { fprintf(stderr, "Error reading the memory region info\n"); return -1; } p = (unsigned long*)buf; if (dt_address_cells == sizeof(unsigned long)) { *start = p[0]; p++; } else if (dt_address_cells == sizeof(unsigned long long)) { *start = ((unsigned long long *)p)[0]; p = (unsigned long long *)p + 1; } else { fprintf(stderr, "Unsupported value for #address-cells : %ld\n", dt_address_cells); return -1; } if (dt_size_cells == sizeof(unsigned long)) *end = *start + p[0]; else if (dt_size_cells == sizeof(unsigned long long)) *end = *start + ((unsigned long long *)p)[0]; else { fprintf(stderr, "Unsupported value for #size-cells : %ld\n", dt_size_cells); return -1; } return 0; } void arch_reuse_initrd(void) { reuse_initrd = 1; } #ifdef WITH_GAMECUBE #define MAX_MEMORY_RANGES 64 static struct memory_range memory_range[MAX_MEMORY_RANGES]; static int get_memory_ranges_gc(struct memory_range **range, int *ranges, unsigned long UNUSED(kexec_flags)) { int memory_ranges = 0; /* 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++; *range = memory_range; *ranges = memory_ranges; return 0; } #else static int use_new_dtb; static int nr_memory_ranges, nr_exclude_ranges; static struct memory_range *exclude_range; static struct memory_range *memory_range; static struct memory_range *base_memory_range; static uint64_t memory_max; /* * Count the memory nodes under /proc/device-tree and populate the * max_memory_ranges variable. This variable replaces MAX_MEMORY_RANGES * macro used earlier. */ static int count_memory_ranges(void) { char device_tree[256] = "/proc/device-tree/"; struct dirent *dentry; DIR *dir; if ((dir = opendir(device_tree)) == NULL) { perror(device_tree); return -1; } while ((dentry = readdir(dir)) != NULL) { if (strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory")) continue; max_memory_ranges++; } /* need to add extra region for retained initrd */ if (use_new_dtb) { max_memory_ranges++; } closedir(dir); return 0; } static void cleanup_memory_ranges(void) { free(memory_range); free(base_memory_range); free(exclude_range); } /* * Allocate memory for various data structures used to hold * values of different memory ranges */ static int alloc_memory_ranges(void) { int memory_range_len; memory_range_len = sizeof(struct memory_range) * max_memory_ranges; memory_range = malloc(memory_range_len); if (!memory_range) return -1; base_memory_range = malloc(memory_range_len); if (!base_memory_range) goto err1; exclude_range = malloc(memory_range_len); if (!exclude_range) goto err1; memset(memory_range, 0, memory_range_len); memset(base_memory_range, 0, memory_range_len); memset(exclude_range, 0, memory_range_len); return 0; err1: fprintf(stderr, "memory range structure allocation failure\n"); cleanup_memory_ranges(); return -1; } /* Sort the exclude ranges in memory */ static int sort_ranges(void) { int i, j; uint64_t tstart, tend; for (i = 0; i < nr_exclude_ranges - 1; i++) { for (j = 0; j < nr_exclude_ranges - i - 1; j++) { if (exclude_range[j].start > exclude_range[j+1].start) { tstart = exclude_range[j].start; tend = exclude_range[j].end; exclude_range[j].start = exclude_range[j+1].start; exclude_range[j].end = exclude_range[j+1].end; exclude_range[j+1].start = tstart; exclude_range[j+1].end = tend; } } } return 0; } /* Sort the base ranges in memory - this is useful for ensuring that our * ranges are in ascending order, even if device-tree read of memory nodes * is done differently. Also, could be used for other range coalescing later */ static int sort_base_ranges(void) { int i, j; unsigned long long tstart, tend; for (i = 0; i < nr_memory_ranges - 1; i++) { for (j = 0; j < nr_memory_ranges - i - 1; j++) { if (base_memory_range[j].start > base_memory_range[j+1].start) { tstart = base_memory_range[j].start; tend = base_memory_range[j].end; base_memory_range[j].start = base_memory_range[j+1].start; base_memory_range[j].end = base_memory_range[j+1].end; base_memory_range[j+1].start = tstart; base_memory_range[j+1].end = tend; } } } return 0; } static int realloc_memory_ranges(void) { size_t memory_range_len; max_memory_ranges++; memory_range_len = sizeof(struct memory_range) * max_memory_ranges; memory_range = (struct memory_range *) realloc(memory_range, memory_range_len); if (!memory_range) goto err; base_memory_range = (struct memory_range *) realloc(base_memory_range, memory_range_len); if (!base_memory_range) goto err; exclude_range = (struct memory_range *) realloc(exclude_range, memory_range_len); if (!exclude_range) goto err; usablemem_rgns.ranges = (struct memory_range *) realloc(usablemem_rgns.ranges, memory_range_len); if (!(usablemem_rgns.ranges)) goto err; return 0; err: fprintf(stderr, "memory range structure re-allocation failure\n"); return -1; } /* Get base memory ranges */ static int get_base_ranges(void) { int local_memory_ranges = 0; char device_tree[256] = "/proc/device-tree/"; char fname[256]; char buf[MAXBYTES]; DIR *dir, *dmem; struct dirent *dentry, *mentry; int n, fd; if ((dir = opendir(device_tree)) == NULL) { perror(device_tree); return -1; } while ((dentry = readdir(dir)) != NULL) { if (strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory")) continue; strcpy(fname, device_tree); strcat(fname, dentry->d_name); if ((dmem = opendir(fname)) == NULL) { perror(fname); closedir(dir); return -1; } while ((mentry = readdir(dmem)) != NULL) { unsigned long long start, end; if (strcmp(mentry->d_name, "reg")) continue; strcat(fname, "/reg"); if ((fd = open(fname, O_RDONLY)) < 0) { perror(fname); closedir(dmem); closedir(dir); return -1; } if (read_memory_region_limits(fd, &start, &end) != 0) { close(fd); closedir(dmem); closedir(dir); return -1; } if (local_memory_ranges >= max_memory_ranges) { if (realloc_memory_ranges() < 0){ close(fd); break; } } base_memory_range[local_memory_ranges].start = start; base_memory_range[local_memory_ranges].end = end; base_memory_range[local_memory_ranges].type = RANGE_RAM; local_memory_ranges++; dbgprintf("%016llx-%016llx : %x\n", base_memory_range[local_memory_ranges-1].start, base_memory_range[local_memory_ranges-1].end, base_memory_range[local_memory_ranges-1].type); close(fd); } closedir(dmem); } closedir(dir); nr_memory_ranges = local_memory_ranges; sort_base_ranges(); memory_max = base_memory_range[nr_memory_ranges - 1].end; dbgprintf("get base memory ranges:%d\n", nr_memory_ranges); return 0; } static int read_kernel_memory_limit(char *fname, char *buf) { FILE *file; int n; if (!fname || !buf) return -1; file = fopen(fname, "r"); if (file == NULL) { if (errno != ENOENT) { perror(fname); return -1; } errno = 0; /* * fall through. On older kernel this file * is not present. Hence return success. */ } else { /* Memory limit property is of u64 type. */ if ((n = fread(&memory_limit, 1, sizeof(uint64_t), file)) < 0) { perror(fname); goto err_out; } if (n != sizeof(uint64_t)) { fprintf(stderr, "%s node has invalid size: %d\n", fname, n); goto err_out; } fclose(file); } return 0; err_out: fclose(file); return -1; } /* Get devtree details and create exclude_range array * Also create usablemem_ranges for KEXEC_ON_CRASH */ static int get_devtree_details(unsigned long kexec_flags) { uint64_t rmo_base; unsigned long long tce_base; unsigned int tce_size; unsigned long long htab_base, htab_size; unsigned long long kernel_end; unsigned long long initrd_start, initrd_end; char buf[MAXBYTES]; char device_tree[256] = "/proc/device-tree/"; char fname[256]; DIR *dir, *cdir; FILE *file; struct dirent *dentry; int n, i = 0; if ((dir = opendir(device_tree)) == NULL) { perror(device_tree); return -1; } while ((dentry = readdir(dir)) != NULL) { if (strncmp(dentry->d_name, "chosen", 6) && strncmp(dentry->d_name, "memory@", 7) && strncmp(dentry->d_name, "memory", 6) && strncmp(dentry->d_name, "pci@", 4) && strncmp(dentry->d_name, "rtas", 4)) continue; strcpy(fname, device_tree); strcat(fname, dentry->d_name); if ((cdir = opendir(fname)) == NULL) { perror(fname); goto error_opendir; } if (strncmp(dentry->d_name, "chosen", 6) == 0) { /* only reserve kernel region if we are doing a crash kernel */ if (kexec_flags & KEXEC_ON_CRASH) { strcat(fname, "/linux,kernel-end"); file = fopen(fname, "r"); if (!file) { perror(fname); goto error_opencdir; } if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); goto error_openfile; } if (n == sizeof(uint32_t)) { kernel_end = ((uint32_t *)buf)[0]; } else if (n == sizeof(uint64_t)) { kernel_end = ((uint64_t *)buf)[0]; } else { fprintf(stderr, "%s node has invalid size: %d\n", fname, n); goto error_openfile; } fclose(file); /* Add kernel memory to exclude_range */ exclude_range[i].start = 0x0UL; exclude_range[i].end = kernel_end; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,crashkernel-base"); file = fopen(fname, "r"); if (!file) { perror(fname); goto error_opencdir; } if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); goto error_openfile; } if (n == sizeof(uint32_t)) { crash_base = ((uint32_t *)buf)[0]; } else if (n == sizeof(uint64_t)) { crash_base = ((uint64_t *)buf)[0]; } else { fprintf(stderr, "%s node has invalid size: %d\n", fname, n); goto error_openfile; } fclose(file); memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,crashkernel-size"); file = fopen(fname, "r"); if (!file) { perror(fname); goto error_opencdir; } if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); goto error_openfile; } if (n == sizeof(uint32_t)) { crash_size = ((uint32_t *)buf)[0]; } else if (n == sizeof(uint64_t)) { crash_size = ((uint64_t *)buf)[0]; } else { fprintf(stderr, "%s node has invalid size: %d\n", fname, n); goto error_openfile; } fclose(file); if (crash_base > mem_min) mem_min = crash_base; if (crash_base + crash_size < mem_max) mem_max = crash_base + crash_size; #ifndef CONFIG_BOOKE add_usable_mem_rgns(0, crash_base + crash_size); /* Reserve the region (KDUMP_BACKUP_LIMIT,crash_base) */ reserve(KDUMP_BACKUP_LIMIT, crash_base-KDUMP_BACKUP_LIMIT); #else add_usable_mem_rgns(crash_base, crash_size); #endif } /* * Read the first kernel's memory limit. * If the first kernel is booted with mem= option then * it would export "linux,memory-limit" file * reflecting value for the same. */ memset(fname, 0, sizeof(fname)); snprintf(fname, sizeof(fname), "%s%s%s", device_tree, dentry->d_name, "/linux,memory-limit"); if (read_kernel_memory_limit(fname, buf) < 0) goto error_opencdir; /* reserve the initrd_start and end locations. */ memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,initrd-start"); file = fopen(fname, "r"); if (!file) { errno = 0; initrd_start = 0; } else { if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); goto error_openfile; } if (n == sizeof(uint32_t)) { initrd_start = ((uint32_t *)buf)[0]; } else if (n == sizeof(uint64_t)) { initrd_start = ((uint64_t *)buf)[0]; } else { fprintf(stderr, "%s node has invalid size: %d\n", fname, n); goto error_openfile; } fclose(file); } memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,initrd-end"); file = fopen(fname, "r"); if (!file) { errno = 0; initrd_end = 0; } else { if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); goto error_openfile; } if (n == sizeof(uint32_t)) { initrd_end = ((uint32_t *)buf)[0]; } else if (n == sizeof(uint64_t)) { initrd_end = ((uint64_t *)buf)[0]; } else { fprintf(stderr, "%s node has invalid size: %d\n", fname, n); goto error_openfile; } fclose(file); } if ((initrd_end - initrd_start) != 0 ) { initrd_base = initrd_start; initrd_size = initrd_end - initrd_start; } if (reuse_initrd) { /* Add initrd address to exclude_range */ exclude_range[i].start = initrd_start; exclude_range[i].end = initrd_end; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); } /* HTAB */ memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,htab-base"); file = fopen(fname, "r"); if (!file) { closedir(cdir); if (errno == ENOENT) { /* Non LPAR */ errno = 0; continue; } perror(fname); goto error_opendir; } if (fread(&htab_base, sizeof(unsigned long), 1, file) != 1) { perror(fname); goto error_openfile; } memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,htab-size"); file = fopen(fname, "r"); if (!file) { perror(fname); goto error_opencdir; } if (fread(&htab_size, sizeof(unsigned long), 1, file) != 1) { perror(fname); goto error_openfile; } /* Add htab address to exclude_range - NON-LPAR only */ exclude_range[i].start = htab_base; exclude_range[i].end = htab_base + htab_size; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); } /* chosen */ if (strncmp(dentry->d_name, "rtas", 4) == 0) { strcat(fname, "/linux,rtas-base"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&rtas_base, sizeof(unsigned int), 1, file) != 1) { perror(fname); goto error_openfile; } memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,rtas-size"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&rtas_size, sizeof(unsigned int), 1, file) != 1) { perror(fname); goto error_openfile; } closedir(cdir); /* Add rtas to exclude_range */ exclude_range[i].start = rtas_base; exclude_range[i].end = rtas_base + rtas_size; i++; if (kexec_flags & KEXEC_ON_CRASH) add_usable_mem_rgns(rtas_base, rtas_size); } /* rtas */ if (!strncmp(dentry->d_name, "memory@", 7) || !strcmp(dentry->d_name, "memory")) { int fd; strcat(fname, "/reg"); if ((fd = open(fname, O_RDONLY)) < 0) { perror(fname); goto error_opencdir; } if (read_memory_region_limits(fd, &rmo_base, &rmo_top) != 0) goto error_openfile; if (rmo_top > 0x30000000UL) rmo_top = 0x30000000UL; close(fd); closedir(cdir); } /* memory */ if (strncmp(dentry->d_name, "pci@", 4) == 0) { strcat(fname, "/linux,tce-base"); file = fopen(fname, "r"); if (!file) { closedir(cdir); if (errno == ENOENT) { /* Non LPAR */ errno = 0; continue; } perror(fname); goto error_opendir; } if (fread(&tce_base, sizeof(unsigned long), 1, file) != 1) { perror(fname); goto error_openfile; } memset(fname, 0, sizeof(fname)); sprintf(fname, "%s%s%s", device_tree, dentry->d_name, "/linux,tce-size"); file = fopen(fname, "r"); if (!file) { perror(fname); goto error_opencdir; } if (fread(&tce_size, sizeof(unsigned int), 1, file) != 1) { perror(fname); goto error_openfile; } /* Add tce to exclude_range - NON-LPAR only */ exclude_range[i].start = tce_base; exclude_range[i].end = tce_base + tce_size; i++; if (kexec_flags & KEXEC_ON_CRASH) add_usable_mem_rgns(tce_base, tce_size); closedir(cdir); } /* pci */ } closedir(dir); nr_exclude_ranges = i; sort_ranges(); int k; for (k = 0; k < i; k++) dbgprintf("exclude_range sorted exclude_range[%d] " "start:%llx, end:%llx\n", k, exclude_range[k].start, exclude_range[k].end); return 0; error_openfile: fclose(file); error_opencdir: closedir(cdir); error_opendir: closedir(dir); return -1; } /* Setup a sorted list of memory ranges. */ static int setup_memory_ranges(unsigned long kexec_flags) { int i, j = 0; /* Get the base list of memory ranges from /proc/device-tree/memory * nodes. Build list of ranges to be excluded from valid memory */ if (get_base_ranges()) goto out; if (get_devtree_details(kexec_flags)) goto out; for (i = 0; i < nr_exclude_ranges; i++) { /* If first exclude range does not start with 0, include the * first hole of valid memory from 0 - exclude_range[0].start */ if (i == 0) { if (exclude_range[i].start != 0) { memory_range[j].start = 0; memory_range[j].end = exclude_range[i].start - 1; memory_range[j].type = RANGE_RAM; j++; } } /* i == 0 */ /* If the last exclude range does not end at memory_max, include * the last hole of valid memory from exclude_range[last].end - * memory_max */ if (i == nr_exclude_ranges - 1) { if (exclude_range[i].end < memory_max) { memory_range[j].start = exclude_range[i].end + 1; memory_range[j].end = memory_max; memory_range[j].type = RANGE_RAM; j++; /* Limit the end to rmo_top */ if (memory_range[j-1].start >= rmo_top) { j--; break; } if ((memory_range[j-1].start < rmo_top) && (memory_range[j-1].end >= rmo_top)) { memory_range[j-1].end = rmo_top; break; } continue; } } /* i == nr_exclude_ranges - 1 */ /* contiguous exclude ranges - skip */ if (exclude_range[i+1].start == exclude_range[i].end + 1) continue; memory_range[j].start = exclude_range[i].end + 1; memory_range[j].end = exclude_range[i+1].start - 1; memory_range[j].type = RANGE_RAM; j++; /* Limit range to rmo_top */ if (memory_range[j-1].start >= rmo_top) { j--; break; } if ((memory_range[j-1].start < rmo_top) && (memory_range[j-1].end >= rmo_top)) { memory_range[j-1].end = rmo_top; break; } } /* fixup in case we have no exclude regions */ if (!j) { memory_range[0].start = base_memory_range[0].start; memory_range[0].end = rmo_top; memory_range[0].type = RANGE_RAM; nr_memory_ranges = 1; } else nr_memory_ranges = j; int k; for (k = 0; k < j; k++) dbgprintf("setup_memory_ranges memory_range[%d] " "start:%llx, end:%llx\n", k, memory_range[k].start, memory_range[k].end); return 0; out: cleanup_memory_ranges(); return -1; } /* Return a list of valid memory ranges */ int get_memory_ranges_dt(struct memory_range **range, int *ranges, unsigned long kexec_flags) { if (count_memory_ranges()) return -1; if (alloc_memory_ranges()) return -1; if (setup_memory_ranges(kexec_flags)) return -1; *range = memory_range; *ranges = nr_memory_ranges; return 0; } #endif /* Return a sorted list of memory ranges. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { int res = 0; res = init_memory_region_info(); if (res != 0) return res; #ifdef WITH_GAMECUBE return get_memory_ranges_gc(range, ranges, kexec_flags); #else return get_memory_ranges_dt(range, ranges, kexec_flags); #endif } 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}, {"uImage-ppc", uImage_ppc_probe, uImage_ppc_load, uImage_ppc_usage }, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { } int arch_process_options(int argc, char **argv) { return 0; } const struct arch_map_entry arches[] = { /* For compatibility with older patches * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_PPC here. */ { "ppc", KEXEC_ARCH_DEFAULT }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } kexec-tools-2.0.10/kexec/arch/ppc/kexec-elf-ppc.c0000644001567400156740000002760512417126536020523 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "kexec-ppc.h" #include #include "../../kexec-syscall.h" #include "crashdump-powerpc.h" #include "config.h" #include "fixup_dtb.h" static const int probe_debug = 0; unsigned char reuse_initrd; const char *ramdisk; int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *, char *); #define UPSZ(X) _ALIGN_UP(sizeof(X), 4); #ifdef WITH_GAMECUBE 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, }, }; #endif int elf_ppc_probe(const char *buf, off_t len) { struct mem_ehdr ehdr; int result; result = build_elf_exec_info(buf, len, &ehdr, 0); 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; } #ifdef WITH_GAMECUBE 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 */ } } #endif /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS {"command-line", 1, 0, OPT_APPEND}, {"append", 1, 0, OPT_APPEND}, {"ramdisk", 1, 0, OPT_RAMDISK}, {"initrd", 1, 0, OPT_RAMDISK}, {"gamecube", 1, 0, OPT_GAMECUBE}, {"dtb", 1, 0, OPT_DTB}, {"reuse-node", 1, 0, OPT_NODES}, {0, 0, 0, 0}, }; static const char short_options[] = KEXEC_ARCH_OPT_STR; 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" " --ramdisk= Initial RAM disk.\n" " --initrd= same as --ramdisk\n" " --gamecube=1|0 Enable/disable support for ELFs with changed\n" " addresses suitable for the GameCube.\n" " --dtb= Specify device tree blob file.\n" " --reuse-node=node Specify nodes which should be taken from /proc/device-tree.\n" " Can be set multiple times.\n" ); } int elf_ppc_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; char *command_line, *crash_cmdline, *cmdline_buf; char *tmp_cmdline; int command_line_len, crash_cmdline_len; char *dtb; int result; char *error_msg; unsigned long max_addr, hole_addr; struct mem_phdr *phdr; size_t size; #ifdef CONFIG_PPC64 unsigned long toc_addr; #endif #ifdef WITH_GAMECUBE int target_is_gamecube = 1; char *arg_buf; size_t arg_bytes; unsigned long arg_base; struct boot_notes *notes; size_t note_bytes; unsigned char *setup_start; uint32_t setup_size; #else char *seg_buf = NULL; off_t seg_size = 0; int target_is_gamecube = 0; unsigned int addr; unsigned long dtb_addr; unsigned long dtb_addr_actual; #endif unsigned long kernel_addr; #define FIXUP_ENTRYS (20) char *fixup_nodes[FIXUP_ENTRYS + 1]; int cur_fixup = 0; int opt; char *blob_buf = NULL; off_t blob_size = 0; command_line = tmp_cmdline = NULL; dtb = NULL; max_addr = LONG_MAX; hole_addr = 0; kernel_addr = 0; ramdisk = 0; result = 0; error_msg = NULL; while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch (opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case OPT_APPEND: tmp_cmdline = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_GAMECUBE: target_is_gamecube = atoi(optarg); break; case OPT_DTB: dtb = optarg; break; case OPT_NODES: if (cur_fixup >= FIXUP_ENTRYS) { die("The number of entries for the fixup is too large\n"); } fixup_nodes[cur_fixup] = optarg; cur_fixup++; break; } } if (ramdisk && reuse_initrd) die("Can't specify --ramdisk or --initrd with --reuseinitrd\n"); command_line_len = 0; if (tmp_cmdline) { command_line = tmp_cmdline; } else { command_line = get_command_line(); } command_line_len = strlen(command_line); fixup_nodes[cur_fixup] = NULL; /* Parse the Elf file */ result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) { goto out; } #ifdef WITH_GAMECUBE if (target_is_gamecube) { gamecube_hack_addresses(&ehdr); } #endif /* Load the Elf data. Physical load addresses in elf64 header do not * show up correctly. Use user supplied address for now to patch the * elf header */ phdr = &ehdr.e_phdr[0]; size = phdr->p_filesz; if (size > phdr->p_memsz) size = phdr->p_memsz; kernel_addr = locate_hole(info, size, 0, 0, max_addr, 1); #ifdef CONFIG_PPC64 ehdr.e_phdr[0].p_paddr = (Elf64_Addr)kernel_addr; #else ehdr.e_phdr[0].p_paddr = kernel_addr; #endif /* Load the Elf data */ result = elf_exec_load(&ehdr, info); if (result < 0) { goto out; } /* * Need to append some command line parameters internally in case of * taking crash dumps. Additional segments need to be created. */ if (info->kexec_flags & KEXEC_ON_CRASH) { crash_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE); result = load_crashdump_segments(info, crash_cmdline, max_addr, 0); if (result < 0) { result = -1; goto out; } crash_cmdline_len = strlen(crash_cmdline); } else { crash_cmdline = NULL; crash_cmdline_len = 0; } /* * In case of a toy we take the hardcoded things and an easy setup via * one of the assembly startups. Every thing else should be grown up * and go through the purgatory. */ #ifdef WITH_GAMECUBE 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) + _ALIGN(command_line_len, 4); arg_bytes = note_bytes + _ALIGN(setup_size, 4); 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 + _ALIGN(setup_size, 4)); 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; #else if (crash_cmdline_len + command_line_len + 1 > COMMAND_LINE_SIZE) { printf("Kernel command line exceeds size\n"); return -1; } cmdline_buf = xmalloc(COMMAND_LINE_SIZE); memset((void *)cmdline_buf, 0, COMMAND_LINE_SIZE); if (command_line) strncat(cmdline_buf, command_line, command_line_len); if (crash_cmdline) strncat(cmdline_buf, crash_cmdline, sizeof(crash_cmdline) - strlen(crash_cmdline) - 1); elf_rel_build_load(info, &info->rhdr, (const char *)purgatory, purgatory_size, 0, elf_max_addr(&ehdr), 1, 0); /* Here we need to initialize the device tree, and find out where * it is going to live so we can place it directly after the * kernel image */ if (dtb) { /* Grab device tree from buffer */ blob_buf = slurp_file(dtb, &blob_size); } else { create_flatten_tree(info, (unsigned char **)&blob_buf, (unsigned long *)&blob_size, cmdline_buf); } if (!blob_buf || !blob_size) { error_msg = "Device tree seems to be an empty file.\n"; goto out2; } /* initial fixup for device tree */ blob_buf = fixup_dtb_init(info, blob_buf, &blob_size, kernel_addr, &dtb_addr); if (ramdisk) { seg_buf = slurp_ramdisk_ppc(ramdisk, &seg_size); /* load the ramdisk *above* the device tree */ hole_addr = add_buffer(info, seg_buf, seg_size, seg_size, 0, dtb_addr + blob_size + 1, max_addr, -1); ramdisk_base = hole_addr; ramdisk_size = seg_size; } if (reuse_initrd) { ramdisk_base = initrd_base; ramdisk_size = initrd_size; } if (info->kexec_flags & KEXEC_ON_CRASH && ramdisk_base != 0) { if ( (ramdisk_base < crash_base) || (ramdisk_base > crash_base + crash_size) ) { printf("WARNING: ramdisk is above crashkernel region!\n"); } else if (ramdisk_base + ramdisk_size > crash_base + crash_size) { printf("WARNING: ramdisk overflows crashkernel region!\n"); } } /* Perform final fixup on devie tree, i.e. everything beside what * was done above */ fixup_dtb_finalize(info, blob_buf, &blob_size, fixup_nodes, cmdline_buf); dtb_addr_actual = add_buffer(info, blob_buf, blob_size, blob_size, 0, dtb_addr, kernel_addr + KERNEL_ACCESS_TOP, 1); if (dtb_addr_actual != dtb_addr) { error_msg = "Error device tree not loadded to address it was expecting to be loaded too!\n"; goto out2; } /* * set various variables for the purgatory. * ehdr.e_entry is a virtual address. we know physical start * address of the kernel (kernel_addr). Find the offset of * e_entry from the virtual start address(e_phdr[0].p_vaddr) * and calculate the actual physical address of the 'kernel entry'. */ addr = kernel_addr + (ehdr.e_entry - ehdr.e_phdr[0].p_vaddr); elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr)); addr = dtb_addr; elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr)); #define PUL_STACK_SIZE (16 * 1024) addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, elf_max_addr(&ehdr), 1); addr += PUL_STACK_SIZE; elf_rel_set_symbol(&info->rhdr, "stack", &addr, sizeof(addr)); #undef PUL_STACK_SIZE /* * Fixup ThreadPointer(r2) for purgatory. * PPC32 ELF ABI expects : * ThreadPointer (TP) = TCB + 0x7000 * We manually allocate a TCB space and set the TP * accordingly. */ #define TCB_SIZE 1024 #define TCB_TP_OFFSET 0x7000 /* PPC32 ELF ABI */ addr = locate_hole(info, TCB_SIZE, 0, 0, ((unsigned long)elf_max_addr(&ehdr) - TCB_TP_OFFSET), 1); addr += TCB_SIZE + TCB_TP_OFFSET; elf_rel_set_symbol(&info->rhdr, "my_thread_ptr", &addr, sizeof(addr)); #undef TCB_SIZE #undef TCB_TP_OFFSET addr = elf_rel_get_addr(&info->rhdr, "purgatory_start"); info->entry = (void *)addr; out2: free(cmdline_buf); #endif out: free_elf_info(&ehdr); free(crash_cmdline); if (!tmp_cmdline) free(command_line); if (error_msg) die(error_msg); return result; } kexec-tools-2.0.10/kexec/arch/ppc/kexec-elf-rel-ppc.c0000644001567400156740000000267111642166046021276 0ustar hormshorms#include #include #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 *UNUSED(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_HI: *(uint16_t *)location = (value>>16) & 0xffff; 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; } kexec-tools-2.0.10/kexec/arch/ppc/kexec-dol-ppc.c0000644001567400156740000003012212417126536020517 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "kexec-ppc.h" #include 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) _ALIGN(addr, PAGE_SIZE) #define MAX_COMMAND_LINE 256 #define UPSZ(X) _ALIGN_UP(sizeof(X), 4) 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 ((uintmax_t)(dol_sect_offset(h, i) + dol_sect_size(h, i)) > (uintmax_t)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 (" --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 UNUSED(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; /* See options.h -- add any more there, too. */ 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; /* * Parse the command line arguments */ 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 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) + _ALIGN(command_line_len, 4); arg_bytes = note_bytes + _ALIGN(setup_dol_size, 4); 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 + _ALIGN(setup_dol_size, 4)); 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; } kexec-tools-2.0.10/kexec/arch/ppc/kexec-uImage-ppc.c0000644001567400156740000002102112417126536021146 0ustar hormshorms/* * uImage support for PowerPC */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-ppc.h" #include "fixup_dtb.h" #include #include "crashdump-powerpc.h" #include int create_flatten_tree(struct kexec_info *, unsigned char **, unsigned long *, char *); /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS {"command-line", 1, 0, OPT_APPEND}, {"append", 1, 0, OPT_APPEND}, {"ramdisk", 1, 0, OPT_RAMDISK}, {"initrd", 1, 0, OPT_RAMDISK}, {"dtb", 1, 0, OPT_DTB}, {"reuse-node", 1, 0, OPT_NODES}, {0, 0, 0, 0}, }; static const char short_options[] = KEXEC_ARCH_OPT_STR; void uImage_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" " --ramdisk= Initial RAM disk.\n" " --initrd= same as --ramdisk\n" " --dtb= Specify device tree blob file.\n" " --reuse-node=node Specify nodes which should be taken from /proc/device-tree.\n" " Can be set multiple times.\n" ); } /* * Load the ramdisk into buffer. * If the supplied image is in uImage format use * uImage_load() to read the payload from the image. */ char *slurp_ramdisk_ppc(const char *filename, off_t *r_size) { struct Image_info img; off_t size; const unsigned char *buf = slurp_file(filename, &size); int rc; /* Check if this is a uImage RAMDisk */ if (!buf) return buf; rc = uImage_probe_ramdisk(buf, size, IH_ARCH_PPC); if (rc < 0) die("uImage: Corrupted ramdisk file %s\n", filename); else if (rc == 0) { if (uImage_load(buf, size, &img) != 0) die("uImage: Reading %ld bytes from %s failed\n", size, filename); buf = img.buf; size = img.len; } *r_size = size; return buf; } int uImage_ppc_probe(const char *buf, off_t len) { return uImage_probe_kernel(buf, len, IH_ARCH_PPC); } static int ppc_load_bare_bits(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info, unsigned int load_addr, unsigned int ep) { char *command_line, *cmdline_buf, *crash_cmdline; char *tmp_cmdline; int command_line_len, crash_cmdline_len; char *dtb; unsigned int addr; unsigned long dtb_addr; unsigned long dtb_addr_actual; #define FIXUP_ENTRYS (20) char *fixup_nodes[FIXUP_ENTRYS + 1]; int cur_fixup = 0; int opt; int ret = 0; char *seg_buf = NULL; off_t seg_size = 0; unsigned long long hole_addr; unsigned long max_addr; char *blob_buf = NULL; off_t blob_size = 0; char *error_msg = NULL; cmdline_buf = NULL; command_line = NULL; tmp_cmdline = NULL; dtb = NULL; max_addr = LONG_MAX; while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch (opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) { break; } case OPT_APPEND: tmp_cmdline = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DTB: dtb = optarg; break; case OPT_NODES: if (cur_fixup >= FIXUP_ENTRYS) { die("The number of entries for the fixup is too large\n"); } fixup_nodes[cur_fixup] = optarg; cur_fixup++; break; } } if (ramdisk && reuse_initrd) die("Can't specify --ramdisk or --initrd with --reuseinitrd\n"); command_line_len = 0; if (tmp_cmdline) { command_line = tmp_cmdline; } else { command_line = get_command_line(); } command_line_len = strlen(command_line) + 1; fixup_nodes[cur_fixup] = NULL; /* * len contains the length of the whole kernel image except the bss * section. The 1 MiB should cover it. The purgatory and the dtb are * allocated from memtop down towards zero so we should never get too * close to the bss :) */ #define _1MiB (1 * 1024 * 1024) /* * If the provided load_addr cannot be allocated, find a new * area. Rebase the entry point based on the new load_addr. */ if (!valid_memory_range(info, load_addr, load_addr + (len + _1MiB))) { int ep_offset = ep - load_addr; load_addr = locate_hole(info, len + _1MiB, 0, 0, max_addr, 1); if (load_addr == ULONG_MAX) { printf("Can't allocate memory for kernel of len %ld\n", len + _1MiB); return -1; } ep = load_addr + ep_offset; } add_segment(info, buf, len, load_addr, len + _1MiB); if (info->kexec_flags & KEXEC_ON_CRASH) { crash_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)crash_cmdline, 0, COMMAND_LINE_SIZE); ret = load_crashdump_segments(info, crash_cmdline, max_addr, 0); if (ret < 0) { ret = -1; goto out; } crash_cmdline_len = strlen(crash_cmdline); } else { crash_cmdline = NULL; crash_cmdline_len = 0; } if (crash_cmdline_len + command_line_len + 1 > COMMAND_LINE_SIZE) { printf("Kernel command line exceeds maximum possible length\n"); return -1; } cmdline_buf = xmalloc(COMMAND_LINE_SIZE); memset((void *)cmdline_buf, 0, COMMAND_LINE_SIZE); if (command_line) strcpy(cmdline_buf, command_line); if (crash_cmdline) strncat(cmdline_buf, crash_cmdline, crash_cmdline_len); elf_rel_build_load(info, &info->rhdr, (const char *)purgatory, purgatory_size, 0, -1, -1, 0); /* Here we need to initialize the device tree, and find out where * it is going to live so we can place it directly after the * kernel image */ if (dtb) { /* Grab device tree from buffer */ blob_buf = slurp_file(dtb, &blob_size); } else { create_flatten_tree(info, (unsigned char **)&blob_buf, (unsigned long *)&blob_size, cmdline_buf); } if (!blob_buf || !blob_size) { error_msg = "Device tree seems to be an empty file.\n"; goto out2; } /* initial fixup for device tree */ blob_buf = fixup_dtb_init(info, blob_buf, &blob_size, load_addr, &dtb_addr); if (ramdisk) { seg_buf = slurp_ramdisk_ppc(ramdisk, &seg_size); /* Load ramdisk at top of memory */ hole_addr = add_buffer(info, seg_buf, seg_size, seg_size, 0, dtb_addr + blob_size, max_addr, -1); ramdisk_base = hole_addr; ramdisk_size = seg_size; } if (reuse_initrd) { ramdisk_base = initrd_base; ramdisk_size = initrd_size; } if (info->kexec_flags & KEXEC_ON_CRASH && ramdisk_base != 0) { if ( (ramdisk_base < crash_base) || (ramdisk_base > crash_base + crash_size) ) { printf("WARNING: ramdisk is above crashkernel region!\n"); } else if (ramdisk_base + ramdisk_size > crash_base + crash_size) { printf("WARNING: ramdisk overflows crashkernel region!\n"); } } /* Perform final fixup on devie tree, i.e. everything beside what * was done above */ fixup_dtb_finalize(info, blob_buf, &blob_size, fixup_nodes, cmdline_buf); dtb_addr_actual = add_buffer(info, blob_buf, blob_size, blob_size, 0, dtb_addr, load_addr + KERNEL_ACCESS_TOP, 1); if (dtb_addr_actual != dtb_addr) { printf("dtb_addr_actual: %lx, dtb_addr: %lx\n", dtb_addr_actual, dtb_addr); error_msg = "Error device tree not loadded to address it was expecting to be loaded too!\n"; goto out2; } /* set various variables for the purgatory */ addr = ep; elf_rel_set_symbol(&info->rhdr, "kernel", &addr, sizeof(addr)); addr = dtb_addr; elf_rel_set_symbol(&info->rhdr, "dt_offset", &addr, sizeof(addr)); #define PUL_STACK_SIZE (16 * 1024) addr = locate_hole(info, PUL_STACK_SIZE, 0, 0, -1, 1); addr += PUL_STACK_SIZE; elf_rel_set_symbol(&info->rhdr, "stack", &addr, sizeof(addr)); /* No allocation past here in order not to overwrite the stack */ #undef PUL_STACK_SIZE /* * Fixup ThreadPointer(r2) for purgatory. * PPC32 ELF ABI expects : * ThreadPointer (TP) = TCB + 0x7000 * We manually allocate a TCB space and set the TP * accordingly. */ #define TCB_SIZE 1024 #define TCB_TP_OFFSET 0x7000 /* PPC32 ELF ABI */ addr = locate_hole(info, TCB_SIZE, 0, 0, ((unsigned long)-1 - TCB_TP_OFFSET), 1); addr += TCB_SIZE + TCB_TP_OFFSET; elf_rel_set_symbol(&info->rhdr, "my_thread_ptr", &addr, sizeof(addr)); #undef TCB_TP_OFFSET #undef TCB_SIZE addr = elf_rel_get_addr(&info->rhdr, "purgatory_start"); info->entry = (void *)addr; out2: free(cmdline_buf); out: free(crash_cmdline); if (!tmp_cmdline) free(command_line); if (error_msg) die(error_msg); return ret; } int uImage_ppc_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct Image_info img; int ret; ret = uImage_load(buf, len, &img); if (ret) return ret; return ppc_load_bare_bits(argc, argv, img.buf, img.len, info, img.base, img.ep); } kexec-tools-2.0.10/kexec/arch/ppc/ppc-setup-simple.S0000644001567400156740000000136311424244110021242 0ustar hormshorms/* * 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 kexec-tools-2.0.10/kexec/arch/ppc/ppc-setup-dol.S0000644001567400156740000000722411424244110020531 0ustar hormshorms/* * 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 kexec-tools-2.0.10/kexec/arch/ppc/fixup_dtb.c0000644001567400156740000002417712417126536020065 0ustar hormshorms#define _GNU_SOURCE #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include #include "ops.h" #include "page.h" #include "fixup_dtb.h" #include "kexec-ppc.h" const char proc_dts[] = "/proc/device-tree"; static void print_fdt_reserve_regions(char *blob_buf) { int i, num; if (!kexec_debug) return; /* Print out a summary of the final reserve regions */ num = fdt_num_mem_rsv(blob_buf); dbgprintf ("reserve regions: %d\n", num); for (i = 0; i < num; i++) { uint64_t offset, size; if (fdt_get_mem_rsv(blob_buf, i, &offset, &size) == 0) { dbgprintf("%d: offset: %llx, size: %llx\n", i, offset, size); } else { dbgprintf("Error retreiving reserved region\n"); } } } static void fixup_nodes(char *nodes[]) { int index = 0; char *fname; char *prop_name; char *node_name; void *node; int len; char *content; off_t content_size; int ret; while (nodes[index]) { len = asprintf(&fname, "%s%s", proc_dts, nodes[index]); if (len < 0) die("asprintf() failed\n"); content = slurp_file(fname, &content_size); if (!content) { die("Can't open %s: %s\n", fname, strerror(errno)); } prop_name = fname + len; while (*prop_name != '/') prop_name--; *prop_name = '\0'; prop_name++; node_name = fname + sizeof(proc_dts) - 1; node = finddevice(node_name); if (!node) node = create_node(NULL, node_name + 1); ret = setprop(node, prop_name, content, content_size); if (ret < 0) die("setprop of %s/%s size: %ld failed: %s\n", node_name, prop_name, content_size, fdt_strerror(ret)); free(content); free(fname); index++; }; } /* * command line priority: * - use the supplied command line * - if none available use the command line from .dtb * - if not available use the current command line */ static void fixup_cmdline(const char *cmdline) { void *chosen; char *fixup_cmd_node[] = { "/chosen/bootargs", NULL, }; chosen = finddevice("/chosen"); if (!cmdline) { if (!chosen) fixup_nodes(fixup_cmd_node); } else { if (!chosen) chosen = create_node(NULL, "chosen"); setprop_str(chosen, "bootargs", cmdline); } return; } #define EXPAND_GRANULARITY 1024 static char *expand_buf(int minexpand, char *blob_buf, off_t *blob_size) { int size = fdt_totalsize(blob_buf); int rc; size = _ALIGN(size + minexpand, EXPAND_GRANULARITY); blob_buf = realloc(blob_buf, size); if (!blob_buf) die("Couldn't find %d bytes to expand device tree\n\r", size); rc = fdt_open_into(blob_buf, blob_buf, size); if (rc != 0) die("Couldn't expand fdt into new buffer: %s\n\r", fdt_strerror(rc)); *blob_size = fdt_totalsize(blob_buf); return blob_buf; } static void fixup_reserve_regions(struct kexec_info *info, char *blob_buf) { int ret, i; int nodeoffset; u64 val = 0; /* If this is a KEXEC kernel we add all regions since they will * all need to be saved */ if (info->kexec_flags & KEXEC_ON_CRASH) { for (i = 0; i < info->nr_segments; i++) { uint64_t address = (unsigned long)info->segment[i].mem; uint64_t size = info->segment[i].memsz; while ((i+1) < info->nr_segments && (address + size == (unsigned long)info->segment[i+1].mem)) { size += info->segment[++i].memsz; } ret = fdt_add_mem_rsv(blob_buf, address, size); if (ret) { printf("%s: Error adding memory range to memreserve!\n", fdt_strerror(ret)); goto out; } } } else if (ramdisk || reuse_initrd) { /* Otherwise we just add back the ramdisk and the device tree * is already in the list */ ret = fdt_add_mem_rsv(blob_buf, ramdisk_base, ramdisk_size); if (ret) { printf("%s: Unable to add new reserved memory for initrd flat device tree\n", fdt_strerror(ret)); goto out; } } #if 0 /* XXX: Do not reserve spin-table for CPUs. */ /* Add reserve regions for cpu-release-addr */ nodeoffset = fdt_node_offset_by_prop_value(blob_buf, -1, "device_type", "cpu", 4); while (nodeoffset != -FDT_ERR_NOTFOUND) { const void *buf; int sz, ret; u64 tmp; buf = fdt_getprop(blob_buf, nodeoffset, "cpu-release-addr", &sz); if (buf) { if (sz == 4) { tmp = *(u32 *)buf; } else if (sz == 8) { tmp = *(u64 *)buf; } /* crude check to see if last value is repeated */ if (_ALIGN_DOWN(tmp, PAGE_SIZE) != _ALIGN_DOWN(val, PAGE_SIZE)) { val = tmp; ret = fdt_add_mem_rsv(blob_buf, _ALIGN_DOWN(val, PAGE_SIZE), PAGE_SIZE); if (ret) printf("%s: Unable to add reserve for cpu-release-addr!\n", fdt_strerror(ret)); } } nodeoffset = fdt_node_offset_by_prop_value(blob_buf, nodeoffset, "device_type", "cpu", 4); } #endif out: print_fdt_reserve_regions(blob_buf); } static void fixup_memory(struct kexec_info *info, char *blob_buf) { if (info->kexec_flags & KEXEC_ON_CRASH) { int nodeoffset, len = 0; u8 tmp[16]; const unsigned long *addrcell, *sizecell; nodeoffset = fdt_path_offset(blob_buf, "/memory"); if (nodeoffset < 0) { printf("Error searching for memory node!\n"); return; } addrcell = fdt_getprop(blob_buf, 0, "#address-cells", NULL); /* use shifts and mask to ensure endianness */ if ((addrcell) && (*addrcell == 2)) { tmp[0] = (crash_base >> 56) & 0xff; tmp[1] = (crash_base >> 48) & 0xff; tmp[2] = (crash_base >> 40) & 0xff; tmp[3] = (crash_base >> 32) & 0xff; tmp[4] = (crash_base >> 24) & 0xff; tmp[5] = (crash_base >> 16) & 0xff; tmp[6] = (crash_base >> 8) & 0xff; tmp[7] = (crash_base ) & 0xff; len = 8; } else { tmp[0] = (crash_base >> 24) & 0xff; tmp[1] = (crash_base >> 16) & 0xff; tmp[2] = (crash_base >> 8) & 0xff; tmp[3] = (crash_base ) & 0xff; len = 4; } sizecell = fdt_getprop(blob_buf, 0, "#size-cells", NULL); /* use shifts and mask to ensure endianness */ if ((sizecell) && (*sizecell == 2)) { tmp[0+len] = (crash_size >> 56) & 0xff; tmp[1+len] = (crash_size >> 48) & 0xff; tmp[2+len] = (crash_size >> 40) & 0xff; tmp[3+len] = (crash_size >> 32) & 0xff; tmp[4+len] = (crash_size >> 24) & 0xff; tmp[5+len] = (crash_size >> 16) & 0xff; tmp[6+len] = (crash_size >> 8) & 0xff; tmp[7+len] = (crash_size ) & 0xff; len += 8; } else { tmp[0+len] = (crash_size >> 24) & 0xff; tmp[1+len] = (crash_size >> 16) & 0xff; tmp[2+len] = (crash_size >> 8) & 0xff; tmp[3+len] = (crash_size ) & 0xff; len += 4; } if (fdt_setprop(blob_buf, nodeoffset, "reg", tmp, len) != 0) { printf ("Error setting memory node!\n"); } fdt_delprop(blob_buf, nodeoffset, "linux,usable-memory"); } } /* removes crashkernel nodes if they exist and we are *rebooting* * into a crashkernel. These nodes should not exist after we * crash and reboot into a new kernel */ static void fixup_crashkernel(struct kexec_info *info, char *blob_buf) { int nodeoffset; nodeoffset = fdt_path_offset(blob_buf, "/chosen"); if (info->kexec_flags & KEXEC_ON_CRASH) { if (nodeoffset < 0) { printf("fdt_crashkernel: %s\n", fdt_strerror(nodeoffset)); return; } fdt_delprop(blob_buf, nodeoffset, "linux,crashkernel-base"); fdt_delprop(blob_buf, nodeoffset, "linux,crashkernel-size"); } } /* remove the old chosen nodes if they exist and add correct chosen * nodes if we have an initd */ static void fixup_initrd(char *blob_buf) { int err, nodeoffset; unsigned long tmp; nodeoffset = fdt_path_offset(blob_buf, "/chosen"); if (nodeoffset < 0) { printf("fdt_initrd: %s\n", fdt_strerror(nodeoffset)); return; } fdt_delprop(blob_buf, nodeoffset, "linux,initrd-start"); fdt_delprop(blob_buf, nodeoffset, "linux,initrd-end"); if ((reuse_initrd || ramdisk) && ((ramdisk_base != 0) && (ramdisk_size != 0))) { tmp = ramdisk_base; err = fdt_setprop(blob_buf, nodeoffset, "linux,initrd-start", &tmp, sizeof(tmp)); if (err < 0) { printf("WARNING: " "could not set linux,initrd-start %s.\n", fdt_strerror(err)); return; } tmp = ramdisk_base + ramdisk_size; err = fdt_setprop(blob_buf, nodeoffset, "linux,initrd-end", &tmp, sizeof(tmp)); if (err < 0) { printf("WARNING: could not set linux,initrd-end %s.\n", fdt_strerror(err)); return; } } } char *fixup_dtb_init(struct kexec_info *info, char *blob_buf, off_t *blob_size, unsigned long hole_addr, unsigned long *dtb_addr) { int ret, i, num = fdt_num_mem_rsv(blob_buf); fdt_init(blob_buf); /* Remove the existing reserve regions as they will no longer * be valid after we reboot */ for (i = num - 1; i >= 0; i--) { ret = fdt_del_mem_rsv(blob_buf, i); if (ret) { printf("%s: Error deleting memory reserve region %d from device tree!\n", fdt_strerror(ret), i); } } /* Pack the FDT first, so we don't grow excessively if there is already free space */ ret = fdt_pack(blob_buf); if (ret) printf("%s: Unable to pack flat device tree\n", fdt_strerror(ret)); /* info->nr_segments just a guide, will grow by at least EXPAND_GRANULARITY */ blob_buf = expand_buf(info->nr_segments * sizeof(struct fdt_reserve_entry), blob_buf, blob_size); /* add reserve region for *THIS* fdt */ *dtb_addr = locate_hole(info, *blob_size, 0, hole_addr, hole_addr+KERNEL_ACCESS_TOP, -1); ret = fdt_add_mem_rsv(blob_buf, *dtb_addr, PAGE_ALIGN(*blob_size)); if (ret) { printf("%s: Unable to add new reserved memory for the flat device tree\n", fdt_strerror(ret)); } return blob_buf; } static void save_fixed_up_dtb(char *blob_buf, off_t blob_size) { FILE *fp; if (!kexec_debug) return; fp = fopen("debug.dtb", "w"); if (fp) { if ( blob_size == fwrite(blob_buf, sizeof(char), blob_size, fp)) { dbgprintf("debug.dtb written\n"); } else { dbgprintf("Unable to write debug.dtb\n"); } } else { dbgprintf("Unable to dump flat device tree to debug.dtb\n"); } } char *fixup_dtb_finalize(struct kexec_info *info, char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline) { fixup_nodes(nodes); fixup_cmdline(cmdline); fixup_reserve_regions(info, blob_buf); fixup_memory(info, blob_buf); fixup_initrd(blob_buf); fixup_crashkernel(info, blob_buf); blob_buf = (char *)dt_ops.finalize(); *blob_size = fdt_totalsize(blob_buf); save_fixed_up_dtb(blob_buf, *blob_size); return blob_buf; } kexec-tools-2.0.10/kexec/arch/ppc/fs2dt.c0000644001567400156740000002710512417126536017115 0ustar hormshorms/* * fs2dt: creates a flattened device-tree * * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation * Copyright (C) 2005 R Sharada (sharada@in.ibm.com), IBM 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 (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 #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "kexec-ppc.h" #define MAXPATH 1024 /* max path name length */ #define NAMESPACE 16384 /* max bytes for property names */ #define TREEWORDS 65536 /* max 32 bit words for properties */ #define MEMRESERVE 256 /* max number of reserved memory blks */ #define MAX_MEMORY_RANGES 1024 #define COMMAND_LINE_SIZE 512 /* from kernel */ static char pathname[MAXPATH]; static char propnames[NAMESPACE] = { 0 }; static unsigned dtstruct[TREEWORDS], *dt; static unsigned long long mem_rsrv[2*MEMRESERVE] = { 0, 0 }; static int crash_param; static char local_cmdline[COMMAND_LINE_SIZE] = { "" }; static unsigned *dt_len; /* changed len of modified cmdline in flat device-tree */ static struct bootblock bb[1]; void reserve(unsigned long long where, unsigned long long length) { size_t offset; for (offset = 0; mem_rsrv[offset + 1]; offset += 2) ; if (offset + 4 >= 2 * MEMRESERVE) die("unrecoverable error: exhasuted reservation meta data\n"); mem_rsrv[offset] = where; mem_rsrv[offset + 1] = length; mem_rsrv[offset + 3] = 0; /* N.B: don't care about offset + 2 */ } /* look for properties we need to reserve memory space for */ static void checkprop(char *name, unsigned *data, int len) { static unsigned long long base, size, end; if ((data == NULL) && (base || size || end)) die("unrecoverable error: no property data"); else if (!strcmp(name, "linux,rtas-base")) base = *data; else if (!strcmp(name, "linux,tce-base")) base = *(unsigned long long *) data; else if (!strcmp(name, "rtas-size") || !strcmp(name, "linux,tce-size")) size = *data; else if (reuse_initrd && !strcmp(name, "linux,initrd-start")) if (len == 8) base = *(unsigned long long *) data; else base = *data; else if (reuse_initrd && !strcmp(name, "linux,initrd-end")) end = *(unsigned long long *) data; if (size && end) die("unrecoverable error: size and end set at same time\n"); if (base && size) { reserve(base, size); base = 0; size = 0; } if (base && end) { reserve(base, end-base); base = 0; end = 0; } } /* * return the property index for a property name, creating a new one * if needed. */ static unsigned propnum(const char *name) { unsigned offset = 0; while (propnames[offset]) if (strcmp(name, propnames+offset)) offset += strlen(propnames+offset)+1; else return offset; if (NAMESPACE - offset < strlen(name) + 1) die("unrecoverable error: propnames overrun\n"); strcpy(propnames+offset, name); return offset; } static void add_usable_mem_property(int fd, int len) { char fname[MAXPATH], *bname; unsigned long buf[2]; unsigned long ranges[2*MAX_MEMORY_RANGES]; unsigned long long base, end, loc_base, loc_end; int range, rlen = 0; strcpy(fname, pathname); bname = strrchr(fname, '/'); bname[0] = '\0'; bname = strrchr(fname, '/'); if (strncmp(bname, "/memory@", 8) && strcmp(bname, "/memory")) return; if (lseek(fd, 0, SEEK_SET) < 0) die("unrecoverable error: error seeking in \"%s\": %s\n", pathname, strerror(errno)); if (read_memory_region_limits(fd, &base, &end) != 0) die("unrecoverable error: error parsing memory/reg limits\n"); for (range = 0; range < usablemem_rgns.size; range++) { loc_base = usablemem_rgns.ranges[range].start; loc_end = usablemem_rgns.ranges[range].end; if (loc_base >= base && loc_end <= end) { ranges[rlen++] = loc_base; ranges[rlen++] = loc_end - loc_base; } else if (base < loc_end && end > loc_base) { if (loc_base < base) loc_base = base; if (loc_end > end) loc_end = end; ranges[rlen++] = loc_base; ranges[rlen++] = loc_end - loc_base; } } if (!rlen) { /* * User did not pass any ranges for thsi region. Hence, write * (0,0) duple in linux,usable-memory property such that * this region will be ignored. */ ranges[rlen++] = 0; ranges[rlen++] = 0; } rlen = rlen * sizeof(unsigned long); /* * No add linux,usable-memory property. */ *dt++ = 3; *dt++ = rlen; *dt++ = propnum("linux,usable-memory"); memcpy(dt, &ranges, rlen); dt += (rlen + 3)/4; } /* put all properties (files) in the property structure */ static void putprops(char *fn, struct dirent **nlist, int numlist) { struct dirent *dp; int i = 0, fd, len; struct stat statbuf; for (i = 0; i < numlist; i++) { dp = nlist[i]; strcpy(fn, dp->d_name); if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; if (lstat(pathname, &statbuf)) die("unrecoverable error: could not stat \"%s\": %s\n", pathname, strerror(errno)); if (!crash_param && !strcmp(fn, "linux,crashkernel-base")) continue; if (!crash_param && !strcmp(fn, "linux,crashkernel-size")) continue; /* * This property will be created for each node during kexec * boot. So, ignore it. */ if (!strcmp(dp->d_name, "linux,pci-domain") || !strcmp(dp->d_name, "linux,htab-base") || !strcmp(dp->d_name, "linux,htab-size") || !strcmp(dp->d_name, "linux,kernel-end") || !strcmp(dp->d_name, "linux,usable-memory")) continue; /* This property will be created/modified later in putnode() * So ignore it, unless we are reusing the initrd. */ if ((!strcmp(dp->d_name, "linux,initrd-start") || !strcmp(dp->d_name, "linux,initrd-end")) && !reuse_initrd) continue; if (!S_ISREG(statbuf.st_mode)) continue; len = statbuf.st_size; *dt++ = 3; dt_len = dt; *dt++ = len; *dt++ = propnum(fn); fd = open(pathname, O_RDONLY); if (fd == -1) die("unrecoverable error: could not open \"%s\": %s\n", pathname, strerror(errno)); if (read(fd, dt, len) != len) die("unrecoverable error: could not read \"%s\": %s\n", pathname, strerror(errno)); checkprop(fn, dt, len); /* Get the cmdline from the device-tree and modify it */ if (!strcmp(dp->d_name, "bootargs")) { int cmd_len; char temp_cmdline[COMMAND_LINE_SIZE] = { "" }; char *param = NULL; cmd_len = strlen(local_cmdline); if (cmd_len != 0) { param = strstr(local_cmdline, "crashkernel="); if (param) crash_param = 1; param = strstr(local_cmdline, "root="); } if (!param) { char *old_param; memcpy(temp_cmdline, dt, len); param = strstr(temp_cmdline, "root="); if (param) { old_param = strtok(param, " "); if (cmd_len != 0) strcat(local_cmdline, " "); strcat(local_cmdline, old_param); } } strcat(local_cmdline, " "); cmd_len = strlen(local_cmdline); cmd_len = cmd_len + 1; memcpy(dt, local_cmdline, cmd_len); len = cmd_len; *dt_len = cmd_len; dbgprintf("Modified cmdline:%s\n", local_cmdline); } dt += (len + 3)/4; if (!strcmp(dp->d_name, "reg") && usablemem_rgns.size) add_usable_mem_property(fd, len); close(fd); } fn[0] = '\0'; checkprop(pathname, NULL, 0); } /* * Compare function used to sort the device-tree directories * This function will be passed to scandir. */ static int comparefunc(const void *dentry1, const void *dentry2) { char *str1 = (*(struct dirent **)dentry1)->d_name; char *str2 = (*(struct dirent **)dentry2)->d_name; /* * strcmp scans from left to right and fails to idetify for some * strings such as memory@10000000 and memory@f000000. * Therefore, we get the wrong sorted order like memory@10000000 and * memory@f000000. */ if (strchr(str1, '@') && strchr(str2, '@') && (strlen(str1) > strlen(str2))) return 1; return strcmp(str1, str2); } /* * put a node (directory) in the property structure. first properties * then children. */ static void putnode(void) { char *dn; struct dirent *dp; char *basename; struct dirent **namelist; int numlist, i; struct stat statbuf; numlist = scandir(pathname, &namelist, 0, comparefunc); if (numlist < 0) die("unrecoverable error: could not scan \"%s\": %s\n", pathname, strerror(errno)); if (numlist == 0) die("unrecoverable error: no directory entries in \"%s\"", pathname); basename = strrchr(pathname, '/') + 1; *dt++ = 1; strcpy((void *)dt, *basename ? basename : ""); dt += strlen((void *)dt) / sizeof(unsigned) + 1; strcat(pathname, "/"); dn = pathname + strlen(pathname); putprops(dn, namelist, numlist); /* * Add initrd entries to the second kernel * if * a) a ramdisk is specified in cmdline * OR * b) reuseinitrd is specified and a initrd is * used by the kernel. * */ if ((ramdisk || (initrd_base && reuse_initrd)) && !strcmp(basename, "chosen/")) { int len = 8; unsigned long long initrd_end; *dt++ = 3; *dt++ = len; *dt++ = propnum("linux,initrd-start"); memcpy(dt, &initrd_base, len); dt += (len + 3)/4; len = 8; *dt++ = 3; *dt++ = len; *dt++ = propnum("linux,initrd-end"); initrd_end = initrd_base + initrd_size; memcpy(dt, &initrd_end, len); dt += (len + 3)/4; /* reserve the existing initrd image in case of reuse_initrd */ if (initrd_base && initrd_size && reuse_initrd) reserve(initrd_base, initrd_size); } for (i = 0; i < numlist; i++) { dp = namelist[i]; strcpy(dn, dp->d_name); free(namelist[i]); if (!strcmp(dn, ".") || !strcmp(dn, "..")) continue; if (lstat(pathname, &statbuf)) die("unrecoverable error: could not stat \"%s\": %s\n", pathname, strerror(errno)); if (S_ISDIR(statbuf.st_mode)) putnode(); } *dt++ = 2; dn[-1] = '\0'; free(namelist); } int create_flatten_tree(struct kexec_info *info, unsigned char **bufp, unsigned long *sizep, char *cmdline) { unsigned long len; unsigned long tlen; unsigned char *buf; unsigned long me; me = 0; strcpy(pathname, "/proc/device-tree/"); dt = dtstruct; if (cmdline) strcpy(local_cmdline, cmdline); putnode(); *dt++ = 9; len = _ALIGN(sizeof(bb[0]), 8); bb->off_mem_rsvmap = len; for (len = 1; mem_rsrv[len]; len += 2) ; len += 3; len *= sizeof(mem_rsrv[0]); bb->off_dt_struct = bb->off_mem_rsvmap + len; len = dt - dtstruct; len *= sizeof(unsigned); bb->dt_struct_size = len; bb->off_dt_strings = bb->off_dt_struct + len; len = propnum(""); bb->dt_strings_size = len; len = _ALIGN(len, 4); bb->totalsize = bb->off_dt_strings + len; bb->magic = 0xd00dfeed; bb->version = 17; bb->last_comp_version = 16; reserve(me, bb->totalsize); /* patched later in kexec_load */ buf = (unsigned char *) malloc(bb->totalsize); *bufp = buf; memcpy(buf, bb, bb->off_mem_rsvmap); tlen = bb->off_mem_rsvmap; memcpy(buf+tlen, mem_rsrv, bb->off_dt_struct - bb->off_mem_rsvmap); tlen = tlen + (bb->off_dt_struct - bb->off_mem_rsvmap); memcpy(buf+tlen, dtstruct, bb->off_dt_strings - bb->off_dt_struct); tlen = tlen + (bb->off_dt_strings - bb->off_dt_struct); memcpy(buf+tlen, propnames, bb->totalsize - bb->off_dt_strings); tlen = tlen + bb->totalsize - bb->off_dt_strings; *sizep = tlen; return 0; } kexec-tools-2.0.10/kexec/arch/ppc/crashdump-powerpc.c0000644001567400156740000002472712417126536021545 0ustar hormshorms#include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "../../crashdump.h" #include "kexec-ppc.h" #include "crashdump-powerpc.h" #ifdef CONFIG_PPC64 static struct crash_elf_info elf_info64 = { class: ELFCLASS64, data: ELFDATA2MSB, machine: EM_PPC64, page_offset: PAGE_OFFSET, lowmem_limit: MAXMEM, }; #endif static struct crash_elf_info elf_info32 = { class: ELFCLASS32, data: ELFDATA2MSB, #ifdef CONFIG_PPC64 machine: EM_PPC64, #else machine: EM_PPC, #endif page_offset: PAGE_OFFSET, lowmem_limit: MAXMEM, }; /* Stores a sorted list of RAM memory ranges for which to create elf headers. * A separate program header is created for backup region */ static struct memory_range *crash_memory_range; static int crash_nr_memory_ranges; /* Define a variable to replace the CRASH_MAX_MEMORY_RANGES macro */ static int crash_max_memory_ranges; /* * Used to save various memory ranges/regions needed for the captured * kernel to boot. (lime memmap= option in other archs) */ mem_rgns_t usablemem_rgns = {0, NULL}; /* Append a segment to crash_memory_range, splitting it into two if * it contains both lowmem and highmem */ static void add_crash_memory_range(unsigned long long start, unsigned long long end) { #ifndef CONFIG_PPC64 if (start < elf_info32.lowmem_limit && end > elf_info32.lowmem_limit) { add_crash_memory_range(start, elf_info32.lowmem_limit); add_crash_memory_range(elf_info32.lowmem_limit, end); return; } #endif if (crash_nr_memory_ranges < crash_max_memory_ranges) { crash_memory_range[crash_nr_memory_ranges].start = start; crash_memory_range[crash_nr_memory_ranges].end = end; crash_memory_range[crash_nr_memory_ranges].type = RANGE_RAM; } crash_nr_memory_ranges++; } /* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to * create Elf headers. Keeping it separate from get_memory_ranges() as * requirements are different in the case of normal kexec and crashdumps. * * Normal kexec needs to look at all of available physical memory irrespective * of the fact how much of it is being used by currently running kernel. * Crashdumps need to have access to memory regions actually being used by * running kernel. Expecting a different file/data structure than /proc/iomem * to look into down the line. May be something like /proc/kernelmem or may * be zone data structures exported from kernel. */ static int get_crash_memory_ranges(struct memory_range **range, int *ranges) { char device_tree[256] = "/proc/device-tree/"; char fname[256]; DIR *dir, *dmem; int fd; struct dirent *dentry, *mentry; int n, crash_rng_len = 0; unsigned long long start, end, cstart, cend; crash_max_memory_ranges = max_memory_ranges + 6; crash_rng_len = sizeof(struct memory_range) * crash_max_memory_ranges; crash_memory_range = (struct memory_range *) malloc(crash_rng_len); if (!crash_memory_range) { fprintf(stderr, "Allocation for crash memory range failed\n"); return -1; } memset(crash_memory_range, 0, crash_rng_len); crash_nr_memory_ranges = 0; #ifndef CONFIG_BOOKE /* create a separate program header for the backup region */ add_crash_memory_range(BACKUP_SRC_START, BACKUP_SRC_END + 1); #endif dir = opendir(device_tree); if (!dir) { perror(device_tree); goto err; } while ((dentry = readdir(dir)) != NULL) { if (strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory")) continue; strcpy(fname, device_tree); strcat(fname, dentry->d_name); dmem = opendir(fname); if (!dmem) { perror(fname); closedir(dir); goto err; } while ((mentry = readdir(dmem)) != NULL) { if (strcmp(mentry->d_name, "reg")) continue; strcat(fname, "/reg"); fd = open(fname, O_RDONLY); if (fd < 0) { perror(fname); closedir(dmem); closedir(dir); goto err; } n = read_memory_region_limits(fd, &start, &end); /* We are done with fd, close it. */ close(fd); if (n != 0) { closedir(dmem); closedir(dir); goto err; } #ifndef CONFIG_BOOKE if (start == 0 && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; #endif /* * Exclude the region that lies within crashkernel. * If memory limit is set then exclude memory region * above it. */ if (memory_limit) { if (start >= memory_limit) continue; if (end > memory_limit) end = memory_limit; } /* * Exclure region used by crash kernel */ cstart = crash_base; cend = crash_base + crash_size; if (cstart >= end || cend <= start) add_crash_memory_range(start, end); else { if (start < cstart) add_crash_memory_range(start, cstart); if (cend < end) add_crash_memory_range(cend, end); } } closedir(dmem); } closedir(dir); /* * If RTAS region is overlapped with crashkernel, need to create ELF * Program header for the overlapped memory. */ if (crash_base < rtas_base + rtas_size && rtas_base < crash_base + crash_size) { cstart = rtas_base; cend = rtas_base + rtas_size; if (cstart < crash_base) cstart = crash_base; if (cend > crash_base + crash_size) cend = crash_base + crash_size; add_crash_memory_range(cstart, cend); } if (crash_nr_memory_ranges >= crash_max_memory_ranges) { fprintf(stderr, "Error: Number of crash memory ranges" " excedeed the max limit\n"); goto err; } *range = crash_memory_range; *ranges = crash_nr_memory_ranges; int j; dbgprintf("CRASH MEMORY RANGES\n"); for (j = 0; j < *ranges; j++) { start = crash_memory_range[j].start; end = crash_memory_range[j].end; dbgprintf("%016Lx-%016Lx\n", start, end); } return 0; err: if (crash_memory_range) free(crash_memory_range); return -1; } /* Converts unsigned long to ascii string. */ static void ulltoa(unsigned long long i, char *str) { int j = 0, k; char tmp; do { str[j++] = i % 10 + '0'; } while ((i /= 10) > 0); str[j] = '\0'; /* Reverse the string. */ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { tmp = str[k]; str[k] = str[j]; str[j] = tmp; } } /* Append str to cmdline */ static void add_cmdline(char *cmdline, char *str) { int cmdlen = strlen(cmdline) + strlen(str); if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str); } static int add_cmdline_param(char *cmdline, unsigned long long addr, char *cmdstr, char *byte) { int align = 1024; char str[COMMAND_LINE_SIZE], *ptr; /* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/ switch (byte[0]) { case 'K': if (addr%align) return -1; addr = addr/align; break; case 'M': addr = addr/(align *align); break; } ptr = str; strcpy(str, cmdstr); ptr += strlen(str); ulltoa(addr, ptr); strcat(str, byte); add_cmdline(cmdline, str); dbgprintf("Command line after adding elfcorehdr: %s\n", cmdline); return 0; } /* Loads additional segments in case of a panic kernel is being loaded. * One segment for backup region, another segment for storing elf headers * for crash memory image. */ int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline, unsigned long max_addr, unsigned long min_base) { void *tmp; unsigned long sz, elfcorehdr; int nr_ranges, align = 1024, i; unsigned long long end; struct memory_range *mem_range; if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0) return -1; info->backup_src_start = BACKUP_SRC_START; info->backup_src_size = BACKUP_SRC_SIZE; #ifndef CONFIG_BOOKE /* Create a backup region segment to store backup data*/ sz = _ALIGN(BACKUP_SRC_SIZE, align); tmp = xmalloc(sz); memset(tmp, 0, sz); info->backup_start = add_buffer(info, tmp, sz, sz, align, 0, max_addr, 1); reserve(info->backup_start, sz); #endif /* On powerpc memory ranges in device-tree is denoted as start * and size rather than start and end, as is the case with * other architectures like i386 . Because of this when loading * the memory ranges in crashdump-elf.c the filesz calculation * [ end - start + 1 ] goes for a toss. * * To be in sync with other archs adjust the end value for * every crash memory range before calling the generic function */ for (i = 0; i < nr_ranges; i++) { end = crash_memory_range[i].end - 1; crash_memory_range[i].end = end; } #ifdef CONFIG_PPC64 /* Create elf header segment and store crash image data. */ if (arch_options.core_header_type == CORE_TYPE_ELF64) { if (crash_create_elf64_headers(info, &elf_info64, crash_memory_range, nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) return -1; } else if (crash_create_elf32_headers(info, &elf_info32, crash_memory_range, nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) return -1; #else if (crash_create_elf32_headers(info, &elf_info32, crash_memory_range, nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) return -1; #endif elfcorehdr = add_buffer(info, tmp, sz, sz, align, min_base, max_addr, 1); reserve(elfcorehdr, sz); /* modify and store the cmdline in a global array. This is later * read by flatten_device_tree and modified if required */ add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K"); add_cmdline(mod_cmdline, " maxcpus=1"); return 0; } /* * Used to save various memory regions needed for the captured kernel. */ void add_usable_mem_rgns(unsigned long long base, unsigned long long size) { int i; unsigned long long end = base + size; unsigned long long ustart, uend; base = _ALIGN_DOWN(base, getpagesize()); end = _ALIGN_UP(end, getpagesize()); for (i = 0; i < usablemem_rgns.size; i++) { ustart = usablemem_rgns.ranges[i].start; uend = usablemem_rgns.ranges[i].end; if (base < uend && end > ustart) { if ((base >= ustart) && (end <= uend)) return; if (base < ustart && end > uend) { usablemem_rgns.ranges[i].start = base; usablemem_rgns.ranges[i].end = end; return; } else if (base < ustart) { usablemem_rgns.ranges[i].start = base; return; } else if (end > uend) { usablemem_rgns.ranges[i].end = end; return; } } } usablemem_rgns.ranges[usablemem_rgns.size].start = base; usablemem_rgns.ranges[usablemem_rgns.size++].end = end; dbgprintf("usable memory rgns size:%u base:%llx size:%llx\n", usablemem_rgns.size, base, size); } int is_crashkernel_mem_reserved(void) { int fd; fd = open("/proc/device-tree/chosen/linux,crashkernel-base", O_RDONLY); if (fd < 0) return 0; close(fd); return 1; } kexec-tools-2.0.10/kexec/libfdt/fdt.c0000644001567400156740000000000012242534555024632 1kexec-tools-2.0.10/kexec/libfdt/fdt.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_ro.c0000644001567400156740000000000012242534555026032 1kexec-tools-2.0.10/kexec/libfdt/fdt_ro.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_wip.c0000644001567400156740000000000012242534555026370 1kexec-tools-2.0.10/kexec/libfdt/fdt_wip.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_sw.c0000644001567400156740000000000012242534555026054 1kexec-tools-2.0.10/kexec/libfdt/fdt_sw.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_rw.c0000644001567400156740000000000012242534555026052 1kexec-tools-2.0.10/kexec/libfdt/fdt_rw.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_strerror.c0000644001567400156740000000000012242534555030536 1kexec-tools-2.0.10/kexec/libfdt/fdt_strerror.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt.c0000644001567400156740000000000012242534555024632 1kexec-tools-2.0.10/kexec/libfdt/fdt.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_ro.c0000644001567400156740000000000012242534555026032 1kexec-tools-2.0.10/kexec/libfdt/fdt_ro.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_wip.c0000644001567400156740000000000012242534555026370 1kexec-tools-2.0.10/kexec/libfdt/fdt_wip.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_sw.c0000644001567400156740000000000012242534555026054 1kexec-tools-2.0.10/kexec/libfdt/fdt_sw.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_rw.c0000644001567400156740000000000012242534555026052 1kexec-tools-2.0.10/kexec/libfdt/fdt_rw.custar hormshormskexec-tools-2.0.10/kexec/libfdt/fdt_strerror.c0000644001567400156740000000000012242534555030536 1kexec-tools-2.0.10/kexec/libfdt/fdt_strerror.custar hormshormskexec-tools-2.0.10/kexec/arch/ppc/libfdt-wrapper.c0000644001567400156740000001137112417126536021013 0ustar hormshorms/* * This file does the necessary interface mapping between the bootwrapper * device tree operations and the interface provided by shared source * files flatdevicetree.[ch]. * * Copyright 2007 David Gibson, IBM Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ #include #include #include #include #include #include "ops.h" #include "../../kexec.h" #define BAD_ERROR(err) (((err) < 0) \ && ((err) != -FDT_ERR_NOTFOUND) \ && ((err) != -FDT_ERR_EXISTS)) #define check_err(err) \ ({ \ if (BAD_ERROR(err) || ((err < 0) && kexec_debug)) \ printf("%s():%d %s\n\r", __func__, __LINE__, \ fdt_strerror(err)); \ if (BAD_ERROR(err)) \ exit(1); \ (err < 0) ? -1 : 0; \ }) #define offset_devp(off) \ ({ \ int _offset = (off); \ check_err(_offset) ? NULL : (void *)(_offset+1); \ }) #define devp_offset_find(devp) (((int)(devp))-1) #define devp_offset(devp) (devp ? ((int)(devp))-1 : 0) static void *fdt; static void *buf; /* = NULL */ struct dt_ops dt_ops; #define EXPAND_GRANULARITY 1024 static void expand_buf(int minexpand) { int size = fdt_totalsize(fdt); int rc; size = _ALIGN(size + minexpand, EXPAND_GRANULARITY); buf = realloc(buf, size); if (!buf) die("Couldn't find %d bytes to expand device tree\n\r", size); rc = fdt_open_into(fdt, buf, size); if (rc != 0) die("Couldn't expand fdt into new buffer: %s\n\r", fdt_strerror(rc)); fdt = buf; } static void *fdt_wrapper_finddevice(const char *path) { return offset_devp(fdt_path_offset(fdt, path)); } static int fdt_wrapper_getprop(const void *devp, const char *name, void *buf, const int buflen) { const void *p; int len; p = fdt_getprop(fdt, devp_offset(devp), name, &len); if (!p) return check_err(len); memcpy(buf, p, min(len, buflen)); return len; } static int fdt_wrapper_setprop(const void *devp, const char *name, const void *buf, const int len) { int rc; rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); if (rc == -FDT_ERR_NOSPACE) { expand_buf(len + 16); rc = fdt_setprop(fdt, devp_offset(devp), name, buf, len); } return check_err(rc); } static void *fdt_wrapper_get_parent(const void *devp) { return offset_devp(fdt_parent_offset(fdt, devp_offset(devp))); } static void *fdt_wrapper_create_node(const void *devp, const char *name) { int offset; offset = fdt_add_subnode(fdt, devp_offset(devp), name); if (offset == -FDT_ERR_NOSPACE) { expand_buf(strlen(name) + 16); offset = fdt_add_subnode(fdt, devp_offset(devp), name); } return offset_devp(offset); } static void *fdt_wrapper_find_node_by_prop_value(const void *prev, const char *name, const char *val, int len) { int offset = fdt_node_offset_by_prop_value(fdt, devp_offset_find(prev), name, val, len); return offset_devp(offset); } static void *fdt_wrapper_find_node_by_compatible(const void *prev, const char *val) { int offset = fdt_node_offset_by_compatible(fdt, devp_offset_find(prev), val); return offset_devp(offset); } static char *fdt_wrapper_get_path(const void *devp, char *buf, int len) { int rc; rc = fdt_get_path(fdt, devp_offset(devp), buf, len); if (check_err(rc)) return NULL; return buf; } static unsigned long fdt_wrapper_finalize(void) { int rc; rc = fdt_pack(fdt); if (rc != 0) die("Couldn't pack flat tree: %s\n\r", fdt_strerror(rc)); return (unsigned long)fdt; } void fdt_init(void *blob) { int err; int bufsize; dt_ops.finddevice = fdt_wrapper_finddevice; dt_ops.getprop = fdt_wrapper_getprop; dt_ops.setprop = fdt_wrapper_setprop; dt_ops.get_parent = fdt_wrapper_get_parent; dt_ops.create_node = fdt_wrapper_create_node; dt_ops.find_node_by_prop_value = fdt_wrapper_find_node_by_prop_value; dt_ops.find_node_by_compatible = fdt_wrapper_find_node_by_compatible; dt_ops.get_path = fdt_wrapper_get_path; dt_ops.finalize = fdt_wrapper_finalize; /* Make sure the dt blob is the right version and so forth */ fdt = blob; bufsize = fdt_totalsize(fdt); err = fdt_open_into(fdt, fdt, bufsize); if (err != 0) die("fdt_init(): %s\n\r", fdt_strerror(err)); } kexec-tools-2.0.10/kexec/arch/ppc/crashdump-powerpc.h0000644001567400156740000000251512417126536021541 0ustar hormshorms#ifndef CRASHDUMP_POWERPC_H #define CRASHDUMP_POWERPC_H struct kexec_info; int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline, unsigned long max_addr, unsigned long min_base); void add_usable_mem_rgns(unsigned long long base, unsigned long long size); extern struct arch_options_t arch_options; #ifdef CONFIG_PPC64 #define PAGE_OFFSET 0xC000000000000000UL #define VMALLOCBASE 0xD000000000000000UL #define MAXMEM (-KERNELBASE-VMALLOCBASE) #else #define PAGE_OFFSET 0xC0000000 #define MAXMEM 0x30000000 /* Use CONFIG_LOWMEM_SIZE from kernel */ #endif #define KERNELBASE PAGE_OFFSET #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define COMMAND_LINE_SIZE 512 /* from kernel */ #ifdef CONFIG_BOOKE /* We don't need backup region in Book E */ #define BACKUP_SRC_START 0x0000 #define BACKUP_SRC_END 0x0000 #define BACKUP_SRC_SIZE 0x0000 #else /* Backup Region, First 64K of System RAM. */ #define BACKUP_SRC_START 0x0000 #define BACKUP_SRC_END 0xffff #define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1) #endif #define KDUMP_BACKUP_LIMIT BACKUP_SRC_SIZE extern unsigned long long crash_base; extern unsigned long long crash_size; extern unsigned int rtas_base; extern unsigned int rtas_size; extern uint64_t opal_base; extern uint64_t opal_size; extern uint64_t memory_limit; #endif /* CRASHDUMP_POWERPC_H */ kexec-tools-2.0.10/kexec/arch/ppc/fixup_dtb.h0000644001567400156740000000046211642166046020060 0ustar hormshorms#ifndef __FIXUP_DTB_H #define __FIXUP_DTB_H char *fixup_dtb_init(struct kexec_info *info, char *blob_buf, off_t *blob_size, unsigned long hole_addr, unsigned long *dtb_addr); char *fixup_dtb_finalize(struct kexec_info *info, char *blob_buf, off_t *blob_size, char *nodes[], char *cmdline); #endif kexec-tools-2.0.10/kexec/arch/ppc/kexec-ppc.h0000644001567400156740000000437412417126536017762 0ustar hormshorms#ifndef KEXEC_PPC_H #define KEXEC_PPC_H #define MAXBYTES 128 #define MAX_LINE 160 #define CORE_TYPE_ELF32 1 #define CORE_TYPE_ELF64 2 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 uint64_t rmo_top; extern struct { uint32_t spr8; } setup_dol_regs; #define SIZE_16M (16*1024*1024UL) 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 uImage_ppc_probe(const char *buf, off_t len); int uImage_ppc_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void uImage_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); /* * During inital setup the kernel does not map the whole memory but a part of * it. On Book-E that is 64MiB, 601 24MiB or 256MiB (if possible). */ #define KERNEL_ACCESS_TOP (24 * 1024 * 1024) /* boot block version 17 as defined by the linux kernel */ struct bootblock { unsigned magic, totalsize, off_dt_struct, off_dt_strings, off_mem_rsvmap, version, last_comp_version, boot_physid, dt_strings_size, dt_struct_size; }; typedef struct mem_rgns { unsigned int size; struct memory_range *ranges; } mem_rgns_t; extern mem_rgns_t usablemem_rgns; extern int max_memory_ranges; extern unsigned long long crash_base, crash_size; extern unsigned long long initrd_base, initrd_size; extern unsigned long long ramdisk_base, ramdisk_size; extern unsigned char reuse_initrd; extern const char *ramdisk; /* Method to parse the memory/reg nodes in device-tree */ extern unsigned long dt_address_cells, dt_size_cells; extern int init_memory_region_info(void); extern int read_memory_region_limits(int fd, unsigned long long *start, unsigned long long *end); #define COMMAND_LINE_SIZE 512 /* from kernel */ /*fs2dt*/ void reserve(unsigned long long where, unsigned long long length); /* Defined kexec-uImage-ppc.c */ extern char* slurp_ramdisk_ppc(const char *filename, off_t *r_size); #endif /* KEXEC_PPC_H */ kexec-tools-2.0.10/kexec/arch/ppc/ops.h0000644001567400156740000001003412417126536016672 0ustar hormshorms/* * Global definition of all the bootwrapper operations. * * Author: Mark A. Greer * * 2006 (c) MontaVista Software, Inc. This file is licensed under * the terms of the GNU General Public License version 2. This program * is licensed "as is" without any warranty of any kind, whether express * or implied. */ #ifndef _PPC_BOOT_OPS_H_ #define _PPC_BOOT_OPS_H_ #include "types.h" #define COMMAND_LINE_SIZE 512 #define MAX_PATH_LEN 256 #define MAX_PROP_LEN 256 /* What should this be? */ typedef void (*kernel_entry_t)(unsigned long r3, unsigned long r4, void *r5); /* Device Tree operations */ struct dt_ops { void * (*finddevice)(const char *name); int (*getprop)(const void *phandle, const char *name, void *buf, const int buflen); int (*setprop)(const void *phandle, const char *name, const void *buf, const int buflen); void *(*get_parent)(const void *phandle); /* The node must not already exist. */ void *(*create_node)(const void *parent, const char *name); void *(*find_node_by_prop_value)(const void *prev, const char *propname, const char *propval, int proplen); void *(*find_node_by_compatible)(const void *prev, const char *compat); unsigned long (*finalize)(void); char *(*get_path)(const void *phandle, char *buf, int len); }; extern struct dt_ops dt_ops; void fdt_init(void *blob); extern void flush_cache(void *, unsigned long); int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size); int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr); int dt_is_compatible(void *node, const char *compat); void dt_get_reg_format(void *node, u32 *naddr, u32 *nsize); int dt_get_virtual_reg(void *node, void **addr, int nres); static inline void *finddevice(const char *name) { return (dt_ops.finddevice) ? dt_ops.finddevice(name) : NULL; } static inline int getprop(void *devp, const char *name, void *buf, int buflen) { return (dt_ops.getprop) ? dt_ops.getprop(devp, name, buf, buflen) : -1; } static inline int setprop(void *devp, const char *name, const void *buf, int buflen) { return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1; } #define setprop_val(devp, name, val) \ do { \ typeof(val) x = (val); \ setprop((devp), (name), &x, sizeof(x)); \ } while (0) static inline int setprop_str(void *devp, const char *name, const char *buf) { if (dt_ops.setprop) return dt_ops.setprop(devp, name, buf, strlen(buf) + 1); return -1; } static inline void *get_parent(const char *devp) { return dt_ops.get_parent ? dt_ops.get_parent(devp) : NULL; } static inline void *create_node(const void *parent, const char *name) { return dt_ops.create_node ? dt_ops.create_node(parent, name) : NULL; } static inline void *find_node_by_prop_value(const void *prev, const char *propname, const char *propval, int proplen) { if (dt_ops.find_node_by_prop_value) return dt_ops.find_node_by_prop_value(prev, propname, propval, proplen); return NULL; } static inline void *find_node_by_prop_value_str(const void *prev, const char *propname, const char *propval) { return find_node_by_prop_value(prev, propname, propval, strlen(propval) + 1); } static inline void *find_node_by_devtype(const void *prev, const char *type) { return find_node_by_prop_value_str(prev, "device_type", type); } static inline void *find_node_by_alias(const char *alias) { void *devp = finddevice("/aliases"); if (devp) { char path[MAX_PATH_LEN]; if (getprop(devp, alias, path, MAX_PATH_LEN) > 0) return finddevice(path); } return NULL; } static inline void *find_node_by_compatible(const void *prev, const char *compat) { if (dt_ops.find_node_by_compatible) return dt_ops.find_node_by_compatible(prev, compat); return NULL; } #define dt_fixup_mac_addresses(...) \ __dt_fixup_mac_addresses(0, __VA_ARGS__, NULL) static inline char *get_path(const void *phandle, char *buf, int len) { if (dt_ops.get_path) return dt_ops.get_path(phandle, buf, len); return NULL; } #endif /* _PPC_BOOT_OPS_H_ */ kexec-tools-2.0.10/kexec/arch/ppc/ppc_asm.h0000644001567400156740000005423111424244110017504 0ustar hormshorms/* * 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 kexec-tools-2.0.10/kexec/arch/ppc/include/page.h0000644001567400156740000000142112242534555020430 0ustar hormshorms#ifndef _PPC_BOOT_PAGE_H #define _PPC_BOOT_PAGE_H /* * Copyright (C) 2001 PPC64 Team, 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; either version * 2 of the License, or (at your option) any later version. */ #ifdef __ASSEMBLY__ #define ASM_CONST(x) x #else #define __ASM_CONST(x) x##UL #define ASM_CONST(x) __ASM_CONST(x) #endif /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 12 #define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1))) #endif /* _PPC_BOOT_PAGE_H */ kexec-tools-2.0.10/kexec/arch/ppc/include/types.h0000644001567400156740000000104511642166046020661 0ustar hormshorms#ifndef _TYPES_H_ #define _TYPES_H_ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; typedef signed char s8; typedef short s16; typedef int s32; typedef long long s64; #define min(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) #define max(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; }) #endif /* _TYPES_H_ */ kexec-tools-2.0.10/kexec/arch/ppc/include/arch/options.h0000644001567400156740000000316412242534555022132 0ustar hormshorms#ifndef KEXEC_ARCH_PPC_OPTIONS_H #define KEXEC_ARCH_PPC_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) /* All 'local' loader options: */ #define OPT_APPEND (OPT_ARCH_MAX+0) #define OPT_GAMECUBE (OPT_ARCH_MAX+1) #define OPT_DTB (OPT_ARCH_MAX+2) #define OPT_NODES (OPT_ARCH_MAX+3) #define OPT_RAMDISK (OPT_ARCH_MAX+4) /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ {"command-line", 1, 0, OPT_APPEND},\ {"append", 1, 0, OPT_APPEND},\ {"ramdisk", 1, 0, OPT_APPEND},\ {"initrd", 1, 0, OPT_APPEND},\ {"gamecube", 1, 0, OPT_GAMECUBE},\ {"dtb", 1, 0, OPT_DTB},\ {"reuse-node", 1, 0, OPT_NODES}, #define KEXEC_ALL_OPT_STR KEXEC_OPT_STR #endif /* KEXEC_ARCH_PPC_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/ppc64/Makefile0000644001567400156740000000127212417126536017536 0ustar hormshorms# # kexec ppc64 (linux booting linux) # ppc64_KEXEC_SRCS = kexec/arch/ppc64/kexec-elf-rel-ppc64.c ppc64_KEXEC_SRCS += kexec/arch/ppc64/kexec-zImage-ppc64.c ppc64_KEXEC_SRCS += kexec/arch/ppc64/kexec-elf-ppc64.c ppc64_KEXEC_SRCS += kexec/arch/ppc64/kexec-ppc64.c ppc64_KEXEC_SRCS += kexec/arch/ppc64/crashdump-ppc64.c ppc64_ARCH_REUSE_INITRD = ppc64_FS2DT = kexec/fs2dt.c ppc64_FS2DT_INCLUDE = -include $(srcdir)/kexec/arch/ppc64/crashdump-ppc64.h \ -include $(srcdir)/kexec/arch/ppc64/kexec-ppc64.h dist += kexec/arch/ppc64/Makefile $(ppc64_KEXEC_SRCS) \ kexec/arch/ppc64/kexec-ppc64.h kexec/arch/ppc64/crashdump-ppc64.h \ kexec/arch/ppc64/include/arch/options.h kexec-tools-2.0.10/kexec/arch/ppc64/kexec-elf-rel-ppc64.c0000644001567400156740000001032112417126536021612 0ustar hormshorms#include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "kexec-ppc64.h" int machine_verify_elf_rel(struct mem_ehdr *ehdr) { 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 = (unsigned char *)ehdr->e_shdr[ehdr->e_shstrndx].sh_data; shdr_end = &ehdr->e_shdr[ehdr->e_shnum]; for (shdr = ehdr->e_shdr; shdr != shdr_end; shdr++) { if (shdr->sh_size && strcmp((char *)&strtab[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) */ 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; } static void do_relative_toc(unsigned long value, uint16_t *location, unsigned long mask, int complain_signed) { if (complain_signed && (value + 0x8000 > 0xffff)) { die("TOC16 relocation overflows (%lu)\n", value); } if ((~mask & 0xffff) & value) { die("bad TOC16 relocation (%lu)\n", value); } *location = (*location & ~mask) | (value & mask); } 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: case R_PPC64_REL64: /* Simply set it */ *(uint64_t *)location = value; break; case R_PPC64_REL32: *(uint32_t *)location = value - (uint32_t)(uint64_t)location; break; case R_PPC64_TOC: *(uint64_t *)location = my_r2(ehdr); break; case R_PPC64_TOC16: do_relative_toc(value - my_r2(ehdr), location, 0xffff, 1); break; case R_PPC64_TOC16_DS: do_relative_toc(value - my_r2(ehdr), location, 0xfffc, 1); break; case R_PPC64_TOC16_LO: do_relative_toc(value - my_r2(ehdr), location, 0xffff, 0); break; case R_PPC64_TOC16_LO_DS: do_relative_toc(value - my_r2(ehdr), location, 0xfffc, 0); break; case R_PPC64_TOC16_HI: do_relative_toc((value - my_r2(ehdr)) >> 16, location, 0xffff, 0); break; case R_PPC64_TOC16_HA: do_relative_toc((value - my_r2(ehdr) + 0x8000) >> 16, location, 0xffff, 0); 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; case R_PPC64_ADDR16_LO: *(uint16_t *)location = value & 0xffff; break; case R_PPC64_ADDR16_HI: *(uint16_t *)location = (value >> 16) & 0xffff; break; case R_PPC64_ADDR16_HA: *(uint16_t *)location = (((value + 0x8000) >> 16) & 0xffff); break; case R_PPC64_ADDR16_HIGHER: *(uint16_t *)location = (((uint64_t)value >> 32) & 0xffff); break; case R_PPC64_ADDR16_HIGHEST: *(uint16_t *)location = (((uint64_t)value >> 48) & 0xffff); break; /* R_PPC64_REL16_HA and R_PPC64_REL16_LO are handled to support * ABIv2 r2 assignment based on r12 for PIC executable. * Here address is know so replace * 0: addis 2,12,.TOC.-0b@ha * addi 2,2,.TOC.-0b@l * by * lis 2,.TOC.@ha * addi 2,2,.TOC.@l */ case R_PPC64_REL16_HA: /* check that we are dealing with the addis 2,12 instruction */ if (((*(uint32_t*)location) & 0xffff0000) != 0x3c4c0000) die("Unexpected instruction for R_PPC64_REL16_HA"); value += my_r2(ehdr); /* replacing by lis 2 */ *(uint32_t *)location = 0x3c400000 + ((value >> 16) & 0xffff); break; case R_PPC64_REL16_LO: /* check that we are dealing with the addi 2,2 instruction */ if (((*(uint32_t*)location) & 0xffff0000) != 0x38420000) die("Unexpected instruction for R_PPC64_REL16_LO"); value += my_r2(ehdr) - 4; *(uint16_t *)location = value & 0xffff; break; default: die("Unknown rela relocation: %lu\n", r_type); break; } } kexec-tools-2.0.10/kexec/arch/ppc64/kexec-zImage-ppc64.c0000644001567400156740000001055112417126536021505 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #define MAX_HEADERS 32 int zImage_ppc64_probe(FILE *file) { Elf32_Ehdr elf; int valid; 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; } valid = (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); return valid ? 0 : -1; } int zImage_ppc64_load(FILE *file, int UNUSED(argc), char **UNUSED(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 = 0; /* 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((void *)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 = (void *)(uintptr_t)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"); } kexec-tools-2.0.10/kexec/arch/ppc64/kexec-elf-ppc64.c0000644001567400156740000002672612466045522021051 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) 2004 Adam Litke (agl@us.ibm.com) * Copyright (C) 2004 IBM Corp. * Copyright (C) 2005 R Sharada (sharada@in.ibm.com) * Copyright (C) 2006 Mohan Kumar M (mohan@in.ibm.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 #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "kexec-ppc64.h" #include "../../fs2dt.h" #include "crashdump-ppc64.h" #include uint64_t initrd_base, initrd_size; unsigned char reuse_initrd = 0; const char *ramdisk; /* Used for enabling printing message from purgatory code */ int my_debug = 0; int elf_ppc64_probe(const char *buf, off_t len) { struct mem_ehdr ehdr; int result; result = build_elf_exec_info(buf, len, &ehdr, 0); 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; } void arch_reuse_initrd(void) { reuse_initrd = 1; } static int read_prop(char *name, void *value, size_t len) { int fd; size_t rlen; fd = open(name, O_RDONLY); if (fd == -1) return -1; rlen = read(fd, value, len); if (rlen < 0) fprintf(stderr, "Warning : Can't read %s : %s", name, strerror(errno)); else if (rlen != len) fprintf(stderr, "Warning : short read from %s", name); close(fd); return 0; } int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; char *cmdline, *modified_cmdline = NULL; const char *devicetreeblob; int cmdline_len, modified_cmdline_len; uint64_t max_addr, hole_addr; char *seg_buf = NULL; off_t seg_size = 0; struct mem_phdr *phdr; size_t size; #ifdef NEED_RESERVE_DTB uint64_t *rsvmap_ptr; struct bootblock *bb_ptr; #endif int i; int result, opt; uint64_t my_kernel, my_dt_offset; uint64_t my_opal_base = 0, my_opal_entry = 0; unsigned int my_panic_kernel; uint64_t my_stack, my_backup_start; uint64_t toc_addr; uint32_t my_run_at_load; unsigned int slave_code[256/sizeof (unsigned int)], master_entry; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, NULL, OPT_APPEND }, { "append", 1, NULL, OPT_APPEND }, { "ramdisk", 1, NULL, OPT_RAMDISK }, { "initrd", 1, NULL, OPT_RAMDISK }, { "devicetreeblob", 1, NULL, OPT_DEVICETREEBLOB }, { "dtb", 1, NULL, OPT_DEVICETREEBLOB }, { "args-linux", 0, NULL, OPT_ARGS_IGNORE }, { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_OPT_STR ""; /* Parse command line arguments */ initrd_base = 0; initrd_size = 0; cmdline = 0; ramdisk = 0; devicetreeblob = 0; max_addr = 0xFFFFFFFFFFFFFFFFULL; hole_addr = 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 OPT_APPEND: cmdline = optarg; break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_DEVICETREEBLOB: devicetreeblob = optarg; break; case OPT_ARGS_IGNORE: break; } } cmdline_len = 0; if (cmdline) cmdline_len = strlen(cmdline) + 1; else fprintf(stdout, "Warning: append= option is not passed. Using the first kernel root partition\n"); if (ramdisk && reuse_initrd) die("Can't specify --ramdisk or --initrd with --reuseinitrd\n"); /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & KEXEC_ON_CRASH) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (cmdline) { strncpy(modified_cmdline, cmdline, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } modified_cmdline_len = strlen(modified_cmdline); } /* Parse the Elf file */ result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) { free_elf_info(&ehdr); return result; } /* Load the Elf data. Physical load addresses in elf64 header do not * show up correctly. Use user supplied address for now to patch the * elf header */ phdr = &ehdr.e_phdr[0]; size = phdr->p_filesz; if (size > phdr->p_memsz) size = phdr->p_memsz; my_kernel = hole_addr = locate_hole(info, size, 0, 0, max_addr, 1); ehdr.e_phdr[0].p_paddr = hole_addr; result = elf_exec_load(&ehdr, info); if (result < 0) { free_elf_info(&ehdr); return result; } /* If panic kernel is being loaded, additional segments need * to be created. */ if (info->kexec_flags & KEXEC_ON_CRASH) { result = load_crashdump_segments(info, modified_cmdline, max_addr, 0); if (result < 0) return -1; /* Use new command line. */ cmdline = modified_cmdline; cmdline_len = strlen(modified_cmdline) + 1; } /* Add v2wrap to the current image */ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0, max_addr, 1, 0); /* Add a ram-disk to the current image * Note: Add the ramdisk after elf_rel_build_load */ if (ramdisk) { if (devicetreeblob) { fprintf(stderr, "Can't use ramdisk with device tree blob input\n"); return -1; } seg_buf = slurp_file(ramdisk, &seg_size); hole_addr = add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, 1); initrd_base = hole_addr; initrd_size = seg_size; } /* ramdisk */ if (devicetreeblob) { /* Grab device tree from buffer */ seg_buf = slurp_file(devicetreeblob, &seg_size); } else { /* create from fs2dt */ create_flatten_tree(&seg_buf, &seg_size, cmdline); } my_dt_offset = add_buffer(info, seg_buf, seg_size, seg_size, 0, 0, max_addr, -1); #ifdef NEED_RESERVE_DTB /* patch reserve map address for flattened device-tree * find last entry (both 0) in the reserve mem list. Assume DT * entry is before this one */ bb_ptr = (struct bootblock *)(seg_buf); rsvmap_ptr = (uint64_t *)(seg_buf + be32_to_cpu(bb_ptr->off_mem_rsvmap)); while (*rsvmap_ptr || *(rsvmap_ptr+1)) rsvmap_ptr += 2; rsvmap_ptr -= 2; *rsvmap_ptr = cpu_to_be64(my_dt_offset); rsvmap_ptr++; *rsvmap_ptr = cpu_to_be64((uint64_t)be32_to_cpu(bb_ptr->totalsize)); #endif if (read_prop("/proc/device-tree/ibm,opal/opal-base-address", &my_opal_base, sizeof(my_opal_base)) == 0) { my_opal_base = be64_to_cpu(my_opal_base); elf_rel_set_symbol(&info->rhdr, "opal_base", &my_opal_base, sizeof(my_opal_base)); } if (read_prop("/proc/device-tree/ibm,opal/opal-entry-address", &my_opal_entry, sizeof(my_opal_entry)) == 0) { my_opal_entry = be64_to_cpu(my_opal_entry); elf_rel_set_symbol(&info->rhdr, "opal_entry", &my_opal_entry, sizeof(my_opal_entry)); } /* Set kernel */ elf_rel_set_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel)); /* Set dt_offset */ elf_rel_set_symbol(&info->rhdr, "dt_offset", &my_dt_offset, sizeof(my_dt_offset)); /* get slave code from new kernel, put in purgatory */ elf_rel_get_symbol(&info->rhdr, "purgatory_start", slave_code, sizeof(slave_code)); master_entry = slave_code[0]; memcpy(slave_code, phdr->p_data, sizeof(slave_code)); slave_code[0] = master_entry; elf_rel_set_symbol(&info->rhdr, "purgatory_start", slave_code, sizeof(slave_code)); if (info->kexec_flags & KEXEC_ON_CRASH) { my_panic_kernel = 1; /* Set panic flag */ elf_rel_set_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel, sizeof(my_panic_kernel)); /* Set backup address */ my_backup_start = info->backup_start; elf_rel_set_symbol(&info->rhdr, "backup_start", &my_backup_start, sizeof(my_backup_start)); /* Tell relocatable kernel to run at load address * via word before slave code in purgatory */ elf_rel_get_symbol(&info->rhdr, "run_at_load", &my_run_at_load, sizeof(my_run_at_load)); if (my_run_at_load == KERNEL_RUN_AT_ZERO_MAGIC) my_run_at_load = 1; /* else it should be a fixed offset image */ elf_rel_set_symbol(&info->rhdr, "run_at_load", &my_run_at_load, sizeof(my_run_at_load)); } /* Set stack address */ my_stack = locate_hole(info, 16*1024, 0, 0, max_addr, 1); my_stack += 16*1024; elf_rel_set_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack)); /* Set toc */ toc_addr = my_r2(&info->rhdr); elf_rel_set_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr)); /* Set debug */ elf_rel_set_symbol(&info->rhdr, "debug", &my_debug, sizeof(my_debug)); my_kernel = 0; my_dt_offset = 0; my_panic_kernel = 0; my_backup_start = 0; my_stack = 0; toc_addr = 0; my_run_at_load = 0; my_debug = 0; my_opal_base = 0; my_opal_entry = 0; elf_rel_get_symbol(&info->rhdr, "opal_base", &my_opal_base, sizeof(my_opal_base)); elf_rel_get_symbol(&info->rhdr, "opal_entry", &my_opal_entry, sizeof(my_opal_entry)); elf_rel_get_symbol(&info->rhdr, "kernel", &my_kernel, sizeof(my_kernel)); elf_rel_get_symbol(&info->rhdr, "dt_offset", &my_dt_offset, sizeof(my_dt_offset)); elf_rel_get_symbol(&info->rhdr, "run_at_load", &my_run_at_load, sizeof(my_run_at_load)); elf_rel_get_symbol(&info->rhdr, "panic_kernel", &my_panic_kernel, sizeof(my_panic_kernel)); elf_rel_get_symbol(&info->rhdr, "backup_start", &my_backup_start, sizeof(my_backup_start)); elf_rel_get_symbol(&info->rhdr, "stack", &my_stack, sizeof(my_stack)); elf_rel_get_symbol(&info->rhdr, "my_toc", &toc_addr, sizeof(toc_addr)); elf_rel_get_symbol(&info->rhdr, "debug", &my_debug, sizeof(my_debug)); dbgprintf("info->entry is %p\n", info->entry); dbgprintf("kernel is %llx\n", (unsigned long long)my_kernel); dbgprintf("dt_offset is %llx\n", (unsigned long long)my_dt_offset); dbgprintf("run_at_load flag is %x\n", my_run_at_load); dbgprintf("panic_kernel is %x\n", my_panic_kernel); dbgprintf("backup_start is %llx\n", (unsigned long long)my_backup_start); dbgprintf("stack is %llx\n", (unsigned long long)my_stack); dbgprintf("toc_addr is %llx\n", (unsigned long long)toc_addr); dbgprintf("purgatory size is %zu\n", purgatory_size); dbgprintf("debug is %d\n", my_debug); dbgprintf("opal_base is %llx\n", (unsigned long long) my_opal_base); dbgprintf("opal_entry is %llx\n", (unsigned long long) my_opal_entry); return 0; } void elf_ppc64_usage(void) { fprintf(stderr, " --command-line= command line to append.\n"); fprintf(stderr, " --append= same as --command-line.\n"); fprintf(stderr, " --ramdisk= Initial RAM disk.\n"); fprintf(stderr, " --initrd= same as --ramdisk.\n"); fprintf(stderr, " --devicetreeblob= Specify device tree blob file.\n"); fprintf(stderr, " --dtb= same as --devicetreeblob.\n"); fprintf(stderr, "elf support is still broken\n"); } kexec-tools-2.0.10/kexec/arch/ppc64/kexec-ppc64.c0000644001567400156740000005653212417126536020304 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) 2003-2005 Eric Biederman (ebiederm@xmission.com) * Copyright (C) 2005 R Sharada (sharada@in.ibm.com), IBM 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 (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 #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-ppc64.h" #include "../../fs2dt.h" #include "crashdump-ppc64.h" #include static struct memory_range *exclude_range = NULL; static struct memory_range *memory_range = NULL; static struct memory_range *base_memory_range = NULL; static uint64_t rmo_top; uint64_t memory_max = 0; uint64_t memory_limit; static int nr_memory_ranges, nr_exclude_ranges; uint64_t crash_base, crash_size; unsigned int rtas_base, rtas_size; uint64_t opal_base, opal_size; int max_memory_ranges; static void cleanup_memory_ranges(void) { if (memory_range) free(memory_range); if (base_memory_range) free(base_memory_range); if (exclude_range) free(exclude_range); if (usablemem_rgns.ranges) free(usablemem_rgns.ranges); } /* * Allocate memory for various data structures used to hold * values of different memory ranges */ static int alloc_memory_ranges(void) { int memory_range_len; memory_range_len = sizeof(struct memory_range) * max_memory_ranges; memory_range = (struct memory_range *) malloc(memory_range_len); if (!memory_range) return -1; base_memory_range = (struct memory_range *) malloc(memory_range_len); if (!base_memory_range) goto err1; exclude_range = (struct memory_range *) malloc(memory_range_len); if (!exclude_range) goto err1; usablemem_rgns.ranges = (struct memory_range *) malloc(memory_range_len); if (!(usablemem_rgns.ranges)) goto err1; memset(memory_range, 0, memory_range_len); memset(base_memory_range, 0, memory_range_len); memset(exclude_range, 0, memory_range_len); memset(usablemem_rgns.ranges, 0, memory_range_len); return 0; err1: fprintf(stderr, "memory range structure allocation failure\n"); cleanup_memory_ranges(); return -1; } static int realloc_memory_ranges(void) { size_t memory_range_len; max_memory_ranges++; memory_range_len = sizeof(struct memory_range) * max_memory_ranges; memory_range = (struct memory_range *) realloc(memory_range, memory_range_len); if (!memory_range) goto err; base_memory_range = (struct memory_range *) realloc(base_memory_range, memory_range_len); if (!base_memory_range) goto err; exclude_range = (struct memory_range *) realloc(exclude_range, memory_range_len); if (!exclude_range) goto err; usablemem_rgns.ranges = (struct memory_range *) realloc(usablemem_rgns.ranges, memory_range_len); if (!(usablemem_rgns.ranges)) goto err; return 0; err: fprintf(stderr, "memory range structure re-allocation failure\n"); return -1; } static void add_base_memory_range(uint64_t start, uint64_t end) { base_memory_range[nr_memory_ranges].start = start; base_memory_range[nr_memory_ranges].end = end; base_memory_range[nr_memory_ranges].type = RANGE_RAM; nr_memory_ranges++; if (nr_memory_ranges >= max_memory_ranges) realloc_memory_ranges(); dbgprintf("%016llx-%016llx : %x\n", base_memory_range[nr_memory_ranges-1].start, base_memory_range[nr_memory_ranges-1].end, base_memory_range[nr_memory_ranges-1].type); } static int get_dyn_reconf_base_ranges(void) { uint64_t start, end; char fname[128], buf[32]; FILE *file; unsigned int i; int n; strcpy(fname, "/proc/device-tree/"); strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,lmb-size"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); return -1; } if (fread(buf, 1, 8, file) != 8) { perror(fname); fclose(file); return -1; } /* * lmb_size, num_of_lmbs(global variables) are * initialized once here. */ lmb_size = be64_to_cpu(((uint64_t *)buf)[0]); fclose(file); strcpy(fname, "/proc/device-tree/"); strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); return -1; } /* first 4 bytes tell the number of lmbs */ if (fread(buf, 1, 4, file) != 4) { perror(fname); fclose(file); return -1; } num_of_lmbs = be32_to_cpu(((unsigned int *)buf)[0]); for (i = 0; i < num_of_lmbs; i++) { if ((n = fread(buf, 1, 24, file)) < 0) { perror(fname); fclose(file); return -1; } if (nr_memory_ranges >= max_memory_ranges) return -1; start = be64_to_cpu(((uint64_t *)buf)[0]); end = start + lmb_size; add_base_memory_range(start, end); } fclose(file); return 0; } /* Sort the base ranges in memory - this is useful for ensuring that our * ranges are in ascending order, even if device-tree read of memory nodes * is done differently. Also, could be used for other range coalescing later */ static int sort_base_ranges(void) { int i, j; unsigned long long tstart, tend; for (i = 0; i < nr_memory_ranges - 1; i++) { for (j = 0; j < nr_memory_ranges - i - 1; j++) { if (base_memory_range[j].start > base_memory_range[j+1].start) { tstart = base_memory_range[j].start; tend = base_memory_range[j].end; base_memory_range[j].start = base_memory_range[j+1].start; base_memory_range[j].end = base_memory_range[j+1].end; base_memory_range[j+1].start = tstart; base_memory_range[j+1].end = tend; } } } return 0; } /* Get base memory ranges */ static int get_base_ranges(void) { uint64_t start, end; char device_tree[256] = "/proc/device-tree/"; char fname[256]; char buf[MAXBYTES]; DIR *dir, *dmem; FILE *file; struct dirent *dentry, *mentry; int n; if ((dir = opendir(device_tree)) == NULL) { perror(device_tree); return -1; } while ((dentry = readdir(dir)) != NULL) { if (!strncmp(dentry->d_name, "ibm,dynamic-reconfiguration-memory", 35)) { get_dyn_reconf_base_ranges(); continue; } if (strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory")) continue; strcpy(fname, device_tree); strcat(fname, dentry->d_name); if ((dmem = opendir(fname)) == NULL) { perror(fname); closedir(dir); return -1; } while ((mentry = readdir(dmem)) != NULL) { if (strcmp(mentry->d_name, "reg")) continue; strcat(fname, "/reg"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); closedir(dmem); closedir(dir); return -1; } if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); fclose(file); closedir(dmem); closedir(dir); return -1; } if (nr_memory_ranges >= max_memory_ranges) { if (realloc_memory_ranges() < 0) break; } start = be64_to_cpu(((uint64_t *)buf)[0]); end = start + be64_to_cpu(((uint64_t *)buf)[1]); add_base_memory_range(start, end); fclose(file); } closedir(dmem); } closedir(dir); sort_base_ranges(); memory_max = base_memory_range[nr_memory_ranges - 1].end; dbgprintf("get base memory ranges:%d\n", nr_memory_ranges); return 0; } /* Sort the exclude ranges in memory */ static int sort_ranges(void) { int i, j; uint64_t tstart, tend; for (i = 0; i < nr_exclude_ranges - 1; i++) { for (j = 0; j < nr_exclude_ranges - i - 1; j++) { if (exclude_range[j].start > exclude_range[j+1].start) { tstart = exclude_range[j].start; tend = exclude_range[j].end; exclude_range[j].start = exclude_range[j+1].start; exclude_range[j].end = exclude_range[j+1].end; exclude_range[j+1].start = tstart; exclude_range[j+1].end = tend; } } } return 0; } void scan_reserved_ranges(unsigned long kexec_flags, int *range_index) { char fname[256], buf[16]; FILE *file; int i = *range_index; strcpy(fname, "/proc/device-tree/reserved-ranges"); file = fopen(fname, "r"); if (file == NULL) { if (errno != ENOENT) { perror(fname); return; } errno = 0; /* File not present. Non PowerKVM system. */ return; } /* * Each reserved range is an (address,size) pair, 2 cells each, * totalling 4 cells per range. */ while (fread(buf, sizeof(uint64_t) * 2, 1, file) == 1) { uint64_t base, size; base = be64_to_cpu(((uint64_t *)buf)[0]); size = be64_to_cpu(((uint64_t *)buf)[1]); exclude_range[i].start = base; exclude_range[i].end = base + size; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); reserve(base, size); } fclose(file); *range_index = i; } /* Get devtree details and create exclude_range array * Also create usablemem_ranges for KEXEC_ON_CRASH */ static int get_devtree_details(unsigned long kexec_flags) { uint64_t rmo_base; uint64_t tce_base; unsigned int tce_size; uint64_t htab_base, htab_size; uint64_t kernel_end; uint64_t initrd_start, initrd_end; char buf[MAXBYTES]; char device_tree[256] = "/proc/device-tree/"; char fname[256]; DIR *dir, *cdir; FILE *file; struct dirent *dentry; struct stat fstat; int n, i = 0; if ((dir = opendir(device_tree)) == NULL) { perror(device_tree); return -1; } scan_reserved_ranges(kexec_flags, &i); while ((dentry = readdir(dir)) != NULL) { if (strncmp(dentry->d_name, "chosen", 6) && strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory") && strncmp(dentry->d_name, "pci@", 4) && strncmp(dentry->d_name, "rtas", 4) && strncmp(dentry->d_name, "ibm,opal", 8)) continue; strcpy(fname, device_tree); strcat(fname, dentry->d_name); if ((cdir = opendir(fname)) == NULL) { perror(fname); goto error_opendir; } if (strncmp(dentry->d_name, "chosen", 6) == 0) { strcat(fname, "/linux,kernel-end"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&kernel_end, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); kernel_end = be64_to_cpu(kernel_end); /* Add kernel memory to exclude_range */ exclude_range[i].start = 0x0UL; exclude_range[i].end = kernel_end; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); if (kexec_flags & KEXEC_ON_CRASH) { memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,crashkernel-base"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&crash_base, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); crash_base = be64_to_cpu(crash_base); memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,crashkernel-size"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&crash_size, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); crash_size = be64_to_cpu(crash_size); if (crash_base > mem_min) mem_min = crash_base; if (crash_base + crash_size < mem_max) mem_max = crash_base + crash_size; add_usable_mem_rgns(0, crash_base + crash_size); reserve(KDUMP_BACKUP_LIMIT, crash_base-KDUMP_BACKUP_LIMIT); } /* * Read the first kernel's memory limit. * If the first kernel is booted with mem= option then * it would export "linux,memory-limit" file * reflecting value for the same. */ memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,memory-limit"); if ((file = fopen(fname, "r")) == NULL) { if (errno != ENOENT) { perror(fname); goto error_opencdir; } errno = 0; /* * File not present. * fall through. On older kernel this file * is not present. */ } else { if (fread(&memory_limit, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); memory_limit = be64_to_cpu(memory_limit); } memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,htab-base"); if ((file = fopen(fname, "r")) == NULL) { closedir(cdir); if (errno == ENOENT) { /* Non LPAR */ errno = 0; continue; } perror(fname); goto error_opendir; } if (fread(&htab_base, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); htab_base = be64_to_cpu(htab_base); memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,htab-size"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&htab_size, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); htab_size = be64_to_cpu(htab_size); /* Add htab address to exclude_range - NON-LPAR only */ exclude_range[i].start = htab_base; exclude_range[i].end = htab_base + htab_size; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); /* reserve the initrd_start and end locations. */ if (reuse_initrd) { memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,initrd-start"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } /* check for 4 and 8 byte initrd offset sizes */ if (stat(fname, &fstat) != 0) { perror(fname); goto error_openfile; } if (fread(&initrd_start, fstat.st_size, 1, file) != 1) { perror(fname); goto error_openfile; } initrd_start = be64_to_cpu(initrd_start); fclose(file); memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,initrd-end"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } /* check for 4 and 8 byte initrd offset sizes */ if (stat(fname, &fstat) != 0) { perror(fname); goto error_openfile; } if (fread(&initrd_end, fstat.st_size, 1, file) != 1) { perror(fname); goto error_openfile; } initrd_end = be64_to_cpu(initrd_end); fclose(file); /* Add initrd address to exclude_range */ exclude_range[i].start = initrd_start; exclude_range[i].end = initrd_end; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); } } /* chosen */ if (strncmp(dentry->d_name, "rtas", 4) == 0) { strcat(fname, "/linux,rtas-base"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&rtas_base, sizeof(unsigned int), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); rtas_base = be32_to_cpu(rtas_base); memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/rtas-size"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&rtas_size, sizeof(unsigned int), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); closedir(cdir); rtas_size = be32_to_cpu(rtas_size); /* Add rtas to exclude_range */ exclude_range[i].start = rtas_base; exclude_range[i].end = rtas_base + rtas_size; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); if (kexec_flags & KEXEC_ON_CRASH) add_usable_mem_rgns(rtas_base, rtas_size); } /* rtas */ if (strncmp(dentry->d_name, "ibm,opal", 8) == 0) { strcat(fname, "/opal-base-address"); file = fopen(fname, "r"); if (file == NULL) { perror(fname); goto error_opencdir; } if (fread(&opal_base, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } opal_base = be64_to_cpu(opal_base); fclose(file); memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/opal-runtime-size"); file = fopen(fname, "r"); if (file == NULL) { perror(fname); goto error_opencdir; } if (fread(&opal_size, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); closedir(cdir); opal_size = be64_to_cpu(opal_size); /* Add OPAL to exclude_range */ exclude_range[i].start = opal_base; exclude_range[i].end = opal_base + opal_size; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); if (kexec_flags & KEXEC_ON_CRASH) add_usable_mem_rgns(opal_base, opal_size); } /* ibm,opal */ if (!strncmp(dentry->d_name, "memory@", 7) || !strcmp(dentry->d_name, "memory")) { strcat(fname, "/reg"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); goto error_openfile; } rmo_base = be64_to_cpu(((uint64_t *)buf)[0]); rmo_top = rmo_base + be64_to_cpu(((uint64_t *)buf)[1]); if (rmo_top > 0x30000000UL) rmo_top = 0x30000000UL; fclose(file); closedir(cdir); } /* memory */ if (strncmp(dentry->d_name, "pci@", 4) == 0) { strcat(fname, "/linux,tce-base"); if ((file = fopen(fname, "r")) == NULL) { closedir(cdir); if (errno == ENOENT) { /* Non LPAR */ errno = 0; continue; } perror(fname); goto error_opendir; } if (fread(&tce_base, sizeof(uint64_t), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); tce_base = be64_to_cpu(tce_base); memset(fname, 0, sizeof(fname)); strcpy(fname, device_tree); strcat(fname, dentry->d_name); strcat(fname, "/linux,tce-size"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); goto error_opencdir; } if (fread(&tce_size, sizeof(unsigned int), 1, file) != 1) { perror(fname); goto error_openfile; } fclose(file); tce_size = be32_to_cpu(tce_size); /* Add tce to exclude_range - NON-LPAR only */ exclude_range[i].start = tce_base; exclude_range[i].end = tce_base + tce_size; i++; if (i >= max_memory_ranges) realloc_memory_ranges(); if (kexec_flags & KEXEC_ON_CRASH) add_usable_mem_rgns(tce_base, tce_size); closedir(cdir); } /* pci */ } closedir(dir); nr_exclude_ranges = i; sort_ranges(); int k; for (k = 0; k < i; k++) dbgprintf("exclude_range sorted exclude_range[%d] " "start:%llx, end:%llx\n", k, exclude_range[k].start, exclude_range[k].end); return 0; error_openfile: fclose(file); error_opencdir: closedir(cdir); error_opendir: closedir(dir); return -1; } /* Setup a sorted list of memory ranges. */ int setup_memory_ranges(unsigned long kexec_flags) { int i, j = 0; /* Get the base list of memory ranges from /proc/device-tree/memory * nodes. Build list of ranges to be excluded from valid memory */ if (get_base_ranges()) goto out; if (get_devtree_details(kexec_flags)) goto out; for (i = 0; i < nr_exclude_ranges; i++) { /* If first exclude range does not start with 0, include the * first hole of valid memory from 0 - exclude_range[0].start */ if (i == 0) { if (exclude_range[i].start != 0) { memory_range[j].start = 0; memory_range[j].end = exclude_range[i].start - 1; memory_range[j].type = RANGE_RAM; j++; if (j >= max_memory_ranges) realloc_memory_ranges(); } } /* i == 0 */ /* If the last exclude range does not end at memory_max, include * the last hole of valid memory from exclude_range[last].end - * memory_max */ if (i == nr_exclude_ranges - 1) { if (exclude_range[i].end < memory_max) { memory_range[j].start = exclude_range[i].end + 1; memory_range[j].end = memory_max; memory_range[j].type = RANGE_RAM; j++; if (j >= max_memory_ranges) realloc_memory_ranges(); /* Limit the end to rmo_top */ if (memory_range[j-1].start >= rmo_top) { j--; break; } if ((memory_range[j-1].start < rmo_top) && (memory_range[j-1].end >= rmo_top)) { memory_range[j-1].end = rmo_top; break; } continue; } } /* i == nr_exclude_ranges - 1 */ /* contiguous exclude ranges - skip */ if (exclude_range[i+1].start == exclude_range[i].end + 1) continue; memory_range[j].start = exclude_range[i].end + 1; memory_range[j].end = exclude_range[i+1].start - 1; memory_range[j].type = RANGE_RAM; j++; if (j >= max_memory_ranges) realloc_memory_ranges(); /* Limit range to rmo_top */ if (memory_range[j-1].start >= rmo_top) { j--; break; } if ((memory_range[j-1].start < rmo_top) && (memory_range[j-1].end >= rmo_top)) { memory_range[j-1].end = rmo_top; break; } } nr_memory_ranges = j; int k; for (k = 0; k < j; k++) dbgprintf("setup_memory_ranges memory_range[%d] " "start:%llx, end:%llx\n", k, memory_range[k].start, memory_range[k].end); return 0; out: cleanup_memory_ranges(); return -1; } /* Return a list of valid memory ranges */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { /* allocate memory_range dynamically */ max_memory_ranges = 1; if (alloc_memory_ranges()) return -1; if (setup_memory_ranges(kexec_flags)) return -1; /* * copy the memory here, another realloc_memory_ranges might * corrupt the old memory */ *range = calloc(sizeof(struct memory_range), nr_memory_ranges); if (*range == NULL) return -1; memmove(*range, memory_range, sizeof(struct memory_range) * nr_memory_ranges); *ranges = nr_memory_ranges; dbgprintf("get memory ranges:%d\n", nr_memory_ranges); return 0; } struct file_type file_type[] = { { "elf-ppc64", elf_ppc64_probe, elf_ppc64_load, elf_ppc64_usage }, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { fprintf(stderr, " --elf64-core-headers Prepare core headers in ELF64 format\n"); } struct arch_options_t arch_options = { .core_header_type = CORE_TYPE_ELF64, }; int arch_process_options(int argc, char **argv) { /* We look for all options so getopt_long doesn't start reordering * argv[] before file_type[n].load() gets a look in. */ static const struct option options[] = { KEXEC_ALL_OPTIONS { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_ALL_OPT_STR; int opt; 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_ELF64_CORE: arch_options.core_header_type = CORE_TYPE_ELF64; break; } } /* Reset getopt for the next pass; called in other source modules */ opterr = 1; optind = 1; return 0; } const struct arch_map_entry arches[] = { /* We are running a 32-bit kexec-tools on 64-bit ppc64. * So pass KEXEC_ARCH_PPC64 here */ { "ppc64", KEXEC_ARCH_PPC64 }, { "ppc64le", KEXEC_ARCH_PPC64 }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } kexec-tools-2.0.10/kexec/arch/ppc64/crashdump-ppc64.c0000644001567400156740000003637712417126536021200 0ustar hormshorms/* * kexec: Linux boots Linux * * Created by: R Sharada (sharada@in.ibm.com) * Copyright (C) IBM Corporation, 2005. All rights reserved * * 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 #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "../../crashdump.h" #include "kexec-ppc64.h" #include "crashdump-ppc64.h" static struct crash_elf_info elf_info64 = { class: ELFCLASS64, #if BYTE_ORDER == LITTLE_ENDIAN data: ELFDATA2LSB, #else data: ELFDATA2MSB, #endif machine: EM_PPC64, page_offset: PAGE_OFFSET, lowmem_limit: MAXMEM, }; static struct crash_elf_info elf_info32 = { class: ELFCLASS32, data: ELFDATA2MSB, machine: EM_PPC64, page_offset: PAGE_OFFSET, lowmem_limit: MAXMEM, }; extern struct arch_options_t arch_options; /* Stores a sorted list of RAM memory ranges for which to create elf headers. * A separate program header is created for backup region */ static struct memory_range *crash_memory_range = NULL; /* Define a variable to replace the CRASH_MAX_MEMORY_RANGES macro */ static int crash_max_memory_ranges; /* * Used to save various memory ranges/regions needed for the captured * kernel to boot. (lime memmap= option in other archs) */ mem_rgns_t usablemem_rgns = {0, NULL}; static unsigned long long cstart, cend; static int memory_ranges; /* * Exclude the region that lies within crashkernel and above the memory * limit which is reflected by mem= kernel option. */ static void exclude_crash_region(uint64_t start, uint64_t end) { /* If memory_limit is set then exclude the memory region above it. */ if (memory_limit) { if (start >= memory_limit) return; if (end > memory_limit) end = memory_limit; } if (cstart < end && cend > start) { if (start < cstart && end > cend) { crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = cstart; crash_memory_range[memory_ranges].type = RANGE_RAM; memory_ranges++; crash_memory_range[memory_ranges].start = cend; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = RANGE_RAM; memory_ranges++; } else if (start < cstart) { crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = cstart; crash_memory_range[memory_ranges].type = RANGE_RAM; memory_ranges++; } else if (end > cend) { crash_memory_range[memory_ranges].start = cend; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = RANGE_RAM; memory_ranges++; } } else { crash_memory_range[memory_ranges].start = start; crash_memory_range[memory_ranges].end = end; crash_memory_range[memory_ranges].type = RANGE_RAM; memory_ranges++; } } static int get_dyn_reconf_crash_memory_ranges(void) { uint64_t start, end; char fname[128], buf[32]; FILE *file; unsigned int i; int n; uint32_t flags; strcpy(fname, "/proc/device-tree/"); strcat(fname, "ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); return -1; } fseek(file, 4, SEEK_SET); for (i = 0; i < num_of_lmbs; i++) { if ((n = fread(buf, 1, 24, file)) < 0) { perror(fname); fclose(file); return -1; } if (memory_ranges >= (max_memory_ranges + 1)) { /* No space to insert another element. */ fprintf(stderr, "Error: Number of crash memory ranges" " excedeed the max limit\n"); return -1; } start = be64_to_cpu(((uint64_t *)buf)[DRCONF_ADDR]); end = start + lmb_size; if (start == 0 && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; flags = be32_to_cpu((*((uint32_t *)&buf[DRCONF_FLAGS]))); /* skip this block if the reserved bit is set in flags (0x80) or if the block is not assigned to this partition (0x8) */ if ((flags & 0x80) || !(flags & 0x8)) continue; exclude_crash_region(start, end); } fclose(file); return 0; } /* Reads the appropriate file and retrieves the SYSTEM RAM regions for whom to * create Elf headers. Keeping it separate from get_memory_ranges() as * requirements are different in the case of normal kexec and crashdumps. * * Normal kexec needs to look at all of available physical memory irrespective * of the fact how much of it is being used by currently running kernel. * Crashdumps need to have access to memory regions actually being used by * running kernel. Expecting a different file/data structure than /proc/iomem * to look into down the line. May be something like /proc/kernelmem or may * be zone data structures exported from kernel. */ static int get_crash_memory_ranges(struct memory_range **range, int *ranges) { char device_tree[256] = "/proc/device-tree/"; char fname[256]; char buf[MAXBYTES]; DIR *dir, *dmem; FILE *file; struct dirent *dentry, *mentry; int i, n, crash_rng_len = 0; unsigned long long start, end; int page_size; crash_max_memory_ranges = max_memory_ranges + 6; crash_rng_len = sizeof(struct memory_range) * crash_max_memory_ranges; crash_memory_range = (struct memory_range *) malloc(crash_rng_len); if (!crash_memory_range) { fprintf(stderr, "Allocation for crash memory range failed\n"); return -1; } memset(crash_memory_range, 0, crash_rng_len); /* create a separate program header for the backup region */ crash_memory_range[0].start = BACKUP_SRC_START; crash_memory_range[0].end = BACKUP_SRC_END + 1; crash_memory_range[0].type = RANGE_RAM; memory_ranges++; if ((dir = opendir(device_tree)) == NULL) { perror(device_tree); goto err; } cstart = crash_base; cend = crash_base + crash_size; while ((dentry = readdir(dir)) != NULL) { if (!strncmp(dentry->d_name, "ibm,dynamic-reconfiguration-memory", 35)){ get_dyn_reconf_crash_memory_ranges(); continue; } if (strncmp(dentry->d_name, "memory@", 7) && strcmp(dentry->d_name, "memory")) continue; strcpy(fname, device_tree); strcat(fname, dentry->d_name); if ((dmem = opendir(fname)) == NULL) { perror(fname); closedir(dir); goto err; } while ((mentry = readdir(dmem)) != NULL) { if (strcmp(mentry->d_name, "reg")) continue; strcat(fname, "/reg"); if ((file = fopen(fname, "r")) == NULL) { perror(fname); closedir(dmem); closedir(dir); goto err; } if ((n = fread(buf, 1, MAXBYTES, file)) < 0) { perror(fname); fclose(file); closedir(dmem); closedir(dir); goto err; } if (memory_ranges >= (max_memory_ranges + 1)) { /* No space to insert another element. */ fprintf(stderr, "Error: Number of crash memory ranges" " excedeed the max limit\n"); goto err; } start = be64_to_cpu(((unsigned long long *)buf)[0]); end = start + be64_to_cpu(((unsigned long long *)buf)[1]); if (start == 0 && end >= (BACKUP_SRC_END + 1)) start = BACKUP_SRC_END + 1; exclude_crash_region(start, end); fclose(file); } closedir(dmem); } closedir(dir); /* * If RTAS region is overlapped with crashkernel, need to create ELF * Program header for the overlapped memory. */ if (crash_base < rtas_base + rtas_size && rtas_base < crash_base + crash_size) { page_size = getpagesize(); cstart = rtas_base; cend = rtas_base + rtas_size; if (cstart < crash_base) cstart = crash_base; if (cend > crash_base + crash_size) cend = crash_base + crash_size; /* * The rtas section created here is formed by reading rtas-base * and rtas-size from /proc/device-tree/rtas. Unfortunately * rtas-size is not required to be a multiple of PAGE_SIZE * The remainder of the page it ends on is just garbage, and is * safe to read, its just not accounted in rtas-size. Since * we're creating an elf section here though, lets round it up * to the next page size boundary though, so makedumpfile can * read it safely without going south on us. */ cend = _ALIGN(cend, page_size); crash_memory_range[memory_ranges].start = cstart; crash_memory_range[memory_ranges++].end = cend; } /* * If OPAL region is overlapped with crashkernel, need to create ELF * Program header for the overlapped memory. */ if (crash_base < opal_base + opal_size && opal_base < crash_base + crash_size) { page_size = getpagesize(); cstart = opal_base; cend = opal_base + opal_size; if (cstart < crash_base) cstart = crash_base; if (cend > crash_base + crash_size) cend = crash_base + crash_size; /* * The opal section created here is formed by reading opal-base * and opal-size from /proc/device-tree/ibm,opal. Unfortunately * opal-size is not required to be a multiple of PAGE_SIZE * The remainder of the page it ends on is just garbage, and is * safe to read, its just not accounted in opal-size. Since * we're creating an elf section here though, lets round it up * to the next page size boundary though, so makedumpfile can * read it safely without going south on us. */ cend = _ALIGN(cend, page_size); crash_memory_range[memory_ranges].start = cstart; crash_memory_range[memory_ranges++].end = cend; } *range = crash_memory_range; *ranges = memory_ranges; int j; dbgprintf("CRASH MEMORY RANGES\n"); for(j = 0; j < *ranges; j++) { start = crash_memory_range[j].start; end = crash_memory_range[j].end; dbgprintf("%016Lx-%016Lx\n", start, end); } return 0; err: if (crash_memory_range) free(crash_memory_range); return -1; } /* Converts unsigned long to ascii string. */ static void ultoa(uint64_t i, char *str) { int j = 0, k; char tmp; do { str[j++] = i % 10 + '0'; } while ((i /=10) > 0); str[j] = '\0'; /* Reverse the string. */ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { tmp = str[k]; str[k] = str[j]; str[j] = tmp; } } static int add_cmdline_param(char *cmdline, uint64_t addr, char *cmdstr, char *byte) { int cmdlen, len, align = 1024; char str[COMMAND_LINE_SIZE], *ptr; /* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/ switch (byte[0]) { case 'K': if (addr%align) return -1; addr = addr/align; break; case 'M': addr = addr/(align *align); break; } ptr = str; strcpy(str, cmdstr); ptr += strlen(str); ultoa(addr, ptr); strcat(str, byte); len = strlen(str); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str); dbgprintf("Command line after adding elfcorehdr: %s\n", cmdline); return 0; } /* Loads additional segments in case of a panic kernel is being loaded. * One segment for backup region, another segment for storing elf headers * for crash memory image. */ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, uint64_t max_addr, unsigned long min_base) { void *tmp; unsigned long sz; uint64_t elfcorehdr; int nr_ranges, align = 1024, i; unsigned long long end; struct memory_range *mem_range; if (get_crash_memory_ranges(&mem_range, &nr_ranges) < 0) return -1; info->backup_src_start = BACKUP_SRC_START; info->backup_src_size = BACKUP_SRC_SIZE; /* Create a backup region segment to store backup data*/ sz = _ALIGN(BACKUP_SRC_SIZE, align); tmp = xmalloc(sz); memset(tmp, 0, sz); info->backup_start = add_buffer(info, tmp, sz, sz, align, 0, max_addr, 1); reserve(info->backup_start, sz); /* On ppc64 memory ranges in device-tree is denoted as start * and size rather than start and end, as is the case with * other architectures like i386 . Because of this when loading * the memory ranges in crashdump-elf.c the filesz calculation * [ end - start + 1 ] goes for a toss. * * To be in sync with other archs adjust the end value for * every crash memory range before calling the generic function */ for (i = 0; i < nr_ranges; i++) { end = crash_memory_range[i].end - 1; crash_memory_range[i].end = end; } /* Create elf header segment and store crash image data. */ if (arch_options.core_header_type == CORE_TYPE_ELF64) { if (crash_create_elf64_headers(info, &elf_info64, crash_memory_range, nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) return -1; } else { if (crash_create_elf32_headers(info, &elf_info32, crash_memory_range, nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) return -1; } elfcorehdr = add_buffer(info, tmp, sz, sz, align, min_base, max_addr, 1); reserve(elfcorehdr, sz); /* modify and store the cmdline in a global array. This is later * read by flatten_device_tree and modified if required */ add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K"); return 0; } /* * Used to save various memory regions needed for the captured kernel. */ void add_usable_mem_rgns(unsigned long long base, unsigned long long size) { unsigned int i; unsigned long long end = base + size; unsigned long long ustart, uend; base = _ALIGN_DOWN(base, getpagesize()); end = _ALIGN_UP(end, getpagesize()); for (i=0; i < usablemem_rgns.size; i++) { ustart = usablemem_rgns.ranges[i].start; uend = usablemem_rgns.ranges[i].end; if (base < uend && end > ustart) { if ((base >= ustart) && (end <= uend)) return; if (base < ustart && end > uend) { usablemem_rgns.ranges[i].start = base; usablemem_rgns.ranges[i].end = end; #ifdef DEBUG fprintf(stderr, "usable memory rgn %u: new base:%llx new size:%llx\n", i, base, size); #endif return; } else if (base < ustart) { usablemem_rgns.ranges[i].start = base; #ifdef DEBUG fprintf(stderr, "usable memory rgn %u: new base:%llx new size:%llx", i, base, usablemem_rgns.ranges[i].end - base); #endif return; } else if (end > uend){ usablemem_rgns.ranges[i].end = end; #ifdef DEBUG fprintf(stderr, "usable memory rgn %u: new end:%llx, new size:%llx", i, end, end - usablemem_rgns.ranges[i].start); #endif return; } } } usablemem_rgns.ranges[usablemem_rgns.size].start = base; usablemem_rgns.ranges[usablemem_rgns.size++].end = end; dbgprintf("usable memory rgns size:%u base:%llx size:%llx\n", usablemem_rgns.size, base, size); } int is_crashkernel_mem_reserved(void) { int fd; fd = open("/proc/device-tree/chosen/linux,crashkernel-base", O_RDONLY); if (fd < 0) return 0; close(fd); return 1; } #if 0 static int sort_regions(mem_rgns_t *rgn) { int i, j; unsigned long long tstart, tend; for (i = 0; i < rgn->size; i++) { for (j = 0; j < rgn->size - i - 1; j++) { if (rgn->ranges[j].start > rgn->ranges[j+1].start) { tstart = rgn->ranges[j].start; tend = rgn->ranges[j].end; rgn->ranges[j].start = rgn->ranges[j+1].start; rgn->ranges[j].end = rgn->ranges[j+1].end; rgn->ranges[j+1].start = tstart; rgn->ranges[j+1].end = tend; } } } return 0; } #endif kexec-tools-2.0.10/kexec/arch/ppc64/kexec-ppc64.h0000644001567400156740000000170312417126536020277 0ustar hormshorms#ifndef KEXEC_PPC64_H #define KEXEC_PPC64_H #define MAXBYTES 128 #define MAX_LINE 160 #define CORE_TYPE_ELF32 1 #define CORE_TYPE_ELF64 2 #define BOOT_BLOCK_VERSION 17 #define BOOT_BLOCK_LAST_COMP_VERSION 17 #if (BOOT_BLOCK_VERSION < 16) # define NEED_STRUCTURE_BLOCK_EXTRA_PAD #endif #define HAVE_DYNAMIC_MEMORY #define NEED_RESERVE_DTB int setup_memory_ranges(unsigned long kexec_flags); 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); struct mem_ehdr; unsigned long my_r2(const struct mem_ehdr *ehdr); extern uint64_t initrd_base, initrd_size; extern int max_memory_ranges; extern unsigned char reuse_initrd; struct arch_options_t { int core_header_type; }; typedef struct mem_rgns { unsigned int size; struct memory_range *ranges; } mem_rgns_t; extern mem_rgns_t usablemem_rgns; #endif /* KEXEC_PPC64_H */ kexec-tools-2.0.10/kexec/arch/ppc64/crashdump-ppc64.h0000644001567400156740000000230212417126536021162 0ustar hormshorms#ifndef CRASHDUMP_PPC64_H #define CRASHDUMP_PPC64_H #include #include struct kexec_info; int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline, uint64_t max_addr, unsigned long min_base); void add_usable_mem_rgns(unsigned long long base, unsigned long long size); #define PAGE_OFFSET 0xC000000000000000ULL #define KERNELBASE PAGE_OFFSET #define VMALLOCBASE 0xD000000000000000ULL #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define MAXMEM (-KERNELBASE-VMALLOCBASE) #define COMMAND_LINE_SIZE 512 /* from kernel */ /* Backup Region, First 64K of System RAM. */ #define BACKUP_SRC_START 0x0000 #define BACKUP_SRC_END 0xffff #define BACKUP_SRC_SIZE (BACKUP_SRC_END - BACKUP_SRC_START + 1) #define KDUMP_BACKUP_LIMIT BACKUP_SRC_SIZE #define KERNEL_RUN_AT_ZERO_MAGIC 0x72756e30 /* "run0" */ extern uint64_t crash_base; extern uint64_t crash_size; extern uint64_t memory_limit; extern unsigned int rtas_base; extern unsigned int rtas_size; extern uint64_t opal_base; extern uint64_t opal_size; uint64_t lmb_size; unsigned int num_of_lmbs; #define DRCONF_ADDR 0 #define DRCONF_FLAGS 20 #endif /* CRASHDUMP_PPC64_H */ kexec-tools-2.0.10/kexec/arch/ppc64/include/arch/options.h0000644001567400156740000000342712417126536022306 0ustar hormshorms#ifndef KEXEC_ARCH_PPC64_OPTIONS_H #define KEXEC_ARCH_PPC64_OPTIONS_H #define OPT_ELF64_CORE (OPT_MAX+0) #define OPT_ARCH_MAX (OPT_MAX+1) /* All 'local' loader options: */ #define OPT_APPEND (OPT_ARCH_MAX+0) #define OPT_RAMDISK (OPT_ARCH_MAX+1) #define OPT_DEVICETREEBLOB (OPT_ARCH_MAX+2) #define OPT_ARGS_IGNORE (OPT_ARCH_MAX+3) /* Options relevant to the architecture (excluding loader-specific ones): */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ { "elf64-core-headers", 0, 0, OPT_ELF64_CORE }, \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ { "command-line", 1, NULL, OPT_APPEND }, \ { "append", 1, NULL, OPT_APPEND }, \ { "ramdisk", 1, NULL, OPT_RAMDISK }, \ { "initrd", 1, NULL, OPT_RAMDISK }, \ { "devicetreeblob", 1, NULL, OPT_DEVICETREEBLOB }, \ { "dtb", 1, NULL, OPT_DEVICETREEBLOB }, \ { "args-linux", 0, NULL, OPT_ARGS_IGNORE }, #define KEXEC_ALL_OPT_STR KEXEC_OPT_STR #endif /* KEXEC_ARCH_PPC64_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/s390/Makefile0000644001567400156740000000057111642166046017300 0ustar hormshorms# # kexec s390 (linux booting linux) # s390_KEXEC_SRCS = kexec/arch/s390/kexec-s390.c s390_KEXEC_SRCS += kexec/arch/s390/kexec-image.c s390_KEXEC_SRCS += kexec/arch/s390/kexec-elf-rel-s390.c s390_KEXEC_SRCS += kexec/arch/s390/crashdump-s390.c dist += kexec/arch/s390/Makefile $(s390_KEXEC_SRCS) \ kexec/arch/s390/kexec-s390.h \ kexec/arch/s390/include/arch/options.h kexec-tools-2.0.10/kexec/arch/s390/kexec-s390.c0000644001567400156740000001404211653441246017575 0ustar hormshorms/* * kexec/arch/s390/kexec-s390.c * * Copyright IBM Corp. 2005,2011 * * Author(s): Rolf Adelsberger * Michael Holzheu * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-s390.h" #include static struct memory_range memory_range[MAX_MEMORY_RANGES]; /* * Read string from file */ static void read_str(char *string, const char *path, size_t len) { size_t rc; FILE *fh; fh = fopen(path, "rb"); if (fh == NULL) die("Could not open \"%s\"", path); rc = fread(string, 1, len - 1, fh); if (rc == 0 && ferror(fh)) die("Could not read \"%s\"", path); fclose(fh); string[rc] = 0; if (string[strlen(string) - 1] == '\n') string[strlen(string) - 1] = 0; } /* * Return number of memory chunks */ static int memory_range_cnt(struct memory_range chunks[]) { int i; for (i = 0; i < MAX_MEMORY_RANGES; i++) { if (chunks[i].end == 0) break; } return i; } /* * Create memory hole with given address and size * * lh = local hole */ static void add_mem_hole(struct memory_range chunks[], unsigned long addr, unsigned long size) { unsigned long lh_start, lh_end, lh_size, chunk_cnt; int i; chunk_cnt = memory_range_cnt(chunks); for (i = 0; i < chunk_cnt; i++) { if (addr + size <= chunks[i].start) break; if (addr > chunks[i].end) continue; lh_start = MAX(addr, chunks[i].start); lh_end = MIN(addr + size - 1, chunks[i].end); lh_size = lh_end - lh_start + 1; if (lh_start == chunks[i].start && lh_end == chunks[i].end) { /* Remove chunk */ memmove(&chunks[i], &chunks[i + 1], sizeof(struct memory_range) * (MAX_MEMORY_RANGES - (i + 1))); memset(&chunks[MAX_MEMORY_RANGES - 1], 0, sizeof(struct memory_range)); chunk_cnt--; i--; } else if (lh_start == chunks[i].start) { /* Make chunk smaller at start */ chunks[i].start = chunks[i].start + lh_size; break; } else if (lh_end == chunks[i].end) { /* Make chunk smaller at end */ chunks[i].end = lh_start - 1; } else { /* Split chunk into two */ if (chunk_cnt >= MAX_MEMORY_RANGES) die("Unable to create memory hole: %i", i); memmove(&chunks[i + 1], &chunks[i], sizeof(struct memory_range) * (MAX_MEMORY_RANGES - (i + 1))); chunks[i + 1].start = lh_start + lh_size; chunks[i].end = lh_start - 1; break; } } } /* * Remove offline memory from memory chunks */ static void remove_offline_memory(struct memory_range memory_range[]) { unsigned long block_size, chunk_nr; struct dirent *dirent; char path[PATH_MAX]; char str[64]; DIR *dir; read_str(str, "/sys/devices/system/memory/block_size_bytes", sizeof(str)); sscanf(str, "%lx", &block_size); dir = opendir("/sys/devices/system/memory"); if (!dir) die("Could not read \"/sys/devices/system/memory\""); while ((dirent = readdir(dir))) { if (sscanf(dirent->d_name, "memory%ld\n", &chunk_nr) != 1) continue; sprintf(path, "/sys/devices/system/memory/%s/state", dirent->d_name); read_str(str, path, sizeof(str)); if (strncmp(str, "offline", 6) != 0) continue; add_mem_hole(memory_range, chunk_nr * block_size, block_size); } closedir(dir); } /* * Get memory ranges of type "System RAM" from /proc/iomem. If with_crashk=1 * then also type "Crash kernel" is added. */ int get_memory_ranges_s390(struct memory_range memory_range[], int *ranges, int with_crashk) { char crash_kernel[] = "Crash kernel\n"; char sys_ram[] = "System RAM\n"; const char *iomem = proc_iomem(); FILE *fp; char line[80]; int current_range = 0; fp = fopen(iomem,"r"); if(fp == 0) { fprintf(stderr,"Unable to open %s: %s\n",iomem,strerror(errno)); return -1; } /* Setup the compare string properly. */ while (fgets(line, sizeof(line), fp) != 0) { unsigned long long start, end; int cons; char *str; if (current_range == MAX_MEMORY_RANGES) break; sscanf(line,"%Lx-%Lx : %n", &start, &end, &cons); str = line+cons; if ((memcmp(str, sys_ram, strlen(sys_ram)) == 0) || ((memcmp(str, crash_kernel, strlen(crash_kernel)) == 0) && with_crashk)) { memory_range[current_range].start = start; memory_range[current_range].end = end; memory_range[current_range].type = RANGE_RAM; current_range++; } else { continue; } } fclose(fp); remove_offline_memory(memory_range); *ranges = memory_range_cnt(memory_range); return 0; } /* * get_memory_ranges: * Return a list of memory ranges by parsing the file returned by * proc_iomem() * * INPUT: * - Pointer to an array of memory_range structures. * - Pointer to an integer with holds the number of memory ranges. * * RETURN: * - 0 on normal execution. * - (-1) if something went wrong. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long flags) { uint64_t start, end; if (get_memory_ranges_s390(memory_range, ranges, flags & KEXEC_ON_CRASH)) return -1; *range = memory_range; if ((flags & KEXEC_ON_CRASH) && !(flags & KEXEC_PRESERVE_CONTEXT)) { if (parse_iomem_single("Crash kernel\n", &start, &end)) return -1; if (start > mem_min) mem_min = start; if (end < mem_max) mem_max = end; } return 0; } /* Supported file types and callbacks */ struct file_type file_type[] = { { "image", image_s390_probe, image_s390_load, image_s390_usage}, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { } int arch_process_options(int UNUSED(argc), char **UNUSED(argv)) { return 0; } const struct arch_map_entry arches[] = { { "s390", KEXEC_ARCH_S390 }, { "s390x", KEXEC_ARCH_S390 }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } int is_crashkernel_mem_reserved(void) { uint64_t start, end; return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ? (start != end) : 0; } kexec-tools-2.0.10/kexec/arch/s390/kexec-image.c0000644001567400156740000001030412417126536020157 0ustar hormshorms/* * kexec/arch/s390/kexec-image.c * * (C) Copyright IBM Corp. 2005 * * Author(s): Rolf Adelsberger * Heiko Carstens * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../kexec/crashdump.h" #include "kexec-s390.h" #include static uint64_t crash_base, crash_end; static char command_line[COMMAND_LINESIZE]; static void add_segment_check(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz) { if (info->kexec_flags & KEXEC_ON_CRASH) if (base + memsz > crash_end - crash_base) die("Not enough crashkernel memory to load segments\n"); add_segment(info, buf, bufsz, crash_base + base, memsz); } int command_line_add(const char *str) { if (strlen(command_line) + strlen(str) + 1 > COMMAND_LINESIZE) { fprintf(stderr, "Command line too long.\n"); return -1; } strcat(command_line, str); return 0; } int image_s390_load(int argc, char **argv, const char *kernel_buf, off_t kernel_size, struct kexec_info *info) { void *krnl_buffer; char *rd_buffer; const char *ramdisk; off_t ramdisk_len; unsigned int ramdisk_origin; int opt; static const struct option options[] = { KEXEC_OPTIONS {"command-line", 1, 0, OPT_APPEND}, {"append", 1, 0, OPT_APPEND}, {"initrd", 1, 0, OPT_RAMDISK}, {0, 0, 0, 0}, }; static const char short_options[] = KEXEC_OPT_STR ""; ramdisk = NULL; ramdisk_len = 0; ramdisk_origin = 0; while ((opt = getopt_long(argc,argv,short_options,options,0)) != -1) { switch(opt) { case OPT_APPEND: if (command_line_add(optarg)) return -1; break; case OPT_RAMDISK: ramdisk = optarg; break; } } if (info->kexec_flags & KEXEC_ON_CRASH) { if (parse_iomem_single("Crash kernel\n", &crash_base, &crash_end)) return -1; } /* Add kernel segment */ add_segment_check(info, kernel_buf + IMAGE_READ_OFFSET, kernel_size - IMAGE_READ_OFFSET, IMAGE_READ_OFFSET, kernel_size - IMAGE_READ_OFFSET); /* We do want to change the kernel image */ krnl_buffer = (void *) kernel_buf + IMAGE_READ_OFFSET; /* * Load ramdisk if present: If image is larger than RAMDISK_ORIGIN_ADDR, * we load the ramdisk directly behind the image with 1 MiB alignment. */ if (ramdisk) { rd_buffer = slurp_file(ramdisk, &ramdisk_len); if (rd_buffer == NULL) { fprintf(stderr, "Could not read ramdisk.\n"); return -1; } ramdisk_origin = MAX(RAMDISK_ORIGIN_ADDR, kernel_size); ramdisk_origin = _ALIGN_UP(ramdisk_origin, 0x100000); add_segment_check(info, rd_buffer, ramdisk_len, ramdisk_origin, ramdisk_len); } if (info->kexec_flags & KEXEC_ON_CRASH) { if (load_crashdump_segments(info, crash_base, crash_end)) return -1; } else { info->entry = (void *) IMAGE_READ_OFFSET; } /* Register the ramdisk and crashkernel memory in the kernel. */ { unsigned long long *tmp; tmp = krnl_buffer + INITRD_START_OFFS; *tmp = (unsigned long long) ramdisk_origin; tmp = krnl_buffer + INITRD_SIZE_OFFS; *tmp = (unsigned long long) ramdisk_len; if (info->kexec_flags & KEXEC_ON_CRASH) { tmp = krnl_buffer + OLDMEM_BASE_OFFS; *tmp = crash_base; tmp = krnl_buffer + OLDMEM_SIZE_OFFS; *tmp = crash_end - crash_base + 1; } } /* * We will write a probably given command line. * First, erase the old area, then setup the new parameters: */ if (strlen(command_line) != 0) { memset(krnl_buffer + COMMAND_LINE_OFFS, 0, COMMAND_LINESIZE); memcpy(krnl_buffer + COMMAND_LINE_OFFS, command_line, strlen(command_line)); } return 0; } int image_s390_probe(const char *UNUSED(kernel_buf), off_t UNUSED(kernel_size)) { /* * Can't reliably tell if an image is valid, * therefore everything is valid. */ return 0; } void image_s390_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=FILENAME Use the file FILENAME as a ramdisk.\n" ); } kexec-tools-2.0.10/kexec/arch/s390/kexec-elf-rel-s390.c0000644001567400156740000000404411642166046021122 0ustar hormshorms/* * kexec/arch/s390/kexec-elf-rel-s390.c * * Copyright IBM Corp. 2005,2011 * * Author(s): Heiko Carstens * */ #include #include #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_S390) return 0; return 1; } void machine_apply_elf_rel(struct mem_ehdr *ehdr, unsigned long r_type, void *loc, unsigned long address, unsigned long val) { switch (r_type) { case R_390_8: /* Direct 8 bit. */ case R_390_12: /* Direct 12 bit. */ case R_390_16: /* Direct 16 bit. */ case R_390_20: /* Direct 20 bit. */ case R_390_32: /* Direct 32 bit. */ case R_390_64: /* Direct 64 bit. */ if (r_type == R_390_8) *(unsigned char *) loc = val; else if (r_type == R_390_12) *(unsigned short *) loc = (val & 0xfff) | (*(unsigned short *) loc & 0xf000); else if (r_type == R_390_16) *(unsigned short *) loc = val; else if (r_type == R_390_20) *(unsigned int *) loc = (*(unsigned int *) loc & 0xf00000ff) | (val & 0xfff) << 16 | (val & 0xff000) >> 4; else if (r_type == R_390_32) *(unsigned int *) loc = val; else if (r_type == R_390_64) *(unsigned long *) loc = val; break; case R_390_PC16: /* PC relative 16 bit. */ case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */ case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */ case R_390_PC32: /* PC relative 32 bit. */ case R_390_PC64: /* PC relative 64 bit. */ val -= address; if (r_type == R_390_PC16) *(unsigned short *) loc = val; else if (r_type == R_390_PC16DBL) *(unsigned short *) loc = val >> 1; else if (r_type == R_390_PC32DBL) *(unsigned int *) loc = val >> 1; else if (r_type == R_390_PC32) *(unsigned int *) loc = val; else if (r_type == R_390_PC64) *(unsigned long *) loc = val; break; default: die("Unknown rela relocation: 0x%lx 0x%lx\n", r_type, address); break; } } kexec-tools-2.0.10/kexec/arch/s390/crashdump-s390.c0000644001567400156740000000437011671063204020461 0ustar hormshorms/* * kexec/arch/s390/crashdump-s390.c * * Copyright IBM Corp. 2011 * * Author(s): Michael Holzheu */ #ifdef __s390x__ #define _GNU_SOURCE #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../kexec/crashdump.h" #include "kexec-s390.h" /* * Create ELF core header */ static int create_elf_header(struct kexec_info *info, unsigned long crash_base, unsigned long crash_end) { #ifdef WITH_ELF_HEADER static struct memory_range crash_memory_range[MAX_MEMORY_RANGES]; unsigned long elfcorehdr, elfcorehdr_size, bufsz; struct crash_elf_info elf_info; char str[COMMAND_LINESIZE]; int ranges; void *tmp; memset(&elf_info, 0, sizeof(elf_info)); elf_info.data = ELFDATA2MSB; elf_info.machine = EM_S390; elf_info.class = ELFCLASS64; elf_info.get_note_info = get_crash_notes_per_cpu; if (get_memory_ranges_s390(crash_memory_range, &ranges, 0)) return -1; if (crash_create_elf64_headers(info, &elf_info, crash_memory_range, ranges, &tmp, &bufsz, ELF_CORE_HEADER_ALIGN)) return -1; elfcorehdr = add_buffer(info, tmp, bufsz, bufsz, 1024, crash_base, crash_end, -1); elfcorehdr_size = bufsz; snprintf(str, sizeof(str), " elfcorehdr=%ld@%ldK\n", elfcorehdr_size, elfcorehdr / 1024); command_line_add(str); #endif return 0; } /* * Load additional segments for kdump kernel */ int load_crashdump_segments(struct kexec_info *info, unsigned long crash_base, unsigned long crash_end) { unsigned long crash_size = crash_size = crash_end - crash_base + 1; if (create_elf_header(info, crash_base, crash_end)) return -1; elf_rel_build_load(info, &info->rhdr, (const char *) purgatory, purgatory_size, crash_base + 0x2000, crash_base + 0x10000, -1, 0); elf_rel_set_symbol(&info->rhdr, "crash_base", &crash_base, sizeof(crash_base)); elf_rel_set_symbol(&info->rhdr, "crash_size", &crash_size, sizeof(crash_size)); info->entry = (void *) elf_rel_get_addr(&info->rhdr, "purgatory_start"); return 0; } #else /* * kdump is not available for s390 */ int load_crashdump_segments(struct kexec_info *info, unsigned long crash_base, unsigned long crash_end) { return -1; } #endif kexec-tools-2.0.10/kexec/arch/s390/kexec-s390.h0000644001567400156740000000204612417126536017604 0ustar hormshorms/* * kexec/arch/s390/kexec-s390.h * * (C) Copyright IBM Corp. 2005 * * Author(s): Rolf Adelsberger * */ #ifndef KEXEC_S390_H #define KEXEC_S390_H #define IMAGE_READ_OFFSET 0x10000 #define RAMDISK_ORIGIN_ADDR 0x800000 #define INITRD_START_OFFS 0x408 #define INITRD_SIZE_OFFS 0x410 #define OLDMEM_BASE_OFFS 0x418 #define OLDMEM_SIZE_OFFS 0x420 #define COMMAND_LINE_OFFS 0x480 #define COMMAND_LINESIZE 896 #define MAX_MEMORY_RANGES 1024 #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) extern int image_s390_load(int, char **, const char *, off_t, struct kexec_info *); extern int image_s390_probe(const char *, off_t); extern void image_s390_usage(void); extern int load_crashdump_segments(struct kexec_info *info, unsigned long crash_base, unsigned long crash_end); extern int get_memory_ranges_s390(struct memory_range range[], int *ranges, int with_crashk); extern int command_line_add(const char *str); #endif /* KEXEC_S390_H */ kexec-tools-2.0.10/kexec/arch/s390/include/arch/options.h0000644001567400156740000000253211645021145022034 0ustar hormshorms#ifndef KEXEC_ARCH_S390_OPTIONS_H #define KEXEC_ARCH_S390_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) #define OPT_APPEND OPT_MAX+0 #define OPT_RAMDISK OPT_MAX+1 /* Options relevant to the architecture (excluding loader-specific ones), * in this case none: */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS \ KEXEC_ARCH_OPTIONS \ {"command-line", 1, 0, OPT_APPEND}, \ {"append", 1, 0, OPT_APPEND}, \ {"initrd", 1, 0, OPT_RAMDISK}, #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR #endif /* KEXEC_ARCH_S390_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/sh/Makefile0000644001567400156740000000122512242534555017212 0ustar hormshorms# # kexec sh (linux booting linux) # sh_KEXEC_SRCS += kexec/arch/sh/kexec-sh.c sh_KEXEC_SRCS += kexec/arch/sh/kexec-uImage-sh.c sh_KEXEC_SRCS += kexec/arch/sh/kexec-zImage-sh.c sh_KEXEC_SRCS += kexec/arch/sh/kexec-netbsd-sh.c sh_KEXEC_SRCS += kexec/arch/sh/kexec-elf-sh.c sh_KEXEC_SRCS += kexec/arch/sh/kexec-elf-rel-sh.c sh_KEXEC_SRCS += kexec/arch/sh/netbsd_booter.S sh_KEXEC_SRCS += kexec/arch/sh/crashdump-sh.c sh_UIMAGE = kexec/kexec-uImage.c sh_ADD_BUFFER = sh_ADD_SEGMENT = sh_VIRT_TO_PHYS = dist += kexec/arch/sh/Makefile $(sh_KEXEC_SRCS) \ kexec/arch/sh/kexec-sh.h \ kexec/arch/sh/crashdump-sh.h \ kexec/arch/sh/include/arch/options.h kexec-tools-2.0.10/kexec/arch/sh/kexec-sh.c0000644001567400156740000001441312473251174017427 0ustar hormshorms/* * kexec-sh.c - kexec for the SH * Copyright (C) 2004 kogiidena@eggplant.ddo.jp * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "kexec-sh.h" #include #define MAX_MEMORY_RANGES 64 static struct memory_range memory_range[MAX_MEMORY_RANGES]; static int kexec_sh_memory_range_callback(void *UNUSED(data), int nr, char *UNUSED(str), unsigned long long base, unsigned long long length) { if (nr < MAX_MEMORY_RANGES) { memory_range[nr].start = base; memory_range[nr].end = base + length - 1; memory_range[nr].type = RANGE_RAM; return 0; } return 1; } /* Return a sorted list of available memory ranges. */ int get_memory_ranges(struct memory_range **range, int *ranges, unsigned long kexec_flags) { int nr, ret; nr = kexec_iomem_for_each_line("System RAM\n", kexec_sh_memory_range_callback, NULL); *range = memory_range; *ranges = nr; /* * Redefine the memory region boundaries if kernel * exports the limits and if it is panic kernel. * Override user values only if kernel exported values are * subset of user defined values. */ if (kexec_flags & KEXEC_ON_CRASH) { unsigned long long start, end; ret = parse_iomem_single("Crash kernel\n", &start, &end); if (ret != 0) { fprintf(stderr, "parse_iomem_single failed.\n"); return -1; } if (start > mem_min) mem_min = start; if (end < mem_max) mem_max = end; } return 0; } /* Supported file types and callbacks */ struct file_type file_type[] = { /* uImage is probed before zImage because the latter also accepts uncompressed images. */ { "uImage-sh", uImage_sh_probe, uImage_sh_load, zImage_sh_usage }, { "zImage-sh", zImage_sh_probe, zImage_sh_load, zImage_sh_usage }, { "elf-sh", elf_sh_probe, elf_sh_load, elf_sh_usage }, { "netbsd-sh", netbsd_sh_probe, netbsd_sh_load, netbsd_sh_usage }, }; int file_types = sizeof(file_type) / sizeof(file_type[0]); void arch_usage(void) { printf( " none\n\n" "Default options:\n" " --append=\"%s\"\n" " STRING of --append is set from /proc/cmdline as default.\n" ,get_append()); } int arch_process_options(int argc, char **argv) { /* The common options amongst loaders (e.g. --append) should be read * here, and the loader-specific options (e.g. NetBSD stuff) should * then be re-parsed in the loader. * (e.g. in kexec-netbsd-sh.c, for example.) */ static const struct option options[] = { KEXEC_ALL_OPTIONS { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR; int opt; opterr = 0; /* Don't complain about unrecognized options here */ while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch(opt) { default: /* Ignore core options */ if (opt < OPT_MAX) { break; } case OPT_APPEND: case OPT_NBSD_HOWTO: case OPT_NBSD_MROOT: ; } } /* Reset getopt for the next pass; called in other source modules */ opterr = 1; optind = 1; return 0; } const struct arch_map_entry arches[] = { /* For compatibility with older patches * use KEXEC_ARCH_DEFAULT instead of KEXEC_ARCH_SH here. */ { "sh3", KEXEC_ARCH_DEFAULT }, { "sh4", KEXEC_ARCH_DEFAULT }, { "sh4a", KEXEC_ARCH_DEFAULT }, { "sh4al-dsp", KEXEC_ARCH_DEFAULT }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *UNUSED(info)) { } char append_buf[256]; char *get_append(void) { FILE *fp; int len; if((fp = fopen("/proc/cmdline", "r")) == NULL){ die("/proc/cmdline file open error !!\n"); } fgets(append_buf, 256, fp); len = strlen(append_buf); append_buf[len-1] = 0; fclose(fp); return append_buf; } void kexec_sh_setup_zero_page(char *zero_page_buf, size_t zero_page_size, char *cmd_line) { size_t n = zero_page_size - 0x100; memset(zero_page_buf, 0, zero_page_size); if (cmd_line) { if (n > strlen(cmd_line)) n = strlen(cmd_line); memcpy(zero_page_buf + 0x100, cmd_line, n); zero_page_buf[0x100 + n] = '\0'; } } static int is_32bit(void) { const char *cpuinfo = "/proc/cpuinfo"; char line[MAX_LINE]; FILE *fp; int status = 0; fp = fopen(cpuinfo, "r"); if (!fp) die("Cannot open %s\n", cpuinfo); while(fgets(line, sizeof(line), fp) != 0) { const char *key = "address sizes"; const char *value = " 32 bits physical"; char *p; if (strncmp(line, key, strlen(key))) continue; p = strchr(line + strlen(key), ':'); if (!p) continue; if (!strncmp(p + 1, value, strlen(value))) status = 1; break; } fclose(fp); return status; } unsigned long virt_to_phys(unsigned long addr) { unsigned long seg = addr & 0xe0000000; unsigned long long start = 0; int have_32bit = is_32bit(); if (seg != 0x80000000 && (have_32bit || seg != 0xc0000000)) die("Virtual address %p is not in P1%s\n", (void *)addr, have_32bit ? "" : " or P2"); /* If 32bit addressing is used then the base of system RAM * is an offset into physical memory. */ if (have_32bit) { unsigned long long end; int ret; /* Assume there is only one "System RAM" region */ ret = parse_iomem_single("System RAM\n", &start, &end); if (ret) die("Could not parse System RAM region " "in /proc/iomem\n"); } return addr - seg + start; } /* * add_segment() should convert base to a physical address on superh, * while the default is just to work with base as is */ void add_segment(struct kexec_info *info, const void *buf, size_t bufsz, unsigned long base, size_t memsz) { add_segment_phys_virt(info, buf, bufsz, base, memsz, 1); } /* * add_buffer() should convert base to a physical address on superh, * while the default is just to work with base as is */ 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) { return add_buffer_phys_virt(info, buf, bufsz, memsz, buf_align, buf_min, buf_max, buf_end, 1); } kexec-tools-2.0.10/kexec/arch/sh/kexec-uImage-sh.c0000644001567400156740000000112512242534555020631 0ustar hormshorms/* * uImage support added by Marc Andre Tanner * * Cloned from ARM by Paul Mundt, 2009. */ #include #include #include #include #include #include "../../kexec.h" #include "kexec-sh.h" int uImage_sh_probe(const char *buf, off_t len) { return uImage_probe_kernel(buf, len, IH_ARCH_SH); } int uImage_sh_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { return zImage_sh_load(argc, argv, buf + sizeof(struct image_header), len - sizeof(struct image_header), info); } kexec-tools-2.0.10/kexec/arch/sh/kexec-zImage-sh.c0000644001567400156740000000672212417126536020646 0ustar hormshorms/* * kexec-zImage-sh.c - kexec zImage loader for the SH * Copyright (C) 2005 kogiidena@eggplant.ddo.jp * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include #include "kexec-sh.h" static const int probe_debug = 0; #define HEAD32_KERNEL_START_ADDR 0 #define HEAD32_DECOMPRESS_KERNEL_ADDR 1 #define HEAD32_INIT_STACK_ADDR 2 #define HEAD32_INIT_SR 3 #define HEAD32_INIT_SR_VALUE 0x400000F0 static unsigned long zImage_head32(const char *buf, int offs) { unsigned long *values = (void *)buf; int k; for (k = (0x200 / 4) - 1; k > 0; k--) if (values[k] != 0x00090009) /* not nop + nop padding*/ return values[k - offs]; return 0; } /* * zImage_sh_probe - sanity check the elf image * * Make sure that the file image has a reasonable chance of working. */ int zImage_sh_probe(const char *buf, off_t UNUSED(len)) { if (memcmp(&buf[0x202], "HdrS", 4) != 0) return -1; if (zImage_head32(buf, HEAD32_INIT_SR) != HEAD32_INIT_SR_VALUE) return -1; return 0; } void zImage_sh_usage(void) { printf( " --append=STRING Set the kernel command line to STRING.\n" " --empty-zero=ADDRESS Set the kernel top ADDRESS. \n\n"); } int zImage_sh_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { char *command_line; int opt; unsigned long empty_zero, zero_page_base, zero_page_size, k; unsigned long image_base; char *param; static const struct option options[] = { KEXEC_ARCH_OPTIONS {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 OPT_APPEND: command_line = optarg; break; } } if (!command_line) command_line = get_append(); /* assume the zero page is the page before the vmlinux entry point. * we don't know the page size though, but 64k seems to be max. * put several 4k zero page copies before the entry point to cover * all combinations. */ empty_zero = zImage_head32(buf, HEAD32_KERNEL_START_ADDR); zero_page_size = 0x10000; zero_page_base = virt_to_phys(empty_zero - zero_page_size); while (!valid_memory_range(info, zero_page_base, zero_page_base + zero_page_size - 1)) { zero_page_base += 0x1000; zero_page_size -= 0x1000; if (zero_page_size == 0) die("Unable to determine zero page size from %p \n", (void *)empty_zero); } param = xmalloc(zero_page_size); for (k = 0; k < (zero_page_size / 0x1000); k++) kexec_sh_setup_zero_page(param + (k * 0x1000), 0x1000, command_line); add_segment(info, param, zero_page_size, 0x80000000 | zero_page_base, zero_page_size); /* load image a bit above the zero page, round up to 64k * the zImage will relocate itself, but only up seems supported. */ image_base = _ALIGN(empty_zero, 0x10000); add_segment(info, buf, len, image_base, len); info->entry = (void *)virt_to_phys(image_base); return 0; } kexec-tools-2.0.10/kexec/arch/sh/kexec-netbsd-sh.c0000644001567400156740000000627412417126536020713 0ustar hormshorms/* * kexec-netbsd-sh.c - kexec netbsd loader for the SH * Copyright (C) 2005 kogiidena@eggplant.ddo.jp * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include static const int probe_debug = 0; extern const unsigned char netbsd_booter[]; /* * netbsd_sh_probe - sanity check the elf image * * Make sure that the file image has a reasonable chance of working. */ int netbsd_sh_probe(const char *buf, off_t UNUSED(len)) { Elf32_Ehdr *ehdr; ehdr = (Elf32_Ehdr *)buf; if(memcmp(buf, ELFMAG, SELFMAG) != 0){ return -1; } if (ehdr->e_machine != EM_SH) { return -1; } return 0; } void netbsd_sh_usage(void) { printf( " --howto=VALUE NetBSD kernel boot option.\n" " --miniroot=FILE NetBSD miniroot ramdisk.\n\n"); } int netbsd_sh_load(int argc, char **argv, const char *buf, off_t UNUSED(len), struct kexec_info *info) { const char *howto, *miniroot; unsigned long entry, start, size, psz; char *miniroot_buf; off_t miniroot_length; unsigned int howto_value; unsigned char *param; unsigned long *paraml; unsigned char *img; int opt; static const struct option options[] = { KEXEC_ARCH_OPTIONS {0, 0, 0, 0}, }; static const char short_options[] = KEXEC_ARCH_OPT_STR ""; howto = miniroot = 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 OPT_NBSD_HOWTO: howto = optarg; break; case OPT_NBSD_MROOT: miniroot = optarg; break; } } /* howto */ howto_value = 0; if(howto){ howto_value = strtol(howto, NULL, 0); } psz = getpagesize(); /* Parse the Elf file */ { Elf32_Ehdr *ehdr; Elf32_Phdr *phdr; unsigned long bbs; ehdr = (Elf32_Ehdr *)buf; phdr = (Elf32_Phdr *)&buf[ehdr->e_phoff]; entry = ehdr->e_entry; img = (unsigned char *)&buf[phdr->p_offset]; start = (phdr->p_paddr) & 0x1fffffff; bbs = phdr->p_filesz; size = phdr->p_memsz; if(size < bbs){ size = bbs; } size = _ALIGN(size, psz); memset(&img[bbs], 0, size-bbs); add_segment(info, img, size, start, size); start += size; } /* miniroot file */ miniroot_buf = 0; if (miniroot) { miniroot_buf = slurp_file(miniroot, &miniroot_length); howto_value |= 0x200; size = _ALIGN(miniroot_length, psz); add_segment(info, miniroot_buf, size, start, size); start += size; } /* howto & bootinfo */ param = xmalloc(4096); memset(param, 0, 4096); paraml = (unsigned long *) ¶m[256]; memcpy(param, netbsd_booter, 256); paraml[0] = entry; paraml[1] = howto_value; add_segment(info, param, 4096, start, 4096); /* For now we don't have arguments to pass :( */ info->entry = (void *) (start | 0xa0000000); return 0; } kexec-tools-2.0.10/kexec/arch/sh/kexec-elf-sh.c0000644001567400156740000000664012417126536020177 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) 2008 Magnus Damm * * Based on x86 implementation, * 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 #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../kexec-elf.h" #include "../../kexec-elf-boot.h" #include #include "crashdump-sh.h" #include "kexec-sh.h" int elf_sh_probe(const char *buf, off_t len) { struct mem_ehdr ehdr; int result; result = build_elf_exec_info(buf, len, &ehdr, 0); if (result < 0) goto out; /* Verify the architecuture specific bits */ if (ehdr.e_machine != EM_SH) { result = -1; goto out; } result = 0; out: free_elf_info(&ehdr); return result; } void elf_sh_usage(void) { printf(" --append=STRING Set the kernel command line to STRING\n" ); } int elf_sh_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { struct mem_ehdr ehdr; char *command_line; char *modified_cmdline; struct mem_sym sym; int opt, rc; static const struct option options[] = { KEXEC_ARCH_OPTIONS { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_OPT_STR ""; /* * Parse the command line arguments */ command_line = modified_cmdline = 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 OPT_APPEND: command_line = optarg; break; } } /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (command_line) { strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } } /* Load the ELF executable */ elf_exec_build_load(info, &ehdr, buf, len, 0); info->entry = (void *)virt_to_phys(ehdr.e_entry); /* If panic kernel is being loaded, additional segments need * to be created. */ if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) { rc = load_crashdump_segments(info, modified_cmdline); if (rc < 0) return -1; /* Use new command line. */ command_line = modified_cmdline; } /* If we're booting a vmlinux then fill in empty_zero_page */ if (elf_rel_find_symbol(&ehdr, "empty_zero_page", &sym) == 0) { char *zp = (void *)ehdr.e_shdr[sym.st_shndx].sh_data; kexec_sh_setup_zero_page(zp, 4096, command_line); } return 0; } kexec-tools-2.0.10/kexec/arch/sh/kexec-elf-rel-sh.c0000644001567400156740000000244211642166046020752 0ustar hormshorms/* * kexec-elf-rel-sh.c - ELF relocations for SuperH * Copyright (C) 2008 Paul Mundt * * Based on the SHcompact module loader (arch/sh/kernel/module.c) in the * Linux kernel, which is written by: * * Copyright (C) 2003 - 2008 Kaz Kojima & Paul Mundt * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #include #include #include "../../kexec.h" #include "../../kexec-elf.h" int machine_verify_elf_rel(struct mem_ehdr *ehdr) { /* Intentionally don't bother with endianness validation, it's * configurable */ if (ehdr->ei_class != ELFCLASS32) return 0; if (ehdr->e_machine != EM_SH) return 0; return 1; } void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr), unsigned long r_type, void *orig_loc, unsigned long UNUSED(address), unsigned long relocation) { uint32_t *location = orig_loc; uint32_t value; switch (r_type) { case R_SH_DIR32: value = get_unaligned(location); value += relocation; put_unaligned(value, location); break; case R_SH_REL32: relocation = (relocation - (uint32_t)location); value = get_unaligned(location); value += relocation; put_unaligned(value, location); break; default: die("Unknown rela relocation: %lu\n", r_type); break; } } kexec-tools-2.0.10/kexec/arch/sh/netbsd_booter.S0000644001567400156740000000122411424244110020510 0ustar hormshorms .globl netbsd_booter netbsd_booter: mov.l ccr,r0 mov #0,r1 mov.l r1,@r0 nop nop nop nop nop nop nop nop nop nop mova netbsd_start,r0 mov.l @r0,r1 add #4,r0 mov.l @r0,r4 ! howto add #4,r0 mov r0,r5 ! bootinfo jmp @r1 nop nop nop .align 4 ccr: .long 0xff00001c .align 8 netbsd_start: .long 0x8c001000 .long 0x200 ! howto .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo .long 0 ! bootinfo kexec-tools-2.0.10/kexec/arch/sh/crashdump-sh.c0000644001567400156740000001026712473251174020321 0ustar hormshorms/* * crashdump-sh.c - crashdump for SuperH * Copyright (C) 2008 Magnus Damm * * Based on x86 and ppc64 implementation, written by * Vivek Goyal (vgoyal@in.ibm.com), R Sharada (sharada@in.ibm.com) * Copyright (C) IBM Corporation, 2005. All rights reserved * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-elf-boot.h" #include "../../kexec-syscall.h" #include "../../crashdump.h" #include "kexec-sh.h" #include "crashdump-sh.h" #include #define CRASH_MAX_MEMORY_RANGES 64 static struct memory_range crash_memory_range[CRASH_MAX_MEMORY_RANGES]; static int crash_sh_range_nr; static int crash_sh_memory_range_callback(void *UNUSED(data), int UNUSED(nr), char *str, unsigned long long base, unsigned long long length) { struct memory_range *range = crash_memory_range; struct memory_range *range2 = crash_memory_range; range += crash_sh_range_nr; if (crash_sh_range_nr >= CRASH_MAX_MEMORY_RANGES) { return 1; } if (strncmp(str, "System RAM\n", 11) == 0) { range->start = base; range->end = base + length - 1; range->type = RANGE_RAM; crash_sh_range_nr++; } if (strncmp(str, "Crash kernel\n", 13) == 0) { if (!crash_sh_range_nr) die("Unsupported /proc/iomem format\n"); range2 = range - 1; if ((base + length - 1) < range2->end) { range->start = base + length; range->end = range2->end; range->type = RANGE_RAM; crash_sh_range_nr++; } range2->end = base - 1; } return 0; } /* Return a sorted list of available memory ranges. */ static int crash_get_memory_ranges(struct memory_range **range, int *ranges) { crash_sh_range_nr = 0; kexec_iomem_for_each_line(NULL, crash_sh_memory_range_callback, NULL); *range = crash_memory_range; *ranges = crash_sh_range_nr; return 0; } static struct crash_elf_info elf_info32 = { class: ELFCLASS32, data: ELFDATA2LSB, machine: EM_SH, page_offset: PAGE_OFFSET, }; /* Converts unsigned long to ascii string. */ static void ultoa(unsigned long i, char *str) { int j = 0, k; char tmp; do { str[j++] = i % 10 + '0'; } while ((i /=10) > 0); str[j] = '\0'; /* Reverse the string. */ for (j = 0, k = strlen(str) - 1; j < k; j++, k--) { tmp = str[k]; str[k] = str[j]; str[j] = tmp; } } static int add_cmdline_param(char *cmdline, uint64_t addr, char *cmdstr, char *byte) { int cmdlen, len, align = 1024; char str[COMMAND_LINE_SIZE], *ptr; /* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/ switch (byte[0]) { case 'K': if (addr%align) return -1; addr = addr/align; break; case 'M': addr = addr/(align *align); break; } ptr = str; strcpy(str, cmdstr); ptr += strlen(str); ultoa(addr, ptr); strcat(str, byte); len = strlen(str); cmdlen = strlen(cmdline) + len; if (cmdlen > (COMMAND_LINE_SIZE - 1)) die("Command line overflow\n"); strcat(cmdline, str); dbgprintf("Command line after adding elfcorehdr: %s\n", cmdline); return 0; } /* Loads additional segments in case of a panic kernel is being loaded. * One segment for storing elf headers for crash memory image. */ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline) { void *tmp; unsigned long sz, elfcorehdr; int nr_ranges; struct memory_range *mem_range; if (crash_get_memory_ranges(&mem_range, &nr_ranges) < 0) return -1; if (crash_create_elf32_headers(info, &elf_info32, mem_range, nr_ranges, &tmp, &sz, ELF_CORE_HEADER_ALIGN) < 0) return -1; elfcorehdr = add_buffer_phys_virt(info, tmp, sz, sz, 1024, 0, 0xffffffff, -1, 0); dbgprintf("Created elf header segment at 0x%lx\n", elfcorehdr); add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K"); add_cmdline_param(mod_cmdline, elfcorehdr - mem_min, " mem=", "K"); return 0; } int is_crashkernel_mem_reserved(void) { uint64_t start, end; return parse_iomem_single("Crash kernel\n", &start, &end) == 0 ? (start != end) : 0; } kexec-tools-2.0.10/kexec/arch/sh/kexec-sh.h0000644001567400156740000000157411642166046017440 0ustar hormshorms#ifndef KEXEC_SH_H #define KEXEC_SH_H #define COMMAND_LINE_SIZE 2048 int uImage_sh_probe(const char *buf, off_t len); int uImage_sh_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); int zImage_sh_probe(const char *buf, off_t len); int zImage_sh_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void zImage_sh_usage(void); int elf_sh_probe(const char *buf, off_t len); int elf_sh_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void elf_sh_usage(void); int netbsd_sh_probe(const char *buf, off_t len); int netbsd_sh_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void netbsd_sh_usage(void); char *get_append(void); void kexec_sh_setup_zero_page(char *zero_page_buf, size_t zero_page_size, char *cmd_line); #endif /* KEXEC_SH_H */ kexec-tools-2.0.10/kexec/arch/sh/crashdump-sh.h0000644001567400156740000000031011424244110020275 0ustar hormshorms#ifndef CRASHDUMP_SH_H #define CRASHDUMP_SH_H struct kexec_info; int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline); #define PAGE_OFFSET 0x80000000 #endif /* CRASHDUMP_SH_H */ kexec-tools-2.0.10/kexec/arch/sh/include/arch/options.h0000644001567400156740000000333012417126536021755 0ustar hormshorms#ifndef KEXEC_ARCH_SH_OPTIONS_H #define KEXEC_ARCH_SH_OPTIONS_H #define OPT_ARCH_MAX (OPT_MAX+0) #define OPT_APPEND (OPT_ARCH_MAX+1) #define OPT_EMPTYZERO (OPT_ARCH_MAX+2) #define OPT_NBSD_HOWTO (OPT_ARCH_MAX+3) #define OPT_NBSD_MROOT (OPT_ARCH_MAX+4) /* Options relevant to the architecture (excluding loader-specific ones): */ #define KEXEC_ARCH_OPTIONS \ KEXEC_OPTIONS \ {"command-line", 1, 0, OPT_APPEND}, \ {"append", 1, 0, OPT_APPEND}, \ {"empty-zero", 1, 0, OPT_APPEND}, \ {"howto", 1, 0, OPT_NBSD_HOWTO}, \ {"miniroot", 1, 0, OPT_NBSD_MROOT}, /* These options seem to be loader-specific rather than superh-specific, so * ought to be moved to KEXEC_ALL_OPTIONS below and parsed in the relevant * loader, e.g. kexec-netbsd-sh.c */ #define KEXEC_ARCH_OPT_STR KEXEC_OPT_STR "" /* The following two #defines list ALL of the options added by all of the * architecture's loaders. * o main() uses this complete list to scan for its options, ignoring * arch-specific/loader-specific ones. * o Then, arch_process_options() uses this complete list to scan for its * options, ignoring general/loader-specific ones. * o Then, the file_type[n].load re-scans for options, using * KEXEC_ARCH_OPTIONS plus its loader-specific options subset. * Any unrecognised options cause an error here. * * This is done so that main()'s/arch_process_options()'s getopt_long() calls * don't choose a kernel filename from random arguments to options they don't * recognise -- as they now recognise (if not act upon) all possible options. */ #define KEXEC_ALL_OPTIONS KEXEC_ARCH_OPTIONS #define KEXEC_ALL_OPT_STR KEXEC_ARCH_OPT_STR #endif /* KEXEC_ARCH_SH_OPTIONS_H */ kexec-tools-2.0.10/kexec/arch/x86_64/Makefile0000644001567400156740000000174312242534555017543 0ustar hormshorms# # kexec x86_64 (linux booting linux) # x86_64_KEXEC_SRCS = kexec/arch/i386/kexec-elf-x86.c x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-bzImage.c x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-multiboot-x86.c x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-beoboot-x86.c x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-nbi.c x86_64_KEXEC_SRCS += kexec/arch/i386/x86-linux-setup.c x86_64_KEXEC_SRCS += kexec/arch/i386/kexec-x86-common.c x86_64_KEXEC_SRCS += kexec/arch/i386/crashdump-x86.c x86_64_KEXEC_SRCS_native = kexec/arch/x86_64/kexec-x86_64.c x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-x86_64.c x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-elf-rel-x86_64.c x86_64_KEXEC_SRCS_native += kexec/arch/x86_64/kexec-bzImage64.c x86_64_KEXEC_SRCS += $(x86_64_KEXEC_SRCS_native) # Don't add sources in i386/ to dist, as i386/Makefile adds them dist += kexec/arch/x86_64/Makefile $(x86_64_KEXEC_SRCS_native) \ kexec/arch/x86_64/kexec-x86_64.h \ kexec/arch/x86_64/include/arch/options.h kexec-tools-2.0.10/kexec/arch/x86_64/kexec-x86_64.c0000644001567400156740000001237712417126536020307 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "kexec-x86_64.h" #include "../i386/crashdump-x86.h" #include 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 }, { "bzImage64", bzImage64_probe, bzImage64_load, bzImage64_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= Specify the serial port for debug output\n" " --serial-baud= Specify the serial port baud rate\n" " --console-vga Enable the vga console\n" " --console-serial Enable the serial console\n" " --pass-memmap-cmdline Pass memory map via command line in kexec on panic case\n" " --noefi Disable efi support\n" ); } struct arch_options_t arch_options = { .reset_vga = 0, .serial_base = 0x3f8, .serial_baud = 0, .console_vga = 0, .console_serial = 0, .core_header_type = CORE_TYPE_ELF64, .pass_memmap_cmdline = 0, .noefi = 0, }; int arch_process_options(int argc, char **argv) { static const struct option options[] = { KEXEC_ALL_OPTIONS { 0, 0, NULL, 0 }, }; static const char short_options[] = KEXEC_ALL_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; case OPT_PASS_MEMMAP_CMDLINE: arch_options.pass_memmap_cmdline = 1; break; case OPT_NOEFI: arch_options.noefi = 1; break; } } /* Reset getopt for the next pass; called in other source modules */ opterr = 1; optind = 1; return 0; } const struct arch_map_entry arches[] = { { "x86_64", KEXEC_ARCH_X86_64 }, { NULL, 0 }, }; int arch_compat_trampoline(struct kexec_info *UNUSED(info)) { return 0; } void arch_update_purgatory(struct kexec_info *info) { uint8_t panic_kernel = 0; 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)); elf_rel_set_symbol(&info->rhdr, "backup_src_start", &info->backup_src_start, sizeof(info->backup_src_start)); elf_rel_set_symbol(&info->rhdr, "backup_src_size", &info->backup_src_size, sizeof(info->backup_src_size)); if (info->kexec_flags & KEXEC_ON_CRASH) { panic_kernel = 1; elf_rel_set_symbol(&info->rhdr, "backup_start", &info->backup_start, sizeof(info->backup_start)); } elf_rel_set_symbol(&info->rhdr, "panic_kernel", &panic_kernel, sizeof(panic_kernel)); } kexec-tools-2.0.10/kexec/arch/x86_64/kexec-elf-x86_64.c0000644001567400156740000001726612417126536021055 0ustar hormshorms/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-syscall.h" #include "../../kexec-elf.h" #include "../../kexec-elf-boot.h" #include "../i386/x86-linux-setup.h" #include "kexec-x86_64.h" #include "../i386/crashdump-x86.h" #include 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, 0); 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" " --reuse-cmdline Use kernel command line from running system.\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 *append = NULL; char *command_line = NULL, *modified_cmdline; char *tmp_cmdline = NULL; 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; int result = 0; char *error_msg = NULL; /* See options.h and add any new options there too! */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, NULL, OPT_APPEND }, { "append", 1, NULL, OPT_APPEND }, { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, { "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; modified_cmdline = 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 OPT_APPEND: append = optarg; break; case OPT_REUSE_CMDLINE: tmp_cmdline = get_command_line(); 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 = concat_cmdline(tmp_cmdline, append); if (tmp_cmdline) free(tmp_cmdline); command_line_len = 0; if (command_line) { command_line_len = strlen(command_line) +1; } /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & KEXEC_ON_CRASH) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (command_line) { strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } } /* Load the ELF executable */ elf_exec_build_load(info, &ehdr, buf, len, 0); 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, 0); } 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) { error_msg = "Ramdisks not supported with generic elf arguments"; goto out; } } else if (arg_style == ARG_STYLE_LINUX) { struct x86_linux_faked_param_header *hdr; unsigned long param_base; char *ramdisk_buf; off_t ramdisk_length; struct entry64_regs regs; int rc=0; /* 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) { ramdisk_buf = slurp_file(ramdisk, &ramdisk_length); } /* If panic kernel is being loaded, additional segments need * to be created. */ if (info->kexec_flags & KEXEC_ON_CRASH) { rc = load_crashdump_segments(info, modified_cmdline, max_addr, 0); if (rc < 0) { result = -1; goto out; } /* Use new command line. */ free(command_line); command_line = modified_cmdline; command_line_len = strlen(modified_cmdline) + 1; modified_cmdline = NULL; } /* 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(info, &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 { error_msg = "Unknown argument style\n"; } out: free(command_line); free(modified_cmdline); if (error_msg) die(error_msg); return result; } kexec-tools-2.0.10/kexec/arch/x86_64/kexec-elf-rel-x86_64.c0000644001567400156740000000351112520551445021615 0ustar hormshorms#include #include #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(r_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 *UNUSED(ehdr), unsigned long r_type, void *location, unsigned long address, unsigned long value) { dbgprintf("%s\n", reloc_name(r_type)); 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: %s\n", reloc_name(r_type)); break; } return; overflow: die("overflow in relocation type %s val %lx\n", reloc_name(r_type), value); } kexec-tools-2.0.10/kexec/arch/x86_64/kexec-bzImage64.c0000644001567400156740000002660112417126536021074 0ustar hormshorms/* * kexec: Linux boots Linux * * Copyright (C) 2003-2010 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" #include "kexec-x86_64.h" #include "../i386/x86-linux-setup.h" #include "../i386/crashdump-x86.h" #include static const int probe_debug = 0; int bzImage_support_efi_boot; int bzImage64_probe(const char *buf, off_t len) { const struct x86_linux_header *header; if ((uintmax_t)len < (uintmax_t)(2 * 512)) { if (probe_debug) fprintf(stderr, "File is too short to be a bzImage!\n"); return -1; } header = (const struct x86_linux_header *)buf; 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 < 0x020C) { if (probe_debug) fprintf(stderr, "Must be at least protocol version 2.12\n"); /* Must be at least protocol version 2.12 */ return -1; } if ((header->loadflags & 1) == 0) { if (probe_debug) fprintf(stderr, "zImage not a bzImage\n"); /* Not a bzImage */ return -1; } if ((header->xloadflags & 3) != 3) { if (probe_debug) fprintf(stderr, "Not a relocatable bzImage64\n"); /* Must be KERNEL_64 and CAN_BE_LOADED_ABOVE_4G */ return -1; } #define XLF_EFI_KEXEC (1 << 4) if ((header->xloadflags & XLF_EFI_KEXEC) == XLF_EFI_KEXEC) bzImage_support_efi_boot = 1; /* I've got a relocatable bzImage64 */ if (probe_debug) fprintf(stderr, "It's a relocatable bzImage64\n"); return 0; } void bzImage64_usage(void) { printf( " --entry-32bit Use the kernels 32bit entry point.\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" " --reuse-cmdline Use kernel command line from running system.\n" " --initrd=FILE Use FILE as the kernel's initial ramdisk.\n" " --ramdisk=FILE Use FILE as the kernel's initial ramdisk.\n" ); } static int do_bzImage64_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) { struct x86_linux_header setup_header; struct x86_linux_param_header *real_mode; int setup_sects; size_t size; int kern16_size; unsigned long setup_base, setup_size, setup_header_size; struct entry64_regs regs64; char *modified_cmdline; unsigned long cmdline_end; unsigned long align, addr, k_size; unsigned kern16_size_needed; /* * Find out about the file I am about to load. */ if ((uintmax_t)kernel_len < (uintmax_t)(2 * 512)) 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; if (kernel_len < kern16_size) { fprintf(stderr, "BzImage truncated?\n"); return -1; } if ((uintmax_t)command_line_len > (uintmax_t)setup_header.cmdline_size) { dbgprintf("Kernel command line too long for kernel!\n"); return -1; } /* Need to append some command line parameters internally in case of * taking crash dumps. */ if (info->kexec_flags & (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT)) { modified_cmdline = xmalloc(COMMAND_LINE_SIZE); memset((void *)modified_cmdline, 0, COMMAND_LINE_SIZE); if (command_line) { strncpy(modified_cmdline, command_line, COMMAND_LINE_SIZE); modified_cmdline[COMMAND_LINE_SIZE - 1] = '\0'; } /* If panic kernel is being loaded, additional segments need * to be created. load_crashdump_segments will take care of * loading the segments as high in memory as possible, hence * in turn as away as possible from kernel to avoid being * stomped by the kernel. */ if (load_crashdump_segments(info, modified_cmdline, -1, 0) < 0) return -1; /* Use new command line buffer */ command_line = modified_cmdline; command_line_len = strlen(command_line) + 1; } /* x86_64 purgatory could be anywhere */ elf_rel_build_load(info, &info->rhdr, purgatory, purgatory_size, 0x3000, -1, -1, 0); dbgprintf("Loaded purgatory at addr 0x%lx\n", info->rhdr.rel_addr); /* The argument/parameter segment */ kern16_size_needed = kern16_size; if (kern16_size_needed < 4096) kern16_size_needed = 4096; setup_size = kern16_size_needed + command_line_len + PURGATORY_CMDLINE_SIZE; real_mode = xmalloc(setup_size); memset(real_mode, 0, setup_size); /* only copy setup_header */ setup_header_size = kernel[0x201] + 0x202 - 0x1f1; if (setup_header_size > 0x7f) setup_header_size = 0x7f; memcpy((unsigned char *)real_mode + 0x1f1, kernel + 0x1f1, setup_header_size); /* No real mode code will be executing. setup segment can be loaded * anywhere as we will be just reading command line. */ setup_base = add_buffer(info, real_mode, setup_size, setup_size, 16, 0x3000, -1, -1); dbgprintf("Loaded real_mode_data and command line at 0x%lx\n", setup_base); /* The main kernel segment */ k_size = kernel_len - kern16_size; /* need to use run-time size for buffer searching */ dbgprintf("kernel init_size 0x%x\n", real_mode->init_size); size = _ALIGN(real_mode->init_size, 4096); align = real_mode->kernel_alignment; addr = add_buffer(info, kernel + kern16_size, k_size, size, align, 0x100000, -1, -1); if (addr == ULONG_MAX) die("can not load bzImage64"); dbgprintf("Loaded 64bit kernel at 0x%lx\n", addr); /* Tell the kernel what is going on */ setup_linux_bootloader_parameters_high(info, real_mode, setup_base, kern16_size_needed, command_line, command_line_len, initrd, initrd_len, 1); /* put initrd high too */ elf_rel_get_symbol(&info->rhdr, "entry64_regs", ®s64, sizeof(regs64)); regs64.rbx = 0; /* Bootstrap processor */ regs64.rsi = setup_base; /* Pointer to the parameters */ regs64.rip = addr + 0x200; /* the entry point for startup_64 */ regs64.rsp = elf_rel_get_addr(&info->rhdr, "stack_end"); /* Stack, unused */ elf_rel_set_symbol(&info->rhdr, "entry64_regs", ®s64, sizeof(regs64)); cmdline_end = setup_base + kern16_size_needed + command_line_len - 1; elf_rel_set_symbol(&info->rhdr, "cmdline_end", &cmdline_end, sizeof(unsigned long)); /* Fill in the information BIOS calls would normally provide. */ setup_linux_system_parameters(info, real_mode); return 0; } /* This assumes file is being loaded using file based kexec syscall */ int bzImage64_load_file(int argc, char **argv, struct kexec_info *info) { int ret = 0; char *command_line = NULL, *tmp_cmdline = NULL; const char *ramdisk = NULL, *append = NULL; int entry_16bit = 0, entry_32bit = 0; int opt; int command_line_len; /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "reuse-cmdline", 0, 0, OPT_REUSE_CMDLINE }, { "initrd", 1, 0, OPT_RAMDISK }, { "ramdisk", 1, 0, OPT_RAMDISK }, { "real-mode", 0, 0, OPT_REAL_MODE }, { "entry-32bit", 0, 0, OPT_ENTRY_32BIT }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "d"; while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch (opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) break; case OPT_APPEND: append = optarg; break; case OPT_REUSE_CMDLINE: tmp_cmdline = get_command_line(); break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_REAL_MODE: entry_16bit = 1; break; case OPT_ENTRY_32BIT: entry_32bit = 1; break; } } command_line = concat_cmdline(tmp_cmdline, append); if (tmp_cmdline) free(tmp_cmdline); command_line_len = 0; if (command_line) { command_line_len = strlen(command_line) + 1; } else { command_line = strdup("\0"); command_line_len = 1; } if (entry_16bit || entry_32bit) { fprintf(stderr, "Kexec2 syscall does not support 16bit" " or 32bit entry yet\n"); ret = -1; goto out; } if (ramdisk) { info->initrd_fd = open(ramdisk, O_RDONLY); if (info->initrd_fd == -1) { fprintf(stderr, "Could not open initrd file %s:%s\n", ramdisk, strerror(errno)); ret = -1; goto out; } } info->command_line = command_line; info->command_line_len = command_line_len; return ret; out: free(command_line); return ret; } int bzImage64_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info) { char *command_line = NULL, *tmp_cmdline = NULL; const char *ramdisk = NULL, *append = NULL; char *ramdisk_buf; off_t ramdisk_length = 0; int command_line_len; int entry_16bit = 0, entry_32bit = 0; int opt; int result; if (info->file_mode) return bzImage64_load_file(argc, argv, info); /* See options.h -- add any more there, too. */ static const struct option options[] = { KEXEC_ARCH_OPTIONS { "command-line", 1, 0, OPT_APPEND }, { "append", 1, 0, OPT_APPEND }, { "reuse-cmdline", 0, 0, OPT_REUSE_CMDLINE }, { "initrd", 1, 0, OPT_RAMDISK }, { "ramdisk", 1, 0, OPT_RAMDISK }, { "real-mode", 0, 0, OPT_REAL_MODE }, { "entry-32bit", 0, 0, OPT_ENTRY_32BIT }, { 0, 0, 0, 0 }, }; static const char short_options[] = KEXEC_ARCH_OPT_STR "d"; while ((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) { switch (opt) { default: /* Ignore core options */ if (opt < OPT_ARCH_MAX) break; case OPT_APPEND: append = optarg; break; case OPT_REUSE_CMDLINE: tmp_cmdline = get_command_line(); break; case OPT_RAMDISK: ramdisk = optarg; break; case OPT_REAL_MODE: entry_16bit = 1; break; case OPT_ENTRY_32BIT: entry_32bit = 1; break; } } command_line = concat_cmdline(tmp_cmdline, append); if (tmp_cmdline) free(tmp_cmdline); command_line_len = 0; if (command_line) { command_line_len = strlen(command_line) + 1; } else { command_line = strdup("\0"); command_line_len = 1; } ramdisk_buf = 0; if (ramdisk) ramdisk_buf = slurp_file(ramdisk, &ramdisk_length); if (entry_16bit || entry_32bit) result = do_bzImage_load(info, buf, len, command_line, command_line_len, ramdisk_buf, ramdisk_length, entry_16bit); else result = do_bzImage64_load(info, buf, len, command_line, command_line_len, ramdisk_buf, ramdisk_length); free(command_line); return result; } kexec-tools-2.0.10/kexec/arch/x86_64/kexec-x86_64.h0000644001567400156740000000134512242534555020305 0ustar hormshorms#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); int bzImage64_probe(const char *buf, off_t len); int bzImage64_load(int argc, char **argv, const char *buf, off_t len, struct kexec_info *info); void bzImage64_usage(void); #endif /* KEXEC_X86_64_H */ kexec-tools-2.0.10/kexec/arch/x86_64/include/arch/options.h0000777001567400156740000000000012242534542030031 2../../../i386/include/arch/options.hustar hormshormskexec-tools-2.0.10/kdump/Makefile0000644001567400156740000000124112417126536015702 0ustar hormshorms# # kdump (reading a crashdump from memory) # KDUMP_SRCS:= kdump/kdump.c KDUMP_OBJS = $(call objify, $(KDUMP_SRCS)) KDUMP_DEPS = $(call depify, $(KDUMP_OBJS)) KDUMP = $(SBINDIR)/kdump KDUMP_MANPAGE = $(MANDIR)/man8/kdump.8 dist += kdump/Makefile $(KDUMP_SRCS) kdump/kdump.8 clean += $(KDUMP_OBJS) $(KDUMP_DEPS) $(KDUMP) $(KDUMP_MANPAGE) -include $(KDUMP_DEPS) $(KDUMP): CC=$(TARGET_CC) $(KDUMP): $(KDUMP_OBJS) @$(MKDIR) -p $(@D) $(LINK.o) -o $@ $^ $(CFLAGS) $(LIBS) $(KDUMP_MANPAGE): kdump/kdump.8 $(MKDIR) -p $(MANDIR)/man8 cp $^ $(KDUMP_MANPAGE) echo:: @echo "KDUMP_SRCS $(KDUMP_SRCS)" @echo "KDUMP_DEPS $(KDUMP_DEPS)" @echo "KDUMP_OBJS $(KDUMP_OBJS)" kexec-tools-2.0.10/kdump/kdump.c0000644001567400156740000001630611642166046015535 0ustar hormshorms#include #include #include #include #include #include #include #include #include #include #include #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", (unsigned int)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; size_t written = 0; 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; } kexec-tools-2.0.10/kdump/kdump.80000644001567400156740000000265011424244110015442 0ustar hormshorms.\" 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 KDUMP 8 "Jul 27, 2005" .\" 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 insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME kdump \- This is just a placeholder until real man page has been written .SH SYNOPSIS .B kdump .RI [ options ] " start_address" ... .SH DESCRIPTION .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBkdump\fP does not have a man page yet. .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. .SH SEE ALSO .SH AUTHOR kdump was written by Eric Biederman. .PP This manual page was written by Khalid Aziz , for the Debian project (but may be used by others). kexec-tools-2.0.10/vmcore-dmesg/Makefile0000644001567400156740000000154012242534555017154 0ustar hormshorms# # vmcore-dmesg (reading demsg from vmcore) # VMCORE_DMESG_SRCS:= vmcore-dmesg/vmcore-dmesg.c VMCORE_DMESG_OBJS = $(call objify, $(VMCORE_DMESG_SRCS)) VMCORE_DMESG_DEPS = $(call depify, $(VMCORE_DMESG_OBJS)) VMCORE_DMESG = $(SBINDIR)/vmcore-dmesg VMCORE_DMESG_MANPAGE = $(MANDIR)/man8/vmcore-dmesg.8 dist += vmcore-dmesg/Makefile $(VMCORE_DMESG_SRCS) vmcore-dmesg/vmcore-dmesg.8 clean += $(VMCORE_DMESG_OBJS) $(VMCORE_DMESG_DEPS) $(VMCORE_DMESG) $(VMCORE_DMESG_MANPAGE) -include $(VMCORE_DMESG_DEPS) $(VMCORE_DMESG): $(VMCORE_DMESG_OBJS) @$(MKDIR) -p $(@D) $(LINK.o) -o $@ $^ $(CFLAGS) $(VMCORE_DMESG_MANPAGE): vmcore-dmesg/vmcore-dmesg.8 $(MKDIR) -p $(MANDIR)/man8 cp $^ $(VMCORE_DMESG_MANPAGE) echo:: @echo "VMCORE_DMESG_SRCS $(VMCORE_DMESG_SRCS)" @echo "VMCORE_DMESG_DEPS $(VMCORE_DMESG_DEPS)" @echo "VMCORE_DMESG_OBJS $(VMCORE_DMESG_OBJS)" kexec-tools-2.0.10/vmcore-dmesg/vmcore-dmesg.c0000644001567400156740000005004412417126536020253 0ustar hormshorms#define _XOPEN_SOURCE 600 #define _LARGEFILE_SOURCE 1 #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* The 32bit and 64bit note headers make it clear we don't care */ typedef Elf32_Nhdr Elf_Nhdr; static const char *fname; static Elf64_Ehdr ehdr; static Elf64_Phdr *phdr; static char osrelease[4096]; static loff_t log_buf_vaddr; static loff_t log_end_vaddr; static loff_t log_buf_len_vaddr; static loff_t logged_chars_vaddr; /* record format logs */ static loff_t log_first_idx_vaddr; static loff_t log_next_idx_vaddr; /* struct printk_log (or older log) size */ static uint64_t log_sz; /* struct printk_log (or older log) field offsets */ static uint64_t log_offset_ts_nsec = UINT64_MAX; static uint16_t log_offset_len = UINT16_MAX; static uint16_t log_offset_text_len = UINT16_MAX; #if __BYTE_ORDER == __LITTLE_ENDIAN #define ELFDATANATIVE ELFDATA2LSB #elif __BYTE_ORDER == __BIG_ENDIAN #define ELFDATANATIVE ELFDATA2MSB #else #error "Unknown machine endian" #endif static uint16_t file16_to_cpu(uint16_t val) { if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) val = bswap_16(val); return val; } static uint32_t file32_to_cpu(uint32_t val) { if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) val = bswap_32(val); return val; } static uint64_t file64_to_cpu(uint64_t val) { if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) val = bswap_64(val); return val; } static uint64_t vaddr_to_offset(uint64_t vaddr) { /* Just hand the simple case where kexec gets * the virtual address on the program headers right. */ ssize_t i; for (i = 0; i < ehdr.e_phnum; i++) { if (phdr[i].p_vaddr > vaddr) continue; if ((phdr[i].p_vaddr + phdr[i].p_memsz) <= vaddr) continue; return (vaddr - phdr[i].p_vaddr) + phdr[i].p_offset; } fprintf(stderr, "No program header covering vaddr 0x%llxfound kexec bug?\n", (unsigned long long)vaddr); exit(30); } static unsigned machine_pointer_bits(void) { uint8_t bits = 0; /* Default to the size of the elf class */ switch(ehdr.e_ident[EI_CLASS]) { case ELFCLASS32: bits = 32; break; case ELFCLASS64: bits = 64; break; } /* Report the architectures pointer size */ switch(ehdr.e_machine) { case EM_386: bits = 32; break; } return bits; } static void read_elf32(int fd) { Elf32_Ehdr ehdr32; Elf32_Phdr *phdr32; size_t phdrs32_size; ssize_t ret, i; ret = pread(fd, &ehdr32, sizeof(ehdr32), 0); if (ret != sizeof(ehdr32)) { fprintf(stderr, "Read of Elf header from %s failed: %s\n", fname, strerror(errno)); exit(10); } ehdr.e_type = file16_to_cpu(ehdr32.e_type); ehdr.e_machine = file16_to_cpu(ehdr32.e_machine); ehdr.e_version = file32_to_cpu(ehdr32.e_version); ehdr.e_entry = file32_to_cpu(ehdr32.e_entry); ehdr.e_phoff = file32_to_cpu(ehdr32.e_phoff); ehdr.e_shoff = file32_to_cpu(ehdr32.e_shoff); ehdr.e_flags = file32_to_cpu(ehdr32.e_flags); ehdr.e_ehsize = file16_to_cpu(ehdr32.e_ehsize); ehdr.e_phentsize = file16_to_cpu(ehdr32.e_phentsize); ehdr.e_phnum = file16_to_cpu(ehdr32.e_phnum); ehdr.e_shentsize = file16_to_cpu(ehdr32.e_shentsize); ehdr.e_shnum = file16_to_cpu(ehdr32.e_shnum); ehdr.e_shstrndx = file16_to_cpu(ehdr32.e_shstrndx); if (ehdr.e_version != EV_CURRENT) { fprintf(stderr, "Bad Elf header version %u\n", ehdr.e_version); exit(11); } if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) { fprintf(stderr, "Bad Elf progra header size %u expected %zu\n", ehdr.e_phentsize, sizeof(Elf32_Phdr)); exit(12); } phdrs32_size = ehdr.e_phnum * sizeof(Elf32_Phdr); phdr32 = calloc(ehdr.e_phnum, sizeof(Elf32_Phdr)); if (!phdr32) { fprintf(stderr, "Calloc of %u phdrs32 failed: %s\n", ehdr.e_phnum, strerror(errno)); exit(14); } phdr = calloc(ehdr.e_phnum, sizeof(Elf64_Phdr)); if (!phdr) { fprintf(stderr, "Calloc of %u phdrs failed: %s\n", ehdr.e_phnum, strerror(errno)); exit(15); } ret = pread(fd, phdr32, phdrs32_size, ehdr.e_phoff); if (ret < 0 || (size_t)ret != phdrs32_size) { fprintf(stderr, "Read of program header @ 0x%llu for %zu bytes failed: %s\n", (unsigned long long)ehdr.e_phoff, phdrs32_size, strerror(errno)); exit(16); } for (i = 0; i < ehdr.e_phnum; i++) { phdr[i].p_type = file32_to_cpu(phdr32[i].p_type); phdr[i].p_offset = file32_to_cpu(phdr32[i].p_offset); phdr[i].p_vaddr = file32_to_cpu(phdr32[i].p_vaddr); phdr[i].p_paddr = file32_to_cpu(phdr32[i].p_paddr); phdr[i].p_filesz = file32_to_cpu(phdr32[i].p_filesz); phdr[i].p_memsz = file32_to_cpu(phdr32[i].p_memsz); phdr[i].p_flags = file32_to_cpu(phdr32[i].p_flags); phdr[i].p_align = file32_to_cpu(phdr32[i].p_align); } free(phdr32); } static void read_elf64(int fd) { Elf64_Ehdr ehdr64; Elf64_Phdr *phdr64; size_t phdrs_size; ssize_t ret, i; ret = pread(fd, &ehdr64, sizeof(ehdr64), 0); if (ret < 0 || (size_t)ret != sizeof(ehdr)) { fprintf(stderr, "Read of Elf header from %s failed: %s\n", fname, strerror(errno)); exit(10); } ehdr.e_type = file16_to_cpu(ehdr64.e_type); ehdr.e_machine = file16_to_cpu(ehdr64.e_machine); ehdr.e_version = file32_to_cpu(ehdr64.e_version); ehdr.e_entry = file64_to_cpu(ehdr64.e_entry); ehdr.e_phoff = file64_to_cpu(ehdr64.e_phoff); ehdr.e_shoff = file64_to_cpu(ehdr64.e_shoff); ehdr.e_flags = file32_to_cpu(ehdr64.e_flags); ehdr.e_ehsize = file16_to_cpu(ehdr64.e_ehsize); ehdr.e_phentsize = file16_to_cpu(ehdr64.e_phentsize); ehdr.e_phnum = file16_to_cpu(ehdr64.e_phnum); ehdr.e_shentsize = file16_to_cpu(ehdr64.e_shentsize); ehdr.e_shnum = file16_to_cpu(ehdr64.e_shnum); ehdr.e_shstrndx = file16_to_cpu(ehdr64.e_shstrndx); if (ehdr.e_version != EV_CURRENT) { fprintf(stderr, "Bad Elf header version %u\n", ehdr.e_version); exit(11); } if (ehdr.e_phentsize != sizeof(Elf64_Phdr)) { fprintf(stderr, "Bad Elf progra header size %u expected %zu\n", ehdr.e_phentsize, sizeof(Elf64_Phdr)); exit(12); } phdrs_size = ehdr.e_phnum * sizeof(Elf64_Phdr); phdr64 = calloc(ehdr.e_phnum, sizeof(Elf64_Phdr)); if (!phdr64) { fprintf(stderr, "Calloc of %u phdrs64 failed: %s\n", ehdr.e_phnum, strerror(errno)); exit(14); } phdr = calloc(ehdr.e_phnum, sizeof(Elf64_Phdr)); if (!phdr) { fprintf(stderr, "Calloc of %u phdrs failed: %s\n", ehdr.e_phnum, strerror(errno)); exit(15); } ret = pread(fd, phdr64, phdrs_size, ehdr.e_phoff); if (ret < 0 || (size_t)ret != phdrs_size) { fprintf(stderr, "Read of program header @ %llu for %zu bytes failed: %s\n", (unsigned long long)(ehdr.e_phoff), phdrs_size, strerror(errno)); exit(16); } for (i = 0; i < ehdr.e_phnum; i++) { phdr[i].p_type = file32_to_cpu(phdr64[i].p_type); phdr[i].p_flags = file32_to_cpu(phdr64[i].p_flags); phdr[i].p_offset = file64_to_cpu(phdr64[i].p_offset); phdr[i].p_vaddr = file64_to_cpu(phdr64[i].p_vaddr); phdr[i].p_paddr = file64_to_cpu(phdr64[i].p_paddr); phdr[i].p_filesz = file64_to_cpu(phdr64[i].p_filesz); phdr[i].p_memsz = file64_to_cpu(phdr64[i].p_memsz); phdr[i].p_align = file64_to_cpu(phdr64[i].p_align); } free(phdr64); } static void scan_vmcoreinfo(char *start, size_t size) { char *last = start + size - 1; char *pos, *eol; char temp_buf[1024]; bool last_line = false; char *str; #define SYMBOL(sym) { \ .str = "SYMBOL(" #sym ")=", \ .name = #sym, \ .len = sizeof("SYMBOL(" #sym ")=") - 1, \ .vaddr = & sym ## _vaddr, \ } static struct symbol { const char *str; const char *name; size_t len; loff_t *vaddr; } symbol[] = { SYMBOL(log_buf), SYMBOL(log_end), SYMBOL(log_buf_len), SYMBOL(logged_chars), SYMBOL(log_first_idx), SYMBOL(log_next_idx), }; for (pos = start; pos <= last; pos = eol + 1) { size_t len, i; /* Find the end of the current line */ for (eol = pos; (eol <= last) && (*eol != '\n') ; eol++) ; if (eol > last) { /* * We did not find \n and note ended. Currently kernel * is appending last field CRASH_TIME without \n. It * is ugly but handle it. */ eol = last; len = eol - pos + 1; if (len >= sizeof(temp_buf)) len = sizeof(temp_buf) - 1; strncpy(temp_buf, pos, len); temp_buf[len + 1] = '\0'; pos = temp_buf; len = len + 1; eol = pos + len -1; last_line = true; } else { len = eol - pos + 1; } /* Stomp the last character so I am guaranteed a terminating null */ *eol = '\0'; /* Copy OSRELEASE if I see it */ if ((len >= 10) && (memcmp("OSRELEASE=", pos, 10) == 0)) { size_t to_copy = len - 10; if (to_copy >= sizeof(osrelease)) to_copy = sizeof(osrelease) - 1; memcpy(osrelease, pos + 10, to_copy); osrelease[to_copy] = '\0'; } /* See if the line is mentions a symbol I am looking for */ for (i = 0; i < sizeof(symbol)/sizeof(symbol[0]); i++ ) { unsigned long long vaddr; if (symbol[i].len >= len) continue; if (memcmp(symbol[i].str, pos, symbol[i].len) != 0) continue; /* Found a symbol now decode it */ vaddr = strtoull(pos + symbol[i].len, NULL, 16); /* Remember the virtual address */ *symbol[i].vaddr = vaddr; } /* Check for "SIZE(printk_log)" or older "SIZE(log)=" */ str = "SIZE(log)="; if (memcmp(str, pos, strlen(str)) == 0) log_sz = strtoull(pos + strlen(str), NULL, 10); str = "SIZE(printk_log)="; if (memcmp(str, pos, strlen(str)) == 0) log_sz = strtoull(pos + strlen(str), NULL, 10); /* Check for struct printk_log (or older log) field offsets */ str = "OFFSET(log.ts_nsec)="; if (memcmp(str, pos, strlen(str)) == 0) log_offset_ts_nsec = strtoull(pos + strlen(str), NULL, 10); str = "OFFSET(printk_log.ts_nsec)="; if (memcmp(str, pos, strlen(str)) == 0) log_offset_ts_nsec = strtoull(pos + strlen(str), NULL, 10); str = "OFFSET(log.len)="; if (memcmp(str, pos, strlen(str)) == 0) log_offset_len = strtoul(pos + strlen(str), NULL, 10); str = "OFFSET(printk_log.len)="; if (memcmp(str, pos, strlen(str)) == 0) log_offset_len = strtoul(pos + strlen(str), NULL, 10); str = "OFFSET(log.text_len)="; if (memcmp(str, pos, strlen(str)) == 0) log_offset_text_len = strtoul(pos + strlen(str), NULL, 10); str = "OFFSET(printk_log.text_len)="; if (memcmp(str, pos, strlen(str)) == 0) log_offset_text_len = strtoul(pos + strlen(str), NULL, 10); if (last_line) break; } } static void scan_notes(int fd, loff_t start, loff_t lsize) { char *buf, *last, *note, *next; size_t size; ssize_t ret; if (lsize > SSIZE_MAX) { fprintf(stderr, "Unable to handle note section of %llu bytes\n", (unsigned long long)lsize); exit(20); } size = lsize; buf = malloc(size); if (!buf) { fprintf(stderr, "Cannot malloc %zu bytes\n", size); exit(21); } last = buf + size - 1; ret = pread(fd, buf, size, start); if (ret != (ssize_t)size) { fprintf(stderr, "Cannot read note section @ 0x%llx of %zu bytes: %s\n", (unsigned long long)start, size, strerror(errno)); exit(22); } for (note = buf; (note + sizeof(Elf_Nhdr)) < last; note = next) { Elf_Nhdr *hdr; char *n_name, *n_desc; size_t n_namesz, n_descsz, n_type; hdr = (Elf_Nhdr *)note; n_namesz = file32_to_cpu(hdr->n_namesz); n_descsz = file32_to_cpu(hdr->n_descsz); n_type = file32_to_cpu(hdr->n_type); n_name = note + sizeof(*hdr); n_desc = n_name + ((n_namesz + 3) & ~3); next = n_desc + ((n_descsz + 3) & ~3); if (next > (last + 1)) break; if ((memcmp(n_name, "VMCOREINFO", 11) != 0) || (n_type != 0)) continue; scan_vmcoreinfo(n_desc, n_descsz); } free(buf); } static void scan_note_headers(int fd) { int i; for (i = 0; i < ehdr.e_phnum; i++) { if (phdr[i].p_type != PT_NOTE) continue; scan_notes(fd, phdr[i].p_offset, phdr[i].p_filesz); } } static uint64_t read_file_pointer(int fd, uint64_t addr) { uint64_t result; ssize_t ret; if (machine_pointer_bits() == 64) { uint64_t scratch; ret = pread(fd, &scratch, sizeof(scratch), addr); if (ret != sizeof(scratch)) { fprintf(stderr, "Failed to read pointer @ 0x%llx: %s\n", (unsigned long long)addr, strerror(errno)); exit(40); } result = file64_to_cpu(scratch); } else { uint32_t scratch; ret = pread(fd, &scratch, sizeof(scratch), addr); if (ret != sizeof(scratch)) { fprintf(stderr, "Failed to read pointer @ 0x%llx: %s\n", (unsigned long long)addr, strerror(errno)); exit(40); } result = file32_to_cpu(scratch); } return result; } static uint32_t read_file_u32(int fd, uint64_t addr) { uint32_t scratch; ssize_t ret; ret = pread(fd, &scratch, sizeof(scratch), addr); if (ret != sizeof(scratch)) { fprintf(stderr, "Failed to read value @ 0x%llx: %s\n", (unsigned long long)addr, strerror(errno)); exit(41); } return file32_to_cpu(scratch); } static int32_t read_file_s32(int fd, uint64_t addr) { return read_file_u32(fd, addr); } static void write_to_stdout(char *buf, unsigned int nr) { ssize_t ret; ret = write(STDOUT_FILENO, buf, nr); if (ret != nr) { fprintf(stderr, "Failed to write out the dmesg log buffer!:" " %s\n", strerror(errno)); exit(54); } } static void dump_dmesg_legacy(int fd) { uint64_t log_buf, log_buf_offset; unsigned log_end, logged_chars, log_end_wrapped; int log_buf_len, to_wrap; char *buf; ssize_t ret; if (!log_buf_vaddr) { fprintf(stderr, "Missing the log_buf symbol\n"); exit(50); } if (!log_end_vaddr) { fprintf(stderr, "Missing the log_end symbol\n"); exit(51); } if (!log_buf_len_vaddr) { fprintf(stderr, "Missing the log_bug_len symbol\n"); exit(52); } if (!logged_chars_vaddr) { fprintf(stderr, "Missing the logged_chars symbol\n"); exit(53); } log_buf = read_file_pointer(fd, vaddr_to_offset(log_buf_vaddr)); log_end = read_file_u32(fd, vaddr_to_offset(log_end_vaddr)); log_buf_len = read_file_s32(fd, vaddr_to_offset(log_buf_len_vaddr)); logged_chars = read_file_u32(fd, vaddr_to_offset(logged_chars_vaddr)); log_buf_offset = vaddr_to_offset(log_buf); buf = calloc(1, log_buf_len); if (!buf) { fprintf(stderr, "Failed to malloc %d bytes for the logbuf: %s\n", log_buf_len, strerror(errno)); exit(51); } log_end_wrapped = log_end % log_buf_len; to_wrap = log_buf_len - log_end_wrapped; ret = pread(fd, buf, to_wrap, log_buf_offset + log_end_wrapped); if (ret != to_wrap) { fprintf(stderr, "Failed to read the first half of the log buffer: %s\n", strerror(errno)); exit(52); } ret = pread(fd, buf + to_wrap, log_end_wrapped, log_buf_offset); if (ret != log_end_wrapped) { fprintf(stderr, "Faield to read the second half of the log buffer: %s\n", strerror(errno)); exit(53); } write_to_stdout(buf + (log_buf_len - logged_chars), logged_chars); } static inline uint16_t struct_val_u16(char *ptr, unsigned int offset) { return(file16_to_cpu(*(uint16_t *)(ptr + offset))); } static inline uint32_t struct_val_u32(char *ptr, unsigned int offset) { return(file32_to_cpu(*(uint32_t *)(ptr + offset))); } static inline uint64_t struct_val_u64(char *ptr, unsigned int offset) { return(file64_to_cpu(*(uint64_t *)(ptr + offset))); } /* human readable text of the record */ static char *log_text(char *msg) { return msg + log_sz; } /* get record by index; idx must point to valid msg */ static char *log_from_idx(char *log_buf, uint32_t idx) { char *msg = log_buf + idx; /* * A length == 0 record is the end of buffer marker. Wrap around and * read the message at the start of the buffer. */ if (!struct_val_u16(msg, log_offset_len)) return log_buf; return msg; } /* get next record; idx must point to valid msg */ static uint32_t log_next(char *log_buf, uint32_t idx) { char *msg = log_buf + idx; uint16_t len; /* length == 0 indicates the end of the buffer; wrap */ /* * A length == 0 record is the end of buffer marker. Wrap around and * read the message at the start of the buffer as *this* one, and * return the one after that. */ len = struct_val_u16(msg, log_offset_len); if (!len) { msg = log_buf; return struct_val_u16(msg, log_offset_len); } return idx + len; } /* Read headers of log records and dump accordingly */ static void dump_dmesg_structured(int fd) { #define OUT_BUF_SIZE 4096 uint64_t log_buf, log_buf_offset, ts_nsec; uint32_t log_first_idx, log_next_idx, current_idx, len = 0, i; int log_buf_len; char *buf, out_buf[OUT_BUF_SIZE]; ssize_t ret; char *msg; uint16_t text_len; imaxdiv_t imaxdiv_sec, imaxdiv_usec; if (!log_buf_vaddr) { fprintf(stderr, "Missing the log_buf symbol\n"); exit(60); } if (!log_buf_len_vaddr) { fprintf(stderr, "Missing the log_bug_len symbol\n"); exit(61); } if (!log_first_idx_vaddr) { fprintf(stderr, "Missing the log_first_idx symbol\n"); exit(62); } if (!log_next_idx_vaddr) { fprintf(stderr, "Missing the log_next_idx symbol\n"); exit(63); } if (!log_sz) { fprintf(stderr, "Missing the struct log size export\n"); exit(64); } if (log_offset_ts_nsec == UINT64_MAX) { fprintf(stderr, "Missing the log.ts_nsec offset export\n"); exit(65); } if (log_offset_len == UINT16_MAX) { fprintf(stderr, "Missing the log.len offset export\n"); exit(66); } if (log_offset_text_len == UINT16_MAX) { fprintf(stderr, "Missing the log.text_len offset export\n"); exit(67); } log_buf = read_file_pointer(fd, vaddr_to_offset(log_buf_vaddr)); log_buf_len = read_file_s32(fd, vaddr_to_offset(log_buf_len_vaddr)); log_first_idx = read_file_u32(fd, vaddr_to_offset(log_first_idx_vaddr)); log_next_idx = read_file_u32(fd, vaddr_to_offset(log_next_idx_vaddr)); log_buf_offset = vaddr_to_offset(log_buf); buf = calloc(1, log_buf_len); if (!buf) { fprintf(stderr, "Failed to malloc %d bytes for the logbuf:" " %s\n", log_buf_len, strerror(errno)); exit(64); } ret = pread(fd, buf, log_buf_len, log_buf_offset); if (ret != log_buf_len) { fprintf(stderr, "Failed to read log buffer of size %d bytes:" " %s\n", log_buf_len, strerror(errno)); exit(65); } /* Parse records and write out data at standard output */ current_idx = log_first_idx; len = 0; while (current_idx != log_next_idx) { msg = log_from_idx(buf, current_idx); ts_nsec = struct_val_u64(msg, log_offset_ts_nsec); imaxdiv_sec = imaxdiv(ts_nsec, 1000000000); imaxdiv_usec = imaxdiv(imaxdiv_sec.rem, 1000); len += sprintf(out_buf + len, "[%5llu.%06llu] ", (long long unsigned int)imaxdiv_sec.quot, (long long unsigned int)imaxdiv_usec.quot); /* escape non-printable characters */ text_len = struct_val_u16(msg, log_offset_text_len); for (i = 0; i < text_len; i++) { unsigned char c = log_text(msg)[i]; if (!isprint(c) && !isspace(c)) len += sprintf(out_buf + len, "\\x%02x", c); else out_buf[len++] = c; if (len >= OUT_BUF_SIZE - 64) { write_to_stdout(out_buf, len); len = 0; } } out_buf[len++] = '\n'; /* Move to next record */ current_idx = log_next(buf, current_idx); } if (len) write_to_stdout(out_buf, len); } static void dump_dmesg(int fd) { if (log_first_idx_vaddr) dump_dmesg_structured(fd); else dump_dmesg_legacy(fd); } int main(int argc, char **argv) { ssize_t ret; int fd; if (argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); return 1; } fname = argv[1]; fd = open(fname, O_RDONLY); if (fd < 0) { fprintf(stderr, "Cannot open %s: %s\n", fname, strerror(errno)); return 2; } ret = pread(fd, ehdr.e_ident, EI_NIDENT, 0); if (ret != EI_NIDENT) { fprintf(stderr, "Read of e_ident from %s failed: %s\n", fname, strerror(errno)); return 3; } if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { fprintf(stderr, "Missing elf signature\n"); return 4; } if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { fprintf(stderr, "Bad elf version\n"); return 5; } if ((ehdr.e_ident[EI_CLASS] != ELFCLASS32) && (ehdr.e_ident[EI_CLASS] != ELFCLASS64)) { fprintf(stderr, "Unknown elf class %u\n", ehdr.e_ident[EI_CLASS]); return 6; } if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) && (ehdr.e_ident[EI_DATA] != ELFDATA2MSB)) { fprintf(stderr, "Unkown elf data order %u\n", ehdr.e_ident[EI_DATA]); return 7; } if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) read_elf32(fd); else read_elf64(fd); scan_note_headers(fd); dump_dmesg(fd); close(fd); return 0; } kexec-tools-2.0.10/vmcore-dmesg/vmcore-dmesg.80000644001567400156740000000315411642166046020177 0ustar hormshorms.\" 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 VMCORE-DMESG 8 "Sep 7, 2010" .\" 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 insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME vmcore-dmesg \- This is just a placeholder until real man page has been written .SH SYNOPSIS .B vmcore-dmesg .RI " vmcore" .SH DESCRIPTION .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBvmcore-dmesg\fP extracts the dmesg from a vmcore and write it to standard out. \fBvmcore-dmesg\fP works against either \fB/proc/vmcore\fP in a crash dump capture context or a copy of \fB/proc/vmcore\fP that has been saved for later analysis. A single build of \fBvmcore-dmesg\fP should work against any linux vmcore written created on any architecture. .\"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. .SH SEE ALSO kexec(8) .SH AUTHOR vmcore-dmesg was written by Eric Biederman. kexec-tools-2.0.10/kexec_test/Makefile0000644001567400156740000000173411424244110016711 0ustar hormshorms# # kexec_test Debugging payload to be certain the infrastructure works # RELOC:=0x10000 KEXEC_TEST_SRCS:= kexec_test/kexec_test16.S kexec_test/kexec_test.S dist += kexec_test/Makefile $(KEXEC_TEST_SRCS) \ kexec_test/x86-setup-legacy-pic.S BUILD_KEXEC_TEST = no ifeq ($(ARCH),i386) BUILD_KEXEC_TEST = yes endif ifeq ($(ARCH),x86_64) BUILD_KEXEC_TEST = yes endif ifeq ($(BUILD_KEXEC_TEST),yes) KEXEC_TEST_OBJS = $(call objify, $(KEXEC_TEST_SRCS)) KEXEC_TEST_DEPS = $(call depify, $(KEXEC_TEST_OBJS)) KEXEC_TEST = $(PKGLIBDIR)/kexec_test clean += $(KEXEC_TEST_OBJS) $(KEXEC_TEST_DEPS) $(KEXEC_TEST) -include $(KEXEC_TEST_DEPS) $(KEXEC_TEST): CC=$(TARGET_CC) $(KEXEC_TEST): CPPFLAGS+=-DRELOC=$(RELOC) $(KEXEC_TEST): ASFLAGS+=-m32 #$(KEXEC_TEST): LDFLAGS=-m32 -Wl,-e -Wl,_start -Wl,-Ttext -Wl,$(RELOC) \ # -nostartfiles $(KEXEC_TEST): LDFLAGS=-melf_i386 -e _start -Ttext $(RELOC) $(KEXEC_TEST): $(KEXEC_TEST_OBJS) mkdir -p $(@D) $(TARGET_LD) $(LDFLAGS) -o $@ $^ endif kexec-tools-2.0.10/kexec_test/kexec_test16.S0000644001567400156740000004423511424244110017705 0ustar hormshorms/* * 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 .code16 .globl test16 .balign 16 .globl _start16 _start16: test16: pushw $s_in_real_mode - _start16 call print_string16 addw $2, %sp #if 0 /* Disable interrupts */ movb $0xff, %al outb %al, $0x21 outb %al, $0xa1 #endif /* Enable interrupts, BIOS calls may fail if we don't */ sti pushw $s_interrupts_enabled - _start16 call print_string16 addw $2, %sp /* Get the base memory size, via a bios call */ /* This is to test BIOS calls more than to achieve anything practical */ xorw %ax, %ax int $0x12 pushw %ax pushw $s_base_memory_size - _start16 call print_string16 addw $2, %sp call print_hex16 addw $2, %sp pushw $s_crlf - _start16 call print_string16 addw $2, %sp /* Some things do not like a20 being enabled so disable it */ call disable_a20 /* Here we test various BIOS calls to determine how much of the system is working */ call get_meme820 call print_meme820 call print_meme801 call print_mem88 call disable_apm call print_equipment_list call print_sysdesc call print_video call print_cursor call print_video_mode call set_auto_repeat_rate call print_dasd_type call print_edd /* Enable a20 */ call enable_a20 pushw $s_a20_enabled - _start16 call print_string16 addw $2, %sp /* Disable interrupts */ cli pushw $s_interrupts_disabled - _start16 call print_string16 addw $2, %sp retw # # Enable A20. This is at the very best an annoying procedure. # A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin. # A20_TEST_LOOPS = 32 # Iterations per wait A20_ENABLE_LOOPS = 255 # Total loops to try A20_DISABLE_LOOPS = 255 # Total loops to try enable_a20: .code16 movb $A20_ENABLE_LOOPS, a20_tries - _start16 a20_try_loop: # First, see if we are on a system with no A20 gate. a20_none: call a20_test jnz a20_done # Next, try the BIOS (INT 0x15, AX=0x2401) a20_bios: movw $0x2401, %ax pushfl # Be paranoid about flags int $0x15 popfl call a20_test jnz a20_done # Try enabling A20 through the keyboard controller a20_kbc: call empty_8042 call a20_test # Just in case the BIOS worked jnz a20_done # but had a delayed reaction. movb $0xD1, %al # command write outb %al, $0x64 call empty_8042 movb $0xDF, %al # A20 on outb %al, $0x60 call empty_8042 # Wait until a20 really *is* enabled; it can take a fair amount of # time on certain systems; Toshiba Tecras are known to have this # problem. a20_kbc_wait: xorw %cx, %cx a20_kbc_wait_loop: call a20_test jnz a20_done loop a20_kbc_wait_loop # Final attempt: use "configuration port A" a20_fast: inb $0x92, %al # Configuration Port A orb $0x02, %al # "fast A20" version andb $0xFE, %al # dont accidentally reset outb %al, $0x92 # Wait for configuration port A to take effect a20_fast_wait: xorw %cx, %cx a20_fast_wait_loop: call a20_test jnz a20_done loop a20_fast_wait_loop # A20 is still not responding. Try frobbing it again. # decb (a20_tries - _start16) jnz a20_try_loop jmp a20_die a20_die: pushw $s_a20_err_msg - _start16 call print_string16 jmp halt16 # If we get here, all is good a20_done: ret # This routine tests whether or not A20 is enabled. If so, it # exits with zf = 0. # # The memory address used, 0x200, is the int $0x80 vector, which # should be safe. A20_TEST_ADDR = 4*0x80 a20_test: .code16 pushw %cx pushw %ax xorw %cx, %cx movw %cx, %fs # Low memory decw %cx movw %cx, %gs # High memory area movw $A20_TEST_LOOPS, %cx movw %fs:(A20_TEST_ADDR), %ax pushw %ax a20_test_wait: incw %ax movw %ax, %fs:(A20_TEST_ADDR) call delay # Serialize and make delay constant cmpw %gs:(A20_TEST_ADDR+0x10), %ax loope a20_test_wait popw %fs:(A20_TEST_ADDR) popw %ax popw %cx ret # # Disable A20 # disable_a20: .code16 movb $A20_DISABLE_LOOPS, a20_disable_tries - _start16 a20_disable_loop: # First see if gate A20 is already disabled call a20_test jz a20_disabled # Next, try the BIOS (INT 0x15, AX= 0x2400) movw $0x2400, %ax pushfl # Be paranoid about flags int $0x15 popfl call a20_test jz a20_disabled # Try disabling A20 through the keyboard controller call empty_8042 call a20_test # Just in case the BIOS worked jz a20_disabled # but had a delayed reaction. movb $0xD1, %al # command write outb %al, $0x64 call empty_8042 movb $0xDD, %al # A20 off outb %al, $0x60 call empty_8042 # Wait until a20 really *is* disabled xorw %cx, %cx a20_kbc_disable_loop: call a20_test jz a20_disabled loop a20_kbc_disable_loop # Final attempt: use "configuration port A" inb $0x92, %al # Configuratin Port A andb $0xFD, %al # "fast A20" version andb $0xFE, %al # dont accidentally reset outb %al, $0x92 # Wait for configuration port A to take affect xorw %cx, %cx a20_fast_disable_loop: call a20_test jz a20_disabled loop a20_fast_disable_loop # A20 is still not responding. Try it again decb (a20_disable_tries - _start16) jnz a20_disable_loop pushw $s_a20_cant_disable - _start16 call print_string16 addw $2, %sp retw # If we get here, all is good a20_disabled: pushw $s_a20_disabled - _start16 call print_string16 addw $2, %sp retw # This routine checks that the keyboard command queue is empty # (after emptying the output buffers) # # Some machines have delusions that the keyboard buffer is always full # with no keyboard attached... # # If there is no keyboard controller, we will usually get 0xff # to all the reads. With each IO taking a microsecond and # a timeout of 100,000 iterations, this can take about half a # second ("delay" == outb to port 0x80). That should be ok, # and should also be plenty of time for a real keyboard controller # to empty. # empty_8042: .code16 pushl %ecx movl $100000, %ecx empty_8042_loop: decl %ecx jz empty_8042_end_loop call delay inb $0x64, %al # 8042 status port testb $1, %al # output buffer? jz no_output call delay inb $0x60, %al # read it jmp empty_8042_loop no_output: testb $2, %al # is input buffer full? jnz empty_8042_loop # yes - loop empty_8042_end_loop: popl %ecx ret # method E820H: # the memory map from hell. e820h returns memory classified into # a whole bunch of different types, and allows memory holes and # everything. We scan through this memory map and build a list # of the first 32 memory areas, which we return at [E820MAP]. # This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm #define SMAP 0x534d4150 #define E820_MAX 32 #define E820_SIZE 20 get_meme820: .code16 pushw %bp movw %sp, %bp pushw %ds pushw %es pushl %esi pushl %edi pushl %ebx xorl %eax, %eax movb %al, e820nr - _start16 xorl %ebx, %ebx # continuation counter movw $e820_map - _start16, %di # point into the whitelist # so we can have the bios # directly write into it. jmpe820: movl $0x0000e820, %eax # e820, upper word zeroed movl $SMAP, %edx # ascii SMAP movl $E820_SIZE, %ecx # size of the e820rec pushw %ds # data record. popw %es int $0x15 # make the call jc bail820 # fall to e801 if it fails cmpl $SMAP, %eax # check the return is SMAP jne bail820 # fall to e801 if it fails # cmpl $1, 16(%di) # is this usable memory? # jne again820 # If this is usable memory, we save it by simply advancing %di by # sizeof(e820rec). # good820: movb e820nr - _start16, %al # up to 32 entries cmpb $E820_MAX, %al jnl bail820 incb e820nr - _start16 movw %di, %ax addw $20, %ax movw %ax, %di again820: cmpl $0, %ebx # check to see if jne jmpe820 # %ebx is set to EOF bail820: popl %ebx popl %edi popl %esi popw %es popw %ds popw %bp retw print_meme820: .code16 pushw %si xorw %cx, %cx movb (e820nr - _start16), %cl movw $e820_map - _start16, %si pushw $s_meme820 - _start16 call print_string16 addw $2, %sp print_meme820.1: pushw %cx pushw 8(%si) pushw 10(%si) pushw 12(%si) pushw 14(%si) call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp pushw $s_at - _start16 call print_string16 addw $2, %sp pushw 0(%si) pushw 2(%si) pushw 4(%si) pushw 6(%si) call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp pushw $s_type - _start16 call print_string16 addw $2, %sp pushw 16(%si) pushw 18(%si) call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp pushw $s_crlf - _start16 call print_string16 addw $2, %sp popw %cx addw $E820_SIZE, %si subw $1, %cx jnz print_meme820.1 popw %si retw print_meme801: .code16 pushw %bp movw %sp, %bp pushw %bx pushl $0 # method E801H: # memory size is in 1k chunksizes stc # fix to work around buggy xorw %cx,%cx # BIOSes which dont clear/set xorw %dx,%dx # carry on pass/error of # e801h memory size call # or merely pass cx,dx though # without changing them. movw $0xe801, %ax int $0x15 jc print_meme801.2 cmpw $0x0, %cx # Kludge to handle BIOSes jne e801usecxdx # which report their extended cmpw $0x0, %dx # memory in AX/BX rather than jne e801usecxdx # CX/DX. The spec I have read movw %ax, %cx # seems to indicate AX/BX movw %bx, %dx # are more reasonable anyway... e801usecxdx: andl $0xffff, %edx # clear sign extend shll $6, %edx # and go from 64k to 1k chunks movl %edx, -6(%bp) # store extended memory size andl $0xffff, %ecx # clear sign extend addl %ecx, -6(%bp) # and add lower memory into pushw $s_meme801 - _start16 call print_string16 addw $2, %sp pushw -6(%bp) pushw -4(%bp) call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp pushw $s_crlf - _start16 call print_string16 addw $2, %sp print_meme801.2: addw $4, %sp popw %bx popw %bp retw print_mem88: .code16 # Ye Olde Traditional Methode. Returns the memory size (up to 16mb or # 64mb, depending on the bios) in ax. movb $0x88, %ah int $0x15 pushw %ax pushw $s_mem88 - _start16 call print_string16 addw $2, %sp call print_hex16 addw $2, %sp pushw $s_crlf - _start16 call print_string16 addw $2, %sp retw print_dasd_type: .code16 pushw $s_dasd_type - _start16 call print_string16 addw $2, %sp movw $0x1500, %ax movb $0x81, %dl int $0x13 jc print_dasd_type.1 pushw %dx pushw %cx pushw $s_space - _start16 pushw %ax call print_hex16 addw $2, %sp call print_string16 addw $2, %sp call print_hex16 addw $2, %sp call print_hex16 addw $2, %sp jmp print_dasd_type.2 print_dasd_type.1: pushw $s_none - _start16 call print_string16 addw $2, %sp print_dasd_type.2: pushw $s_crlf - _start16 call print_string16 addw $2, %sp retw print_equipment_list: .code16 pushw $s_equipment_list - _start16 call print_string16 addw $2, %sp int $0x11 pushw %ax call print_hex16 addw $2, %sp pushw $s_crlf - _start16 call print_string16 addw $2, %sp retw print_sysdesc: .code16 pushw $s_sysdesc - _start16 call print_string16 addw $2, %sp pushw %es movb $0xc0, %ah stc int $0x15 movw %es, %ax popw %es jc print_sysdesc.1 pushw %bx pushw $s_colon - _start16 pushw %ax call print_hex16 addw $2, %sp call print_string16 addw $2, %sp call print_hex16 addw $2, %sp jmp print_sysdesc.2 print_sysdesc.1: pushw $s_none - _start16 call print_string16 addw $2, %sp print_sysdesc.2: pushw $s_crlf - _start16 call print_string16 addw $2, %sp retw print_edd: .code16 pushw $s_edd - _start16 call print_string16 add $2, %sp movb $0x80, %dl movb $0x41, %ah # Function 41 movw $0x55aa, %bx # magic int $0x13 # make the call jc print_edd.1 # no more BIOS devices cmpw $0xAA55, %bx # is magic right? jne print_edd.1 # nope pushw $s_ok - _start16 call print_string16 add $2, %sp jmp print_edd.2 print_edd.1: pushw $s_none - _start16 call print_string16 add $2, %sp print_edd.2: pushw $s_crlf - _start16 call print_string16 addw $2, %sp retw set_auto_repeat_rate: .code16 pushw $s_auto_repeat_rate - _start16 call print_string16 add $2, %sp # Set the keyboard repeat rate to the max movw $0x0305, %ax xorw %bx, %bx int $0x16 pushw $s_done - _start16 call print_string16 add $2, %sp retw print_video: .code16 pushw $s_video_type - _start16 call print_string16 add $2, %sp movb $0x12, %ah # Check EGA/VGA movb $0x10, %bl int $0x10 movw $s_video_pre_ega - _start16, %cx cmpb $0x10, %bl je print_video.1 movw $0x1a00, %ax # Check EGA or VGA? int $0x10 movw $s_video_vga - _start16, %cx cmpb $0x1a, %al # 1a means VGA... je print_video.1 # anything else is EGA. movw $s_video_ega - _start16, %cx print_video.1: pushw %cx call print_string16 addw $2, %sp pushw $s_crlf - _start16 call print_string16 addw $2, %sp retw print_cursor: .code16 pushw $s_cursor - _start16 call print_string16 add $2, %sp movb $0x03, %ah # Read cursor position xorb %bh, %bh int $0x10 xorw %ax, %ax movb %dl, %al pushw %ax pushw $s_space - _start16 movb %dh, %al pushw %ax call print_hex16 add $2, %sp call print_string16 add $2, %sp call print_hex16 add $2, %sp pushw $s_crlf - _start16 call print_string16 add $2, %sp retw print_video_mode: .code16 pushw $s_video_mode - _start16 call print_string16 add $2, %sp movb $0x0f, %ah # Read cursor position int $0x10 xorb %ah, %ah pushw %ax call print_hex16 add $2, %sp pushw $s_crlf - _start16 call print_string16 add $2, %sp retw disable_apm: push %bp movw %sp, %bp pushw %bx pushw $s_testing_for_apm - _start16 call print_string16 add $2, %sp # check for APM BIOS movw $0x5300, %ax # APM BIOS installation check xorw %bx, %bx int $0x15 jc done_apm_bios # error -> no APM BIOS cmpw $0x504d, %bx # check for "PM" signature jne done_apm_bios # no signature -> no APM BIOS pushw $s_apm_found_disconnecting - _start16 call print_string16 add $2, %sp movw $0x5304, %ax # Disconnect first just in case xorw %bx, %bx int $0x15 # ignore return code pushw $s_apm_connecting - _start16 call print_string16 add $2, %sp movw $0x5301, %ax # Real Mode connect xorw %bx, %bx int $0x15 jc done_apm_bios # error pushw $s_apm_disabling - _start16 call print_string16 add $2, %sp movw $0x5308, %ax # Disable APM mov $0xffff, %bx xorw %cx, %cx int $0x15 pushw $s_apm_disconnecting - _start16 call print_string16 add $2, %sp movw $0x5304, %ax # Do a final disconnect xorw %bx, %bx int $0x15 done_apm_bios: pushw $s_apm_test_done - _start16 call print_string16 add $2, %sp popw %bx popw %bp retw # Delay is needed after doing I/O delay: .code16 outb %al,$0x80 retw halt16: .code16 hlt jmp halt16 print_string16: .code16 pushw %bp movw %sp, %bp pushw %si movw 4(%bp), %si xorw %ax, %ax print_string16.1: lodsb %ds:(%si), %al testb $0xff, %al jz print_string16.2 call print_char16 jmp print_string16.1 print_string16.2: popw %si popw %bp ret print_hex16: .code16 pushw %bp movw %sp, %bp movw $16, %cx print_hex16.1: movw 4(%bp), %ax subb $4, %cl shrw %cl, %ax andb $0x0f, %al cmpb $9, %al ja print_hex16.2 addb $'0', %al jmp print_hex16.3 print_hex16.2: addb $'A' - 10, %al print_hex16.3: pushw %cx call print_char16 popw %cx testb %cl, %cl jnz print_hex16.1 popw %bp ret print_char16: .code16 # The character to print is in al call serial_print_char16 retw #define TTYS0_BASE 0x3f8 #define TTYS0_RBR (TTYS0_BASE + 0x00) #define TTYS0_TBR (TTYS0_BASE + 0x00) #define TTYS0_LSR (TTYS0_BASE + 0x05) serial_print_char16: .code16 pushw %bp movw %sp, %bp # The character to print is in al pushw %ax # Wait until the serial port is ready to receive characters serial_print_char16.1: movw $TTYS0_LSR, %dx inb %dx, %al testb $0x20, %al jz serial_print_char16.1 # Output the character movw $TTYS0_TBR, %dx movb -2(%bp), %al outb %al, %dx # Wait until the serial port has transmitted the character serial_print_char16.2: movw $TTYS0_LSR, %dx inb %dx, %al testb $0x40, %al jz serial_print_char16.2 # Restore %eax popw %ax # Return to caller popw %bp retw s_a20_err_msg: .asciz "A20 gate not responding!\r\n" s_in_real_mode: .asciz "In real mode.\r\n" s_base_memory_size: .asciz "Base memory size: " s_interrupts_enabled: .asciz "Interrupts enabled.\r\n" s_a20_disabled: .asciz "A20 disabled.\r\n" s_a20_cant_disable: .asciz "Can not A20 line.\r\n" s_a20_enabled: .asciz "A20 enabled\r\n" s_interrupts_disabled: .asciz "Interrupts disabled.\r\n" s_meme820: .asciz "E820 Memory Map.\r\n" s_at: .asciz " @ " s_type: .asciz " type: " s_space: .asciz " " s_colon: .asciz ":" s_none: .asciz " none " s_ok: .asciz " ok " s_done: .asciz " done\r\n" s_meme801: .asciz "E801 Memory size: " s_mem88: .asciz "Mem88 Memory size: " s_dasd_type: .asciz "DASD type: " s_equipment_list: .asciz "Equiptment list: " s_sysdesc: .asciz "Sysdesc: " s_edd: .asciz "EDD: " s_auto_repeat_rate: .asciz "Setting auto repeat rate " s_video_type: .asciz "Video type: " s_video_pre_ega: .asciz "CGA/MDA/HGA" s_video_ega: .asciz "EGA" s_video_vga: .asciz "VGA" s_cursor: .asciz "Cursor Position(Row,Column): " s_video_mode: .asciz "Video Mode: " s_testing_for_apm: .asciz "Testing for APM.\r\n" s_apm_found_disconnecting: .asciz "APM Found disconnecting.\r\n" s_apm_connecting: .asciz "APM connecting.\r\n" s_apm_disabling: .asciz "APM disabling.\r\n" s_apm_disconnecting: .asciz "APM disconnecting.\r\n" s_apm_test_done: .asciz "APM test done.\r\n" s_crlf: .asciz "\r\n" a20_tries: .byte A20_ENABLE_LOOPS a20_disable_tries: .byte A20_DISABLE_LOOPS e820nr: .byte 0 e820_map: .fill E820_MAX * E820_SIZE, 1, 0 kexec-tools-2.0.10/kexec_test/kexec_test.S0000644001567400156740000002022211424244110017524 0ustar hormshorms/* * 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 "config.h" .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 PACKAGE_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 kexec-tools-2.0.10/kexec_test/x86-setup-legacy-pic.S0000644001567400156740000000325411424244110021172 0ustar hormshorms/* * 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 kexec-tools-2.0.10/kexec-tools.spec0000644001567400156740000000203312542752177016240 0ustar hormshormsSummary: Load one kernel from another Name: kexec-tools Version: 2.0.10 Release: 0 License: GPL Group: Development/Tools Source0:%{name}-%{version}.tar.gz Packager: Eric Biederman BuildRoot: %{_tmppath}/%{name} %description /sbin/kexec is a user space utility 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 %{_sbindir}/kdump %{_sbindir}/vmcore-dmesg %doc News %doc COPYING %doc TODO %{_mandir}/man8/kexec.8.gz %{_mandir}/man8/kdump.8.gz %{_mandir}/man8/vmcore-dmesg.8.gz %changelog * Tue Dec 16 2004 Eric Biederman - kexec-tools initialy packaged as an rpm.