diff options
author | tjd21@arcadians.cl.cam.ac.uk <tjd21@arcadians.cl.cam.ac.uk> | 2005-03-29 10:01:06 +0000 |
---|---|---|
committer | tjd21@arcadians.cl.cam.ac.uk <tjd21@arcadians.cl.cam.ac.uk> | 2005-03-29 10:01:06 +0000 |
commit | 4ceed52eee936e46559d85e08b07123fda1ba82d (patch) | |
tree | eafd8bb5529bc266d52d67e6a08c2c458c4589f7 | |
parent | d3bd0aa333f314d098211dd51a439b69f1a400e0 (diff) | |
download | xen-4ceed52eee936e46559d85e08b07123fda1ba82d.tar.gz xen-4ceed52eee936e46559d85e08b07123fda1ba82d.tar.bz2 xen-4ceed52eee936e46559d85e08b07123fda1ba82d.zip |
bitkeeper revision 1.1236.1.149 (42492762NRUXAIqtzpmd2lX5HSPVog)
Added the mbootpack tool, which packages multiboot boot files and
disguises them as a linux bzImage. Useful for booting Xen using
pxelinux, or another linux-only bootloader.
Signed-off-by: Tim Deegan <Tim.Deegan@cl.cam.ac.uk>
-rw-r--r-- | .rootkeys | 11 | ||||
-rw-r--r-- | BitKeeper/etc/logging_ok | 1 | ||||
-rw-r--r-- | tools/misc/Makefile | 4 | ||||
-rw-r--r-- | tools/misc/mbootpack/GPL | 340 | ||||
-rw-r--r-- | tools/misc/mbootpack/Makefile | 97 | ||||
-rw-r--r-- | tools/misc/mbootpack/README | 77 | ||||
-rw-r--r-- | tools/misc/mbootpack/bin2c.c | 356 | ||||
-rw-r--r-- | tools/misc/mbootpack/bootsect.S | 136 | ||||
-rw-r--r-- | tools/misc/mbootpack/buildimage.c | 174 | ||||
-rw-r--r-- | tools/misc/mbootpack/mb_header.h | 90 | ||||
-rw-r--r-- | tools/misc/mbootpack/mb_info.h | 217 | ||||
-rw-r--r-- | tools/misc/mbootpack/mbootpack.c | 703 | ||||
-rw-r--r-- | tools/misc/mbootpack/mbootpack.h | 91 | ||||
-rw-r--r-- | tools/misc/mbootpack/setup.S | 1064 |
14 files changed, 3361 insertions, 0 deletions
@@ -696,6 +696,17 @@ 41a216ca7mgVSnCBHPCLkGOIqPS1CQ tools/libxutil/util.h 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile 40ab2cfawIw8tsYo0dQKtp83h4qfTQ tools/misc/fakei386xen +4249273cDOw6_uLUPvvUwWU1ZrJxnQ tools/misc/mbootpack/GPL +4249273cSmj2h8Fj3UpTg0g-k6CLsA tools/misc/mbootpack/Makefile +4249273c8gKIttF1QPiczvGo5AEOeA tools/misc/mbootpack/README +4249273c4N4PAkvt3trNlto4h76k8A tools/misc/mbootpack/bin2c.c +4249273cISg5nhW1Pt7OJ0jFu343ig tools/misc/mbootpack/bootsect.S +4249273cUiz8CgLqnG7XYFa8x5-MoQ tools/misc/mbootpack/buildimage.c +4249273c_gZ2yI_h-ci66E1Y5oSEPA tools/misc/mbootpack/mb_header.h +4249273cWnlW0-lOIYua1bkKirn6vA tools/misc/mbootpack/mb_info.h +4249273cA8LI3IMaSuhLOjykuMeQJA tools/misc/mbootpack/mbootpack.c +4249273cVTgyv2HYd-mC29IDaz0-mg tools/misc/mbootpack/mbootpack.h +4249273cLXQbRWFp_v-FqcyOm0sYtg tools/misc/mbootpack/setup.S 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile 3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README 3f6dc142IHaf6XIcAYGmhV9nNSIHFQ tools/misc/miniterm/miniterm.c diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index a5cd08799d..fb88f12f88 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -81,6 +81,7 @@ smh22@uridium.cl.cam.ac.uk sos22@donkeykong.cl.cam.ac.uk sos22@douglas.cl.cam.ac.uk sos22@labyrinth.cl.cam.ac.uk +tjd21@arcadians.cl.cam.ac.uk tlh20@elite.cl.cam.ac.uk tlh20@labyrinth.cl.cam.ac.uk tw275@labyrinth.cl.cam.ac.uk diff --git a/tools/misc/Makefile b/tools/misc/Makefile index b815072184..f12193eb6e 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -21,6 +21,7 @@ INSTALL_SBIN = netfix xm xend xensv xenperf all: build build: $(TARGETS) $(MAKE) -C miniterm + $(MAKE) -C mbootpack install: build [ -d $(DESTDIR)/usr/bin ] || $(INSTALL_DIR) $(DESTDIR)/usr/bin @@ -29,10 +30,13 @@ install: build $(INSTALL_PROG) $(INSTALL_SBIN) $(DESTDIR)/usr/sbin # No sense in installing miniterm on the Xen box. # $(MAKE) -C miniterm install +# Likewise mbootpack +# $(MAKE) -C mbootpack install clean: $(RM) *.o $(TARGETS) *~ $(MAKE) -C miniterm clean + $(MAKE) -C mbootpack clean %.o: %.c $(HDRS) Makefile $(CC) -c $(CFLAGS) -o $@ $< diff --git a/tools/misc/mbootpack/GPL b/tools/misc/mbootpack/GPL new file mode 100644 index 0000000000..5b6e7c66c2 --- /dev/null +++ b/tools/misc/mbootpack/GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/tools/misc/mbootpack/Makefile b/tools/misc/mbootpack/Makefile new file mode 100644 index 0000000000..c0bb60e28d --- /dev/null +++ b/tools/misc/mbootpack/Makefile @@ -0,0 +1,97 @@ +# +# Makefile for mbootpack +# +INSTALL = install +INSTALL_PROG = $(INSTALL) -m0755 +INSTALL_DIR = $(INSTALL) -d -m0755 + +XEN_ROOT=../../.. +include $(XEN_ROOT)/tools/Rules.mk + +CFLAGS += -Wall -Werror -O3 + +INCLUDES += -I $(XEN_XC) +INCLUDES += -I $(XEN_LIBXC) +CFLAGS += $(INCLUDES) + +HDRS = $(wildcard *.h) + +TARGETS = mbootpack + +INSTALL_BIN = mbootpack +INSTALL_SBIN = + +all: build +build: $(TARGETS) + +install: build + $(INSTALL_PROG) $(INSTALL_BIN) $(DESTDIR)/usr/bin + +# +# What object files need building for the program +# + +OBJS := mbootpack.o buildimage.o +DEPS := mbootpack.d buildimage.d + +# +# Tools etc. +# + +RM := rm -f +GDB := gdb +INCS := -I. -I- +DEFS := +LDFLAGS := +CC := gcc +CFLAGS := -W -Wall -Wpointer-arith -Wcast-qual -Wno-unused -Wno-format +CFLAGS += -Wmissing-prototypes +#CFLAGS += -pipe -g -O0 -Wcast-align +CFLAGS += -pipe -O3 + +# +# Rules +# + +mbootpack: $(OBJS) + $(CC) -o $@ $(filter-out %.a, $^) $(LDFLAGS) + +clean: FRC + $(RM) mbootpack *.o *.d bootsect setup bzimage_header.c bin2c + +bootsect: bootsect.S + $(CC) $(CFLAGS) $(INCS) $(DEFS) -D__MB_ASM -c bootsect.S -o bootsect.o + $(LD) -m elf_i386 -Ttext 0x0 -s --oformat binary bootsect.o -o $@ + +setup: setup.S + $(CC) $(CFLAGS) $(INCS) $(DEFS) -D__MB_ASM -c setup.S -o setup.o + $(LD) -m elf_i386 -Ttext 0x0 -s --oformat binary setup.o -o $@ + +bin2c: bin2c.o + $(CC) -o $@ $^ + +bzimage_header.c: bootsect setup bin2c + ./bin2c -n 8 -b1 -a bzimage_bootsect bootsect > bzimage_header.c + ./bin2c -n 8 -b1 -a bzimage_setup setup >> bzimage_header.c + +buildimage.c buildimage.d: bzimage_header.c + +%.o: %.S + $(CC) $(CFLAGS) $(INCS) $(DEFS) -c $< -o $@ + +%.o: %.c + $(CC) $(CFLAGS) $(INCS) $(DEFS) -c $< -o $@ + +%.d: %.c + $(CC) $(CFLAGS) $(INCS) $(DEFS) -M $< > $@ + +FRC: +.PHONY:: all FRC clean gdb +.PRECIOUS: $(OBJS) $(OBJS:.o=.c) $(DEPS) +.SUFFIXES: + +-include $(DEPS) + +# +# EOF +# diff --git a/tools/misc/mbootpack/README b/tools/misc/mbootpack/README new file mode 100644 index 0000000000..07516529b4 --- /dev/null +++ b/tools/misc/mbootpack/README @@ -0,0 +1,77 @@ + +mbootpack +--------- + +This is a utility to take a multiboot kernel and modules and repackage +them in a form that a standard linux bootloader will be able to load them. +It statically allocates memory addresses based on a 'standard' PC memory +layout, and then saves the image of the loaded system, along with an +almost-standard linux bzImage header which takes care of the start-of-day +requirements of a multiboot kernel (setting up 32-bit protected mode, etc.) + +Example invocation, to package a xen VMM and xenlinux guest and initrd: + + mbootpack -o bzImage -m ./xenlinux -m ./initrd.img ./xen-image + +You can now boot the 'bzImage' file using your favourite linux bootloader. + +The kernel command line will be provided at boot time by the bootloader +(you can specify a kernel command-line using the '-c' flag, but it will +be overridden at boot time unledd the bootloder provides an entirely +empty command line). If you wan to override the command line for the +first module (i.e. domain 0 kernel in Xen) at boot time, append ' -- ' +and the module commadn line to the bootloader command line, e.g.: + + boot: bzImage com1=9600,8n1 console=com1 dom0_mem=49152 -- root=/dev/sda3 ro console=ttyS0,9600n8 + +Everything before the '--' is passed to the kernel (xen) as its command +line; everything after is passed to the first module (xenlinux). + +This is ALPHA code: there are execution paths which have *not* been +tested, though it works for loading the Xen hypervisor using GrUB, LILO +or SYSLINUX. Bug reports and patches are very welcome. + +Possible features for future versions (all look possible, if there's any +demand for them): + + - support for kernels that load below 1MB + - zImage-style compressed images + - sane error messgaes for insane load addresses + - support for the MULTIBOOT_VIDEO_MODE bit + - proper support for passing E820h memory-maps from bzImage + + +Tim Deegan <tjd21@cl.cam.ac.uk>, March 2005 + + + +License and attributions +------------------------ + +The bzImage header block was originally taken from the Linux kernel. +http://www.kernel.org/ + +Some parts of the Multiboot loader code are based on GNU GRUB. +mb_info.h and mb_header.h are taken from GNU GRUB. +http://www.gnu.org/software/grub/ + +Bin2C was written by Nicolas Doualot; I tidied it a bit for a clean compile. +http://slubman.celeonet.fr/program.php?style=Default&project=bin2c + +All other code is copyright (C) 2003-2005 Tim Deegan (tjd21@cl.cam.ac.uk) + +mbootpack is distributed under the GNU General Public License: see "GPL" + +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 diff --git a/tools/misc/mbootpack/bin2c.c b/tools/misc/mbootpack/bin2c.c new file mode 100644 index 0000000000..609335da7d --- /dev/null +++ b/tools/misc/mbootpack/bin2c.c @@ -0,0 +1,356 @@ +/*************************************************************************************** + Project informations: + Project: bin2c + Version: 1.00 + Plateforme: PC + Copyright: DNDD.INC + Date: 28/03/2004 + + File informations: + Name: bin2c.c + Description:Convert any file to a C array + + Author informations: + Author: DOUALOT Nicolas + E-Mail: slubman@laposte.net + site: http://membres.lycos.fr/slubman/gp32 +***************************************************************************************/ + + +#include <stdio.h> /*perror */ +#include <sys/mman.h> /*PROT_READ,MAP_xxx */ +#include <fcntl.h> /*O_RDONLY */ +#include <sys/stat.h> /*stat */ +#include <stdlib.h> /*atoi */ +#include <string.h> /*strcmp */ +#include <ctype.h> /*toupper */ + +#define VERSION "1.10" + + +static void help(void) +{ + fprintf(stdout, "\nbin2c v"VERSION"\n"); + fprintf(stdout, "Slubman DevSoft (c)2003-2004 slubman.dndd@laposte.net \n\n"); + + fprintf(stdout, "Usage: bin2c [flags] <infile>\n\n"); + + //fprintf(stdout, "\t-quiet :\tdon't output standard messages\n"); + //fprintf(stdout, "\t-slash :\tappend backslash at end of line\n"); + fprintf(stdout, "\t-n <count> :\tnumber of items per line\n"); + fprintf(stdout, "\t-b1 :\tgenerate unsigned char array\n"); + fprintf(stdout, "\t-b2 :\tgenerate unsigned short array\n"); + fprintf(stdout, "\t-b4 :\tgenerate unsigned long array\n"); + fprintf(stdout, "\t-a <name> :\tgenerate an array with given name\n"); + fprintf(stdout, "\t-ss <nr> :\tskip number of bytes at begin of inputfile\n"); + fprintf(stdout, "\t-se <nr> :\tskip number of bytes at end of inputfile\n"); + fprintf(stdout, "\t-lb <nr> :\tinsert an additionally linebreak every nr line\n"); + fprintf(stdout, "\t-h :\tproduce an header\n"); + fprintf(stdout, "\tinfile :\tname of infile\n"); + fprintf(stdout, "\toutfile :\tname of outfile (use \"-\" for stdout)\n\n"); + + fprintf(stdout, " \tconverts binary file to C array data\n"); +} + +static void UnknownFlag(char *flag) +{ + fprintf(stderr, "Error: unknown flag %s\n", flag); + help(); + exit(EXIT_FAILURE); +} + +static void WriteHeader(FILE * outFile, char *oFileName, char *iFileName) +{ + // File Header + fprintf(outFile, "/***************************************************************************************\n"); + fprintf(outFile, "* File Name:\n"); + fprintf(outFile, "* Name: %s\n", oFileName); + fprintf(outFile, "* From: %s\n", iFileName); + fprintf(outFile, "* Created by :bin2c v"VERSION"\n*\n"); + fprintf(outFile, "* bin2c v"VERSION":\n"); + fprintf(outFile, "* Author: DOUALOT Nicolas\n"); + fprintf(outFile, "* E-Mail: slubman.dndd@laposte.net\n"); + fprintf(outFile, "* site: http://www.slubman.linux-fan.com/\n"); + fprintf(outFile, "***************************************************************************************/\n\n"); +} + +int main(int argc, char *argv[]) +{ + FILE *inFile = stdin, *outFile = stdout; + int a, i, nbLine = 0; + unsigned char *memory; + struct stat st; + + // Options + char arrayName[255] = "array"; // Array name + char *iFileName = NULL; // File to convert + char *oFileName = NULL; // File to write + int bpd = 1; // Array item length + int lb = 0; // Array blank line each lb line(s) + int nbCol = 15; // Nuber of items per line + int SkeepStart = 0; // Number of byte to skip at file begining + int SkeepEnd = 0; // Number of byte to skip at file end + int header = 0; // Produce an header + + // Is there the good number of arguments + if (argc < 2) + { + help(); + return 0; + } + + // On récupère les arguments (Ready for more options) + for (a = 1; a < argc; a++) + { + // An option + if (argv[a][0] == '-') + { + // Wich flag is it ? + switch (argv[a][1]) + { + // Writting on stdout + case 0: + printf("%s\n", argv[a]); + outFile = stdout; + break; + + // ArrayName flag + case 'a': + strcpy(arrayName, argv[++a]); + break; + + // Data type + case 'b': + switch (argv[a][2]) + { + case '1': + bpd = 1; + break; + + case '2': + bpd = 2; + break; + + case '4': + bpd = 4; + break; + + default: + UnknownFlag(argv[a]); + } + break; + + // Produce an header + case 'h': + header = 1; + break; + + // New line each n line + case 'l': + switch (argv[a][2]) + { + case 'b': + lb = atoi(argv[++a]); + break; + + default: + UnknownFlag(argv[a]); + } + + // Number of bit per line + case 'n': + nbCol = atoi(argv[++a]); + break; + + // Skip bytes + case 's': + switch (argv[a][2]) + { + // Beginig of file + case 's': + SkeepStart = atoi(argv[++a]); + break; + + // End of file + case 'e': + SkeepEnd = atoi(argv[++a]); + break; + + // Flag inconnu + default: + UnknownFlag(argv[a]); + } + + // Flag inconnu + default: + UnknownFlag(argv[a]); + } + } + // A filename + else + { + if (iFileName == NULL) + { + iFileName = argv[a]; + if ((inFile = fopen(iFileName, "rb")) == NULL) + { + fprintf(stderr, "Error: can't open %s\n", iFileName); + exit(EXIT_FAILURE); + } + } + else + { + if (oFileName == NULL) + { + oFileName = argv[a]; + if ((outFile = fopen(oFileName, "wb")) == NULL) + { + fprintf(stderr, "Error: can't open %s\n", oFileName); + exit(EXIT_FAILURE); + } + } + else + { + fprintf(stderr, "Error: Too many filesnames given!\n"); + help(); + exit(EXIT_FAILURE); + } + } + } + } + + if (!iFileName) + exit(EXIT_FAILURE); + + // Get file informations + if (stat(iFileName, &st) != 0) + { + fprintf(stderr, "Error: when scanning file %s\n", argv[1]); + exit(EXIT_FAILURE); + } + + // Allocating memory + if (!(memory = malloc(st.st_size + 3))) + { + memset(memory, 0, st.st_size + 3); + fprintf(stderr, "Error: not enought memory\n"); + exit(EXIT_FAILURE); + } + + // Reading the file + if (fread(memory, 1, st.st_size, inFile) != (size_t)st.st_size) + { + fprintf(stderr, "Error: when reading file %s\n", argv[1]); + fclose(inFile); + exit(EXIT_FAILURE); + } + fclose(inFile); + + // Must produce an header + if (header) + { + unsigned int i; + char hFileName[256], *def = NULL; + FILE *hFile = stdout; + + if (oFileName) + { + strcpy(hFileName, oFileName); + hFileName[strlen(hFileName) - 1] = 'h'; + hFile = fopen(hFileName, "wt"); + } + + WriteHeader(hFile, hFileName, iFileName); + + // Replace all '.' by '_' + for (i = 0; i < strlen(hFileName); i++) + if (hFileName[i] == '.') + hFileName[i] = '_'; + else + hFileName[i] = toupper(hFileName[i]); + + // the #ifdef at the begining + def = strrchr(hFileName, '/'); + def = def ? def + 1 : hFileName; + fprintf(hFile, "#ifndef __%s__\n#define __%s__\n\n", def, def); + + // Define array size + fprintf(hFile, "#define _%s_size_ %u\n\n", arrayName, (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd); + + // Begin the array + fprintf(hFile, "extern unsigned "); + fprintf(hFile, "%s ", bpd == 1 ? "char" : bpd == 2 ? "short" : "long"); + fprintf(hFile, "%s[", arrayName); + fprintf(hFile, "%u];\n\n", (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd); + + // the #endif at the end + fprintf(hFile, "#endif\n\n"); + + if (oFileName) + fclose(hFile); + } + + WriteHeader(outFile, oFileName, iFileName); + + // Define array size + if (!header) + fprintf(outFile, "#define _%s_size_ %u\n\n", arrayName, (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd); + + // Begin the array + fprintf(outFile, "unsigned "); + fprintf(outFile, "%s ", bpd == 1 ? "char" : bpd == 2 ? "short" : "long"); + fprintf(outFile, "%s[", arrayName); + fprintf(outFile, "%u] = {\n\t", (unsigned int) (st.st_size - SkeepStart - SkeepEnd) / bpd); + + // Writing file elements + for (i = 0; i < (st.st_size - SkeepEnd - SkeepStart) / bpd; /*i+=bpd */ i++) + { + // We write an item of bpd byte(s) + switch (bpd) + { + case 1: + fprintf(outFile, "0x%02x", *(unsigned char *) &memory[SkeepStart + i]); + break; + + case 2: + fprintf(outFile, "0x%04x", *(unsigned short *) &memory[SkeepStart + i]); + break; + + case 4: + fprintf(outFile, "0x%08lx", *(unsigned long *) &memory[SkeepStart + i]); + break; + } + + // Must put a coma ? + if (i != st.st_size - 1) + fprintf(outFile, ","); + + // End of a line ? + if (i && !((i + 1) % nbCol)) + { + // -lb option + if (lb && !((++nbLine) % lb)) + fprintf(outFile, "\n"); + fprintf(outFile, "\n\t"); + } + // Add a space + else + fprintf(outFile, " "); + } + + // The last line as nbCol elements + if (((st.st_size - SkeepStart - SkeepEnd) / bpd) % nbCol) + fprintf(outFile, "\n"); + + // Close the array + fprintf(outFile, "};\n"); + + // CLose the output file + if (outFile != stdout) + fclose(outFile); + + // Free allocated memory + free(memory); + + exit(EXIT_SUCCESS); +} diff --git a/tools/misc/mbootpack/bootsect.S b/tools/misc/mbootpack/bootsect.S new file mode 100644 index 0000000000..2cc9ee106c --- /dev/null +++ b/tools/misc/mbootpack/bootsect.S @@ -0,0 +1,136 @@ +/* + * bootsect.S + * + * This is bootsect.S from the linux 2.6.9 sources, + * with minor changes for mbootpack. + * + * + * 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. + * + * $Id: bootsect.S,v 1.2 2005/03/23 10:39:11 tjd21 Exp $ + * + */ + +#include "mbootpack.h" + +/* + * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds + * + * modified by Drew Eckhardt + * modified by Bruce Evans (bde) + * modified by Chris Noe (May 1999) (as86 -> gas) + * gutted by H. Peter Anvin (Jan 2003) + * + * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment + * addresses must be multiplied by 16 to obtain their respective linear + * addresses. To avoid confusion, linear addresses are written using leading + * hex while segment addresses are written as segment:offset. + * + */ + +/* #include <asm/boot.h> */ +/* Definitions we should have got from there */ +#define DEF_INITSEG 0x9000 +#define DEF_SYSSEG 0x1000 +#define DEF_SETUPSEG 0x9020 +#define DEF_SYSSIZE 0x7F00 +#define NORMAL_VGA 0xffff +#define EXTENDED_VGA 0xfffe +#define ASK_VGA 0xfffd + + +/* SETUPSECTS = 4 */ /* default nr of setup-sectors */ +BOOTSEG = 0x07C0 /* original address of boot-sector */ +INITSEG = DEF_INITSEG /* we move boot here - out of the way */ +SETUPSEG = DEF_SETUPSEG /* setup starts here */ +SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */ +SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */ + /* to be loaded */ +ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */ +SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */ + +#ifndef SVGA_MODE +/* #define SVGA_MODE ASK_VGA */ +#define SVGA_MODE NORMAL_VGA +#endif + +#ifndef RAMDISK +#define RAMDISK 0 +#endif + +#ifndef ROOT_RDONLY +#define ROOT_RDONLY 1 +#endif + +.code16 +.text + +.global _start +_start: + + # Normalize the start address + jmpl $BOOTSEG, $start2 + +start2: + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw $0x7c00, %sp + sti + cld + + movw $bugger_off_msg, %si + +msg_loop: + lodsb + andb %al, %al + jz die + movb $0xe, %ah + movw $7, %bx + int $0x10 + jmp msg_loop + +die: + # Allow the user to press a key, then reboot + xorw %ax, %ax + int $0x16 + int $0x19 + + # int 0x19 should never return. In case it does anyway, + # invoke the BIOS reset code... + ljmp $0xf000,$0xfff0 + + +bugger_off_msg: + .ascii "Direct booting from floppy is no longer supported.\r\n" + .ascii "Please use a boot loader program instead.\r\n" + .ascii "\n" + .ascii "Remove disk and press any key to reboot . . .\r\n" + .byte 0 + + + # Kernel attributes; used by setupbegtext + + .org 497 +setup_sects: .byte SETUPSECTS +root_flags: .word ROOT_RDONLY +syssize: .word SYSSIZE +swap_dev: .word SWAP_DEV +ram_size: .word RAMDISK +vid_mode: .word SVGA_MODE +root_dev: .word ROOT_DEV +boot_flag: .word 0xAA55 diff --git a/tools/misc/mbootpack/buildimage.c b/tools/misc/mbootpack/buildimage.c new file mode 100644 index 0000000000..223172803d --- /dev/null +++ b/tools/misc/mbootpack/buildimage.c @@ -0,0 +1,174 @@ +/* + * buildimage.c + * + * Takes the memory image of a loaded kernel and modules and repackages + * it as a linux bzImage + * + * Copyright (C) 2003-2004 Tim Deegan (tjd21@cl.cam.ac.uk) + * + * 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. + * + * $Id: buildimage.c,v 1.2 2005/03/23 10:39:19 tjd21 Exp $ + * + */ + + + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <getopt.h> +#include <elf.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <asm/page.h> + +#include "mbootpack.h" +#include "mb_header.h" + +/* We will build an image that a bzImage-capable bootloader will load like + * this: + * + * ============== (0) + * (BIOS memory) + * -------------- + * (Bootloader) + * -------------- + * bzImage startup code + * MBI, command-lines, module info + * ============== (0xa0000) + * (memory hole) + * ============== (0x100000) + * Kernel and modules + * ============== + * + * The bzImage startup code is mostly taken straight from the linux kernel + * (see bootsect.S, startup.S). It does the usual unpleasant start-of-day + * tasks to get to 32-bit protected mode, then sets registers appropriately + * and jumps to the kernel's entry address. + * + * It also does some relocation to make sure the MBI is where we expect it, + * and parses the linux command line. + */ + +#define BZ_SETUP_OFFSET (512 * (1 + SETUPSECTS)) +#define BZ_ENTRY_OFFSET 0x30 +#define BZ_MBI_OFFSET 0x34 +/* These *MUST* fit the offsets of entry_address and mbi_address in setup.S */ + +/* Bring in the bzImage boot sector and setup code */ +#include "bzimage_header.c" + +address_t place_mbi(long int size) +/* Find space at the top of *low* memory for the MBI and associated red tape */ +{ + address_t start; + start = 0xa000 - size; + if (start < 0x9000 + sizeof(bzimage_bootsect) + sizeof(bzimage_setup)) { + printf("Fatal: command-lines too long: need %i, have %i bytes\n", + size, + 0x1000 - (sizeof(bzimage_bootsect) + sizeof(bzimage_setup))); + exit(1); + } + if (!quiet) { + printf("Placed MBI and strings (%p+%p)\n", + start, size); + } + return start; +} + +void make_bzImage(section_t *sections, + address_t entry, + address_t mbi, + FILE *fp) +/* Rework this list of sections into a bzImage and write it out to fp */ +{ + int i; + size_t offset; + section_t *s; + + /* Patch the kernel and mbi addresses into the setup code */ + *(address_t *)(bzimage_setup + BZ_ENTRY_OFFSET) = entry; + *(address_t *)(bzimage_setup + BZ_MBI_OFFSET) = mbi; + if (!quiet) printf("Kernel entry is %p, MBI is %p.\n", entry, mbi); + + /* Write out header and trampoline */ + if (fseek(fp, 0, SEEK_SET) < 0) { + printf("Fatal: error seeking in output file: %s\n", + strerror(errno)); + exit(1); + } + if (fwrite(bzimage_bootsect, sizeof(bzimage_bootsect), 1, fp) != 1) { + printf("Fatal: error writing to output file: %s\n", + strerror(errno)); + exit(1); + } + if (fwrite(bzimage_setup, sizeof(bzimage_setup), 1, fp) != 1) { + printf("Fatal: error writing to output file: %s\n", + strerror(errno)); + exit(1); + } + + if (!quiet) printf("Wrote bzImage header: %i + %i bytes.\n", + sizeof(bzimage_bootsect), sizeof(bzimage_setup)); + + /* Sorted list of sections below 1MB: write them out */ + for (s = sections, i = 0; s; s = s->next) { + if (s->start >= HIGHMEM_START) continue; + offset = (s->start - 0x9000); + if (fseek(fp, offset, SEEK_SET) < 0) { + printf("Fatal: error seeking in output file: %s\n", + strerror(errno)); + exit(1); + } + if (fwrite(s->buffer, s->size, 1, fp) != 1) { + printf("Fatal: error writing to output file: %s\n", + strerror(errno)); + exit(1); + } + i++; + } + + if (!quiet) printf("Wrote %i low-memory sections.\n", i); + + /* Sorted list of sections higher than 1MB: write them out */ + for (s = sections, i = 0; s; s = s->next) { + if (s->start < HIGHMEM_START) continue; + offset = (s->start - HIGHMEM_START) + BZ_SETUP_OFFSET; + if (fseek(fp, offset, SEEK_SET) < 0) { + printf("Fatal: error seeking in output file: %s\n", + strerror(errno)); + exit(1); + } + if (fwrite(s->buffer, s->size, 1, fp) != 1) { + printf("Fatal: error writing to output file: %s\n", + strerror(errno)); + exit(1); + } + i++; + } + + if (!quiet) printf("Wrote %i high-memory sections.\n", i); +} + + +/* + * EOF(buildimage.c) + */ diff --git a/tools/misc/mbootpack/mb_header.h b/tools/misc/mbootpack/mb_header.h new file mode 100644 index 0000000000..21934574f3 --- /dev/null +++ b/tools/misc/mbootpack/mb_header.h @@ -0,0 +1,90 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * MultiBoot Header description + */ + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see below. */ + unsigned magic; + + /* Feature flags - see below. */ + unsigned flags; + + /* + * Checksum + * + * The above fields plus this one must equal 0 mod 2^32. + */ + unsigned checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + unsigned header_addr; + unsigned load_addr; + unsigned load_end_addr; + unsigned bss_end_addr; + unsigned entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + unsigned mode_type; + unsigned width; + unsigned height; + unsigned 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 \ + && ! (*((unsigned *) (addr)) + *((unsigned *) (addr + 4)) \ + + *((unsigned *) (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 diff --git a/tools/misc/mbootpack/mb_info.h b/tools/misc/mbootpack/mb_info.h new file mode 100644 index 0000000000..fb37f10ff0 --- /dev/null +++ b/tools/misc/mbootpack/mb_info.h @@ -0,0 +1,217 @@ +/* + * 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 */ + unsigned long mod_start; + unsigned long mod_end; + + /* Module command line */ + unsigned long cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + unsigned long 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 +{ + unsigned long size; + unsigned long long BaseAddr; + unsigned long long Length; + unsigned long 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. */ + unsigned long size; + + /* The BIOS drive number. */ + unsigned char drive_number; + + /* The access mode (see below). */ + unsigned char drive_mode; + + /* The BIOS geometry. */ + unsigned short drive_cylinders; + unsigned char drive_heads; + unsigned char drive_sectors; + + /* The array of I/O ports used for the drive. */ + unsigned short drive_ports[0]; +}; + +/* Drive Mode. */ +#define MB_DI_CHS_MODE 0 +#define MB_DI_LBA_MODE 1 + + +/* APM BIOS info. */ +struct apm_info +{ + unsigned short version; + unsigned short cseg; + unsigned long offset; + unsigned short cseg_16; + unsigned short dseg_16; + unsigned short cseg_len; + unsigned short cseg_16_len; + unsigned short 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 */ + unsigned long flags; + + /* Available memory from BIOS */ + unsigned long mem_lower; + unsigned long mem_upper; + + /* "root" partition */ + unsigned long boot_device; + + /* Kernel command line */ + unsigned long cmdline; + + /* Boot-Module list */ + unsigned long mods_count; + unsigned long mods_addr; + + union + { + struct + { + /* (a.out) Kernel symbol table info */ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long pad; + } + a; + + struct + { + /* (ELF) Kernel section header table */ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; + } + e; + } + syms; + + /* Memory Mapping buffer */ + unsigned long mmap_length; + unsigned long mmap_addr; + + /* Drive Info buffer */ + unsigned long drives_length; + unsigned long drives_addr; + + /* ROM configuration table */ + unsigned long config_table; + + /* Boot Loader Name */ + unsigned long boot_loader_name; + + /* APM table */ + unsigned long apm_table; + + /* Video */ + unsigned long vbe_control_info; + unsigned long vbe_mode_info; + unsigned short vbe_mode; + unsigned short vbe_interface_seg; + unsigned short vbe_interface_off; + unsigned short 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 diff --git a/tools/misc/mbootpack/mbootpack.c b/tools/misc/mbootpack/mbootpack.c new file mode 100644 index 0000000000..42a3151cd9 --- /dev/null +++ b/tools/misc/mbootpack/mbootpack.c @@ -0,0 +1,703 @@ +/* + * mbootpack.c + * + * Takes a multiboot image, command-line and modules, and repackages + * them as if they were a linux kernel. Only supports a subset of + * the multiboot info page options (enough to boot the Xen hypervisor). + * + * Copyright (C) 2003-2004 Tim Deegan (tjd21@cl.cam.ac.uk) + * + * Parts based on GNU GRUB, 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * $Id: mbootpack.c,v 1.3 2005/03/23 10:38:36 tjd21 Exp tjd21 $ + * + */ + +#define _GNU_SOURCE +#include "mbootpack.h" + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <getopt.h> +#include <elf.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <asm/page.h> + +/* From GNU GRUB */ +#include "mb_header.h" +#include "mb_info.h" + + +/* + * The plan: Marshal up the multiboot modules and strings as if we + * were loading them into memory on a fresh ix86 PC. Attach + * a linux bzImage header to the front, which sets up the machine + * appropriately and then jumps to the kernel entry address. + * + * The memory map will be made up roughly like so: + * + * ============= + * multiboot information (mbi) struct + * ------- + * kernel command line + * ------- + * bootloader name + * ------- + * module command lines + * ------- + * module information structs + * ============= + * (memory hole) + * ============= + * kernel + * ------------- + * module 1 + * ------------- + * module 2 + * ------------- + * . + * . + * . + * + * ============== + * + * + * For allocation of memory we assume that the target machine has 'low' + * memory from 0 to 640K and 'high' memory starting at 1M. We allocate + * the kernel first, wherever it wants to be. After that, sections + * are added at the next available aligned address, always in the order + * given above, and skipping the memory hole at 640K. Allocated sections + * are stored in a linked list of buffers. + * + * Re-packaging as a bzImage file happens in buildimage.c + * + */ + +/* Version */ +static const char version_string[] = "mbootpack " MBOOTPACK_VERSION_STRING; + +/* Flags */ +int quiet = 0; + +/* How much of the start of a kernel we read looking for headers. + * Must be >= MULTIBOOT_SEARCH */ +#define HEADERBUF_SIZE MULTIBOOT_SEARCH + + +/* Linked list of loaded sections, and a pointer to the next + * available space (i.e. just above the highest allocation so far). */ +static section_t *sections = NULL; +static section_t *last_section = NULL; +static address_t next_free_space = 0; + +static void usage(void) +/* If we don't understand the command-line options */ +{ + printf( +"Usage: mbpack [OPTIONS] kernel-image\n\n" +" -h --help Print this text.\n" +" -q --quiet Only output errors and warnings.\n" +" -o --output=filename Output to filename (default \"bzImage\").\n" +" -M --multiboot-output Produce a multiboot kernel, not a bzImage\n" +" (sets default output file to \"mbImage\").\n" +" -c --command-line=STRING Set the kernel command line (DEPRECATED!).\n" +" -m --module=\"MOD arg1 arg2...\" Load module MOD with arguments \"arg1...\"\n" +" (can be used multiple times).\n" +"\n"); + exit(1); +} + + +static void place_kernel_section(address_t start, long int size) +/* Place the kernel in memory, checking for the memory hole. */ +{ + if (start >= MEM_HOLE_END) { + /* Above the memory hole: easy */ + next_free_space = MAX(next_free_space, start + size); + if (!quiet) { + printf("Placed kernel section (%p+%p)\n", start, size); + } + return; + } + + if (start >= MEM_HOLE_START) { + /* In the memory hole. Not so good */ + printf("Fatal: kernel load address (%p) is in the memory hole.\n", + start); + exit(1); + } + + if (start + size > MEM_HOLE_START) { + /* Too big for low memory */ + printf("Fatal: kernel (%p+%p) runs into the memory hole.\n", + start, size); + exit(1); + } + + /* Kernel loads below the memory hole */ + next_free_space = MAX(next_free_space, start + size); + + if (!quiet) { + printf("Placed kernel section (%p+%p)\n", start, size); + } +} + + +static address_t place_section(long int size, int align) +/* Find the next available place for this section. + * "align" must be a power of 2 */ +{ + address_t start; + assert(next_free_space != 0); + assert(((~align + 1) & align) == align); + + start = ROUNDUP_P2(next_free_space, align); + + /* Check that we don't hit the memory hole */ + if (start < MEM_HOLE_END && (start + size) > MEM_HOLE_START) + start = ROUNDUP_P2(MEM_HOLE_END, align); + + next_free_space = start + size; + + if (!quiet) { + printf("Placed section (%p+%p), align=%p\n", + start, size, align); + } + return start; +} + + + + +static address_t load_kernel(const char *filename) +/* Load an elf32/multiboot kernel from this file + * Returns the entry address for the kernel. */ +{ + unsigned int i; + address_t start; + size_t len; + long int size, loadsize; + FILE *fp; + char *buffer; + section_t *sec, *s; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + struct multiboot_header *mbh; + struct stat sb; + + static char headerbuf[HEADERBUF_SIZE]; + + /* Stat and open the file */ + if (stat(filename, &sb) != 0) { + printf("Fatal: cannot stat %s: %s\n", filename, strerror(errno)); + exit(1); + } + if ((fp = fopen(filename, "r")) == NULL) { + printf("Fatal: cannot open %s: %s\n", filename, strerror(errno)); + exit(1); + } + + /* Load the first 8k of the file */ + if (fseek(fp, 0, SEEK_SET) < 0) { + printf("Fatal: seek error in %s: %s\n", filename, strerror(errno)); + exit(1); + } + if ((len = fread(headerbuf, 1, HEADERBUF_SIZE, fp)) + < HEADERBUF_SIZE) + { + if (feof(fp)) /* Short file */ + { + if (len < 12) { + printf("Fatal: %s is too short to be a multiboot file.", + filename); + exit(1); + } + } else { + printf("Fatal: read error in %s: %s\n", filename, strerror(errno)); + exit(1); + } + } + + /* Sanity-check: is this file compressed? */ + if ((headerbuf[0] == '\037' && + (headerbuf[1] == '\235' /* .Z */ || + headerbuf[1] == '\213' /* .gz */)) || + (headerbuf[0] == 'B' && headerbuf[1] == 'Z') /* .bz[2] */) { + printf("Warning: %s looks like a compressed file.\n" + " You should uncompress it first!\n", filename); + } + + /* Now look for a multiboot header */ + for (i = 0; i <= MIN(len - 12, MULTIBOOT_SEARCH - 12); i += 4) + { + 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_UNSUPPORTED) { + /* Requires options we don't support */ + printf("Fatal: found a multiboot header, but it " + "requires multiboot options that I\n" + "don't understand. Sorry.\n"); + exit(1); + } + if (mbh->flags & MULTIBOOT_VIDEO_MODE) { + /* Asked for screen mode information */ + /* XXX carry on regardless */ + printf("Warning: found a multiboot header which asks " + "for screen mode information.\n" + " This kernel will NOT be given valid" + "screen mode information at boot time.\n"); + } + /* This kernel will do: place and load it */ + + if (mbh->flags & MULTIBOOT_AOUT_KLUDGE) { + + /* Load using the offsets in the multiboot header */ + if(!quiet) + printf("Loading %s using multiboot header.\n", filename); + + /* How much is there? */ + start = mbh->load_addr; + if (mbh->load_end_addr != 0) + loadsize = mbh->load_end_addr - mbh->load_addr; + else + loadsize = sb.st_size; + + /* How much memory will it take up? */ + if (mbh->bss_end_addr != 0) + size = mbh->bss_end_addr - mbh->load_addr; + else + size = loadsize; + + if (loadsize > size) { + printf("Fatal: can't load %i bytes of kernel into %i bytes " + "of memory.\n", loadsize, size); + exit(1); + } + + /* Does it fit where it wants to be? */ + place_kernel_section(start, size); + + /* Load the kernel */ + if ((buffer = malloc(size)) == NULL) { + printf("Fatal: malloc() for kernel load failed: %s\n", + strerror(errno)); + exit(1); + } + if ((fread(buffer, loadsize, 1, fp)) != 1) { + printf("Fatal: cannot read %s: %s\n", + filename, strerror(errno)); + exit(1); + } + fclose(fp); + + /* Clear the kernel BSS */ + memset(buffer + loadsize, 0, size - loadsize); + + /* Start off the linked list of sections */ + if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) { + printf("Fatal: malloc() for section_t failed: %s\n", + strerror(errno)); + exit(1); + } + sec->buffer = buffer; + sec->start = start; + sec->size = size; + sec->next = NULL; + sec->prev = NULL; + sections = sec; + last_section = sec; + + /* Done. */ + if (!quiet) printf("Loaded kernel from %s\n", filename); + return mbh->entry_addr; + + } else { + + /* Now look for an ELF32 header */ + ehdr = (Elf32_Ehdr *)headerbuf; + if (*(unsigned long *)ehdr != 0x464c457f + || ehdr->e_ident[EI_DATA] != ELFDATA2LSB + || ehdr->e_ident[EI_CLASS] != ELFCLASS32 + || ehdr->e_machine != EM_386) + { + printf("Fatal: kernel has neither ELF32/x86 nor multiboot load" + " headers.\n"); + exit(1); + } + if (ehdr->e_phoff + ehdr->e_phnum*sizeof(*phdr) > HEADERBUF_SIZE) { + /* Don't expect this will happen with sane kernels */ + printf("Fatal: too much ELF for me. Try increasing " + "HEADERBUF_SIZE in mbootpack.\n"); + exit(1); + } + if (ehdr->e_phoff + ehdr->e_phnum*sizeof (*phdr) > len) { + printf("Fatal: malformed ELF header overruns EOF.\n"); + exit(1); + } + if (ehdr->e_phnum <= 0) { + printf("Fatal: ELF kernel has no program headers.\n"); + exit(1); + } + + if(!quiet) + printf("Loading %s using ELF header.\n", filename); + + if (ehdr->e_type != ET_EXEC + || ehdr->e_version != EV_CURRENT + || ehdr->e_phentsize != sizeof (Elf32_Phdr)) { + printf("Warning: funny-looking ELF header.\n"); + } + phdr = (Elf32_Phdr *)(headerbuf + ehdr->e_phoff); + + /* Obey the program headers to load the kernel */ + for(i = 0; i < ehdr->e_phnum; i++) { + + start = phdr[i].p_paddr; + size = phdr[i].p_memsz; + if (phdr[i].p_type != PT_LOAD) + loadsize = 0; + else + loadsize = MIN((long int)phdr[i].p_filesz, size); + + if ((buffer = malloc(size)) == NULL) { + printf("Fatal: malloc() for kernel load failed: %s\n", + strerror(errno)); + exit(1); + } + + /* Place the section where it wants to be */ + place_kernel_section(start, size); + + /* Load section from file */ + if (loadsize > 0) { + if (fseek(fp, phdr[i].p_offset, SEEK_SET) != 0) { + printf("Fatal: seek failed in %s\n", + strerror(errno)); + exit(1); + } + if ((fread(buffer, loadsize, 1, fp)) != 1) { + printf("Fatal: cannot read %s: %s\n", + filename, strerror(errno)); + exit(1); + } + } + + /* Clear the rest of the buffer */ + memset(buffer + loadsize, 0, size - loadsize); + + /* Add this section to the list (keeping it ordered) */ + if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) { + printf("Fatal: malloc() for section_t failed: %s\n", + strerror(errno)); + exit(1); + } + sec->buffer = buffer; + sec->start = start; + sec->size = size; + + for(s = sections; s; s = s->next) { + if (s->start > start) { + sec->next = s; + if (s->prev == NULL) { + /* sec becomes the new first item */ + s->prev = sec; + sections = sec; + } else { + /* sec goes between s->prev and s */ + sec->prev = s->prev; + sec->prev->next = sec; + s->prev = sec; + } + break; + } + } + if (s == NULL) { + /* sec becomes the new last item */ + sec->next = NULL; + sec->prev = last_section; + if (last_section) { + last_section->next = sec; + } else { + sections = sec; + } + last_section = sec; + } + } + + /* Done! */ + if (!quiet) printf("Loaded kernel from %s\n", filename); + return ehdr->e_entry; + } + + } + + /* This is not a multiboot kernel */ + printf("Fatal: %s is not a multiboot kernel.\n", filename); + exit(1); +} + + + + +int main(int argc, char **argv) +{ + char *buffer, *imagename, *command_line, *p; + char *mod_filename, *mod_command_line, *mod_clp; + char *out_filename; + section_t *sec; + FILE *fp; + struct stat sb; + struct multiboot_info *mbi; + struct mod_list *modp; + address_t start, kernel_entry; + long int size, mod_command_line_space, command_line_len; + int modules, opt, mbi_reloc_offset, make_multiboot; + + static const char short_options[] = "hc:m:o:qM"; + static const struct option options[] = { + { "help", 0, 0, 'h' }, + { "command-line", 1, 0, 'c' }, + { "append", 1, 0, 'c' }, + { "module", 1, 0, 'm' }, + { "output", 1, 0, 'o' }, + { "quiet", 0, 0, 'q' }, + { 0, 0, 0, 0 }, + }; + + /* Parse the command line */ + out_filename = NULL; + command_line = ""; + command_line_len = 0; + modules = 0; + mod_command_line_space = 0; + while((opt = getopt_long(argc, argv, short_options, options, 0)) != -1) + { + switch(opt) { + case 'c': + command_line = optarg; + break; + case 'm': + modules++; + mod_command_line_space += strlen(optarg) + 1; + break; + case 'o': + out_filename = optarg; + break; + case 'q': + quiet = 1; + break; + case 'h': + case '?': + default: + usage(); + } + } + imagename = argv[optind]; + if (!imagename || strlen(imagename) == 0) usage(); + command_line_len = strlen(command_line) + strlen(imagename) + 2; + /* Leave space to overwritethe command-line at boot time */ + command_line_len = MAX(command_line_len, CMD_LINE_SPACE); + if (!out_filename) out_filename = "bzImage"; + + /* Place and load the kernel */ + kernel_entry = load_kernel(imagename); + assert(sections != NULL); + assert(last_section != NULL); + assert(next_free_space != 0); + + /* Next section is all the metadata between kernel and modules */ + size = ((((sizeof (struct multiboot_info) + + command_line_len + + strlen(version_string) + 1 + + mod_command_line_space) + + 3 ) & ~3) + + modules * sizeof (struct mod_list)); + /* Locate this section after the setup sectors, in *low* memory */ + start = place_mbi(size); + + if ((buffer = malloc(size)) == NULL) { + printf("Fatal: malloc() for boot metadata failed: %s\n", + strerror(errno)); + exit(1); + } + + if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) { + printf("Fatal: malloc() for section_t failed: %s\n", + strerror(errno)); + exit(1); + } + sec->buffer = buffer; + sec->start = start; + sec->size = size; + sec->next = NULL; + sec->prev = last_section; + last_section->next = sec; + last_section = sec; + + /* Multiboot info struct */ + mbi = (struct multiboot_info *)buffer; + memset(buffer, 0, sizeof (struct multiboot_info)); + mbi_reloc_offset = start - (address_t)buffer; + + /* Command line */ + p = (char *)(mbi + 1); + sprintf(p, "%s %s", imagename, command_line); + mbi->cmdline = ((address_t)p) + mbi_reloc_offset; + p += command_line_len; + + /* Bootloader ID */ + sprintf(p, version_string); + mbi->boot_loader_name = ((address_t)p) + mbi_reloc_offset; + p += strlen(version_string) + 1; + + /* Next is space for the module command lines */ + mod_clp = p; + + /* Last come the module info structs */ + modp = (struct mod_list *) + ((((address_t)p + mod_command_line_space) + 3) & ~3); + mbi->mods_count = modules; + mbi->mods_addr = ((address_t)modp) + mbi_reloc_offset; + + /* Memory information will be added at boot time, by setup.S + * or trampoline.S. */ + mbi->flags = MB_INFO_CMDLINE | MB_INFO_BOOT_LOADER_NAME; + + + /* Load the modules */ + if (modules) { + mbi->flags |= MB_INFO_MODS; + + /* Go back and parse the module command lines */ + optind = opterr = 1; + while((opt = getopt_long(argc, argv, + short_options, options, 0)) != -1) + { + if (opt != 'm') continue; + + /* Split module filename from command line */ + mod_command_line = mod_filename = optarg; + if ((p = strchr(mod_filename, ' ')) != NULL) { + /* See as I discard the 'const' modifier */ + *p = '\0'; + } + + /* Find space for it */ + if (stat(mod_filename, &sb) != 0) { + printf("Fatal: cannot stat %s: %s\n", + mod_filename, strerror(errno)); + exit(1); + } + size = sb.st_size; + start = place_section(size, X86_PAGE_SIZE); + /* XXX should be place_section(size, 4) if the MBH hasn't got + * XXX MULTIBOOT_PAGE_ALIGN set, but that breaks Xen */ + + /* Load it */ + if ((buffer = malloc(sb.st_size)) == NULL) { + printf("Fatal: malloc failed for module load: %s\n", + strerror(errno)); + exit(1); + } + if ((fp = fopen(mod_filename, "r")) == NULL) { + printf("Fatal: cannot open %s: %s\n", + mod_filename, strerror(errno)); + exit(1); + } + if ((fread(buffer, sb.st_size, 1, fp)) != 1) { + printf("Fatal: cannot read %s: %s\n", + mod_filename, strerror(errno)); + exit(1); + } + fclose(fp); + + /* Sanity-check: is this file compressed? */ + if ((buffer[0] == '\037' && + (buffer[1] == '\235' /* .Z */ || + buffer[1] == '\213' /* .gz */)) || + (buffer[0] == 'B' && buffer[1] == 'Z') /* .bz[2] */) { + printf("Warning: %s looks like a compressed file.\n", + mod_filename); + } + + if (!quiet) printf("Loaded module from %s\n", mod_filename); + + /* Restore the command line to its former glory */ + if (p != NULL) *p = ' '; + + /* Fill in the module info struct */ + modp->mod_start = start; + modp->mod_end = start + size; + modp->cmdline = (address_t)mod_clp + mbi_reloc_offset; + modp->pad = 0; + modp++; + + /* Store the module command line */ + sprintf(mod_clp, "%s", mod_command_line); + mod_clp += strlen(mod_clp) + 1; + + /* Add the section to the list */ + if ((sec = (section_t *)malloc(sizeof (section_t))) == NULL) { + printf("Fatal: malloc() for section_t failed: %s\n", + strerror(errno)); + exit(1); + } + sec->buffer = buffer; + sec->start = start; + sec->size = size; + sec->next = NULL; + sec->prev = last_section; + last_section->next = sec; + last_section = sec; + + } + + } + + /* Everything is placed and loaded. Now we package it all up + * as a bzImage */ + if ((fp = fopen(out_filename, "w")) == NULL) { + printf("Fatal: cannot open %s: %s\n", out_filename, strerror(errno)); + exit(1); + } + make_bzImage(sections, + kernel_entry, + ((address_t)mbi) + mbi_reloc_offset, + fp); + fclose(fp); + + /* Success! */ + if(!quiet) printf("Finished.\n"); + return 0; +} + +/* + * EOF (mbootpack.c) + */ + diff --git a/tools/misc/mbootpack/mbootpack.h b/tools/misc/mbootpack/mbootpack.h new file mode 100644 index 0000000000..b28718b88c --- /dev/null +++ b/tools/misc/mbootpack/mbootpack.h @@ -0,0 +1,91 @@ +/* + * mbootpack.h + * + * Common definitions for mbootpack + * + * Copyright (C) 2003-2004 Tim Deegan (tjd21@cl.cam.ac.uk) + * + * 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. + * + * $Id: mbootpack.h,v 1.2 2005/03/23 10:38:37 tjd21 Exp $ + * + */ + +#ifndef __MBOOTPACK__H__ +#define __MBOOTPACK__H__ + +#ifndef __MB_ASM + +#undef NDEBUG +#include <stdio.h> + +/* Flags */ +extern int quiet; + +/* Types */ +typedef unsigned long address_t; + +typedef struct section_t { + char *buffer; + address_t start; + long int size; + struct section_t *prev; + struct section_t *next; +} section_t; + +/* buildimage.c */ +extern void make_bzImage(section_t *sections, + address_t entry, + address_t mbi, + FILE *fp); + +address_t place_mbi(long int size); + + +/* trampoline.S */ +extern unsigned char mb_trampoline[]; +extern unsigned char mb_trampoline_end[]; +extern volatile address_t mb_mbi_address, mb_entry_address; + +/* Macros */ +#define MIN(_x,_y) (((_x)<=(_y))?(_x):(_y)) +#define MAX(_x,_y) (((_x)<=(_y))?(_y):(_x)) +#define ROUNDUP_P2(_x, _a) (((_x)+((_a)-1))&(~((_a)-1))) + +#endif + +/* x86 memory: such fun */ +#define MEM_HOLE_START 0xa0000 +#define MEM_HOLE_END 0x100000 +#define HIGHMEM_START MEM_HOLE_END +#define X86_PAGE_SIZE 0x1000 + +/* How much command line we'll take from the bootloader. */ +#define CMD_LINE_SPACE 0x300 + +/* Number of 512-byte sectors to load in low memory (max 7) */ +#define SETUPSECTS 7 + + +/* Who are we? */ +#define MBOOTPACK_VERSION_STRING "v0.2 (alpha)" + +#endif /* __MBOOTPACK__H__ */ + +/* + * EOF (mbootpack.h) + */ + diff --git a/tools/misc/mbootpack/setup.S b/tools/misc/mbootpack/setup.S new file mode 100644 index 0000000000..f429312df6 --- /dev/null +++ b/tools/misc/mbootpack/setup.S @@ -0,0 +1,1064 @@ +/* + * bootsect.S + * + * This is setup.S from the linux 2.6.9 source code, + * with heavy cuts and changes for mbootpack + * November 2004 Tim Deegan <tjd21@cl.cam.ac.uk> + * + * + * 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. + * + * $Id: setup.S,v 1.4 2005/03/23 10:39:03 tjd21 Exp $ + * + */ + +#include "mbootpack.h" + +/* + * setup.S Copyright (C) 1991, 1992 Linus Torvalds + * + * setup.s is responsible for getting the system data from the BIOS, + * and putting them into the appropriate places in system memory. + * both setup.s and system has been loaded by the bootblock. + * + * This code asks the bios for memory/disk/other parameters, and + * puts them in a "safe" place: 0x90000-0x901FF, ie where the + * boot-block used to be. It is then up to the protected mode + * system to read them from there before the area is overwritten + * for buffer-blocks. + * + * Move PS/2 aux init code to psaux.c + * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 + * + * some changes and additional features by Christoph Niemann, + * March 1993/June 1994 (Christoph.Niemann@linux.org) + * + * add APM BIOS checking by Stephen Rothwell, May 1994 + * (sfr@canb.auug.org.au) + * + * High load stuff, initrd support and position independency + * by Hans Lermen & Werner Almesberger, February 1996 + * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch> + * + * Video handling moved to video.S by Martin Mares, March 1996 + * <mj@k332.feld.cvut.cz> + * + * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david + * parsons) to avoid loadlin confusion, July 1997 + * + * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. + * <stiker@northlink.com> + * + * Fix to work around buggy BIOSes which dont use carry bit correctly + * and/or report extended memory in CX/DX for e801h memory size detection + * call. As a result the kernel got wrong figures. The int15/e801h docs + * from Ralf Brown interrupt list seem to indicate AX/BX should be used + * anyway. So to avoid breaking many machines (presumably there was a reason + * to orginally use CX/DX instead of AX/BX), we do a kludge to see + * if CX/DX have been changed in the e801 call and if so use AX/BX . + * Michael Miller, April 2001 <michaelm@mjmm.org> + * + * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes + * by Robert Schwebel, December 2001 <robert@schwebel.de> + */ + +/* +#include <linux/config.h> +#include <asm/segment.h> +#include <linux/version.h> +#include <linux/compile.h> +#include <asm/boot.h> +#include <asm/e820.h> +#include <asm/page.h> +*/ + +/* Definitions that should have come from these includes */ +#define DEF_INITSEG 0x9000 +#define DEF_SYSSEG 0x1000 +#define DEF_SETUPSEG 0x9020 +#define DEF_SYSSIZE 0x7F00 +#define NORMAL_VGA 0xffff +#define EXTENDED_VGA 0xfffe +#define ASK_VGA 0xfffd +#define GDT_ENTRY_BOOT_CS 2 +#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8) +#define GDT_ENTRY_BOOT_DS (GDT_ENTRY_BOOT_CS + 1) +#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8) +#define __PAGE_OFFSET (0xC0000000) +#define E820MAP 0x2d0 /* our map */ +#define E820MAX 32 /* number of entries in E820MAP */ +#define E820NR 0x1e8 /* # entries in E820MAP */ +#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 +#define __BIG_KERNEL__ + + +/* Signature words to ensure LILO loaded us right */ +#define SIG1 0xAA55 +#define SIG2 0x5A5A + +INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way +SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). +SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment + # ... and the former contents of CS + +DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020 + +.code16 +.globl _start, begtext, begdata, begbss, endtext, enddata, endbss + +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +_start: +start: + jmp trampoline + +# This is the setup header, and it must start at %cs:2 (old 0x9020:2) + + .ascii "HdrS" # header signature + .word 0x0203 # header version number (>= 0x0105) + # or else old loadlin-1.5 will fail) +realmode_swtch: .word 0, 0 # default_switch, SETUPSEG +start_sys_seg: .word SYSSEG + .word kernel_version # pointing to kernel version string + # above section of header is compatible + # with loadlin-1.5 (header v1.5). Don't + # change it. + +type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, + # Bootlin, SYSLX, bootsect...) + # See Documentation/i386/boot.txt for + # assigned ids + +# flags, unused bits must be zero (RFU) bit within loadflags +loadflags: +LOADED_HIGH = 1 # If set, the kernel is loaded high +CAN_USE_HEAP = 0x80 # If set, the loader also has set + # heap_end_ptr to tell how much + # space behind setup.S can be used for + # heap purposes. + # Only the loader knows what is free +#ifndef __BIG_KERNEL__ + .byte 0 +#else + .byte LOADED_HIGH +#endif + +setup_move_size: .word 0x8000 # size to move, when setup is not + # loaded at 0x90000. We will move setup + # to 0x90000 then just before jumping + # into the kernel. However, only the + # loader knows how much data behind + # us also needs to be loaded. + +/* N.B. these next addresses are entirely ignored by this code -- it + * assumes it was loaded with the 32bit code at 0x100000, and doesn't + * touch the ramdisk. */ +code32_start: # here loaders can put a different + # start address for 32-bit code. +#ifndef __BIG_KERNEL__ + .long 0x1000 # 0x1000 = default for zImage +#else + .long 0x100000 # 0x100000 = default for big kernel +#endif + +ramdisk_image: .long 0 # address of loaded ramdisk image + # Here the loader puts the 32-bit + # address where it loaded the image. + # This only will be read by the kernel. + +ramdisk_size: .long 0 # its size in bytes + +bootsect_kludge: + .long 0 # obsolete + +heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later) + # space from here (exclusive) down to + # end of setup code can be used by setup + # for local heap purposes. + +pad1: .word 0 +cmd_line_ptr: .long 0 # (Header version 0x0202 or later) + # If nonzero, a 32-bit pointer + # to the kernel command line. + # The command line should be + # located between the start of + # setup and the end of low + # memory (0xa0000), or it may + # get overwritten before it + # gets read. If this field is + # used, there is no longer + # anything magical about the + # 0x90000 segment; the setup + # can be located anywhere in + # low memory 0x10000 or higher. + +ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff + # (Header version 0x0203 or later) + # The highest safe address for + # the contents of an initrd + +/* Add more known locations: the image builder will overwrite + * these with the entry point and MBI location for the multiboot kernel. + * These offsets *must* match the definitions in buildimage.c */ + +entry_address: .long 0 # This will be offset 0x30 (0x230 from b'sect) +mbi_address: .long 0 # This will be offset 0x34 + +/* Storage space for the size of memory */ +highmem_size: .long 0 + +trampoline: call start_of_setup + .space 1024 +# End of setup header ##################################################### + +start_of_setup: +# Bootlin depends on this being done early + movw $0x01500, %ax + movb $0x81, %dl + int $0x13 + +#ifdef SAFE_RESET_DISK_CONTROLLER +# Reset the disk controller. + movw $0x0000, %ax + movb $0x80, %dl + int $0x13 +#endif + +# Set %ds = %cs, we know that SETUPSEG = %cs at this point + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds + +# Check signature at end of setup + cmpw $SIG1, setup_sig1 + jne bad_sig + + cmpw $SIG2, setup_sig2 + jne bad_sig + + jmp good_sig1 + +# Routine to print asciiz string at ds:si +prtstr: + lodsb + andb %al, %al + jz fin + + call prtchr + jmp prtstr + +fin: ret + +# Space printing +prtsp2: call prtspc # Print double space +prtspc: movb $0x20, %al # Print single space (note: fall-thru) + +# Part of above routine, this one just prints ascii al +prtchr: pushw %ax + pushw %cx + movw $7,%bx + movw $0x01, %cx + movb $0x0e, %ah + int $0x10 + popw %cx + popw %ax + ret + +beep: movb $0x07, %al + jmp prtchr + +no_sig_mess: .string "No setup signature found ..." + +good_sig1: + jmp good_sig + +# We now have to find the rest of the setup code/data +bad_sig: + movw %cs, %ax # SETUPSEG + subw $DELTA_INITSEG, %ax # INITSEG + movw %ax, %ds + xorb %bh, %bh + movb (497), %bl # get setup sect from bootsect + subw $4, %bx # LILO loads 4 sectors of setup + shlw $8, %bx # convert to words (1sect=2^8 words) + movw %bx, %cx + shrw $3, %bx # convert to segment + addw $SYSSEG, %bx + movw %bx, %cs:start_sys_seg +# Move rest of setup code/data to here + movw $2048, %di # four sectors loaded by LILO + subw %si, %si + pushw %cs + popw %es + movw $SYSSEG, %ax + movw %ax, %ds + rep + movsw + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds + cmpw $SIG1, setup_sig1 + jne no_sig + + cmpw $SIG2, setup_sig2 + jne no_sig + + jmp good_sig + +no_sig: + lea no_sig_mess, %si + call prtstr + +no_sig_loop: + hlt + jmp no_sig_loop + +mb_hello_mess1: + .string "mboot" + +good_sig: + lea mb_hello_mess1, %si + call prtstr + + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ax, %ds +# Check if an old loader tries to load a big-kernel + testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel? + jz loader_ok # No, no danger for old loaders. + + cmpb $0, %cs:type_of_loader # Do we have a loader that + # can deal with us? + jnz loader_ok # Yes, continue. + + pushw %cs # No, we have an old loader, + popw %ds # die. + lea loader_panic_mess, %si + call prtstr + + jmp no_sig_loop + +loader_panic_mess: .string "Wrong loader, giving up..." + +loader_ok: + +# Get memory size (extended mem, kB) + +/* We'll be storing this in highmem_size, to be copied to the mbi */ + +# Try three different memory detection schemes. First, try +# e820h, which lets us assemble a memory map, then try e801h, +# which returns a 32-bit memory size, and finally 88h, which +# returns 0-64m + + xorl %edx, %edx + xorl %eax, %eax + movl %eax, (0x1e0) + movl %eax, highmem_size + movb %al, (E820NR) + +# 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.acpi.info/, in the ACPI 2.0 specification. + +#define SMAP 0x534d4150 + +meme820: + xorl %ebx, %ebx # continuation counter + movw $E820MAP, %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 $20, %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), %al # up to 32 entries + cmpb $E820MAX, %al + jnl bail820 + + incb (E820NR) + movw %di, %ax + addw $20, %ax + movw %ax, %di +again820: + cmpl $0, %ebx # check to see if + jne jmpe820 # %ebx is set to EOF + +/* Multiboot spec says high mem should be the address of the first + * upper memory hole, minus 1 MB */ + xorl %ebx, %ebx + xorl %ecx, %ecx + xorl %edx, %edx + movw $E820MAP, %di # Start at the beginning +calc_highmem_loop: + cmpl $1, 16(%di) # is it usable memory? + jnz calc_highmem_next + cmpl $0, 4(%di) # is base < 4GB? + jnz calc_highmem_next + cmpl $0x100000, 0(%di) # is base <= 1MB? + jg calc_highmem_next + movl 8(%di), %ecx # Calculate base+length + shrl $10, %ecx # in kilobytes + movl 12(%di), %edx + shll $22, %edx + orl %edx, %ecx + movl 0(%di), %edx + shrl $10, %edx + addl %edx, %ecx + subl $1024, %ecx # - 1 MB + cmpl %cs:highmem_size, %ecx + jl calc_highmem_next + movl %ecx, %cs:highmem_size +calc_highmem_next: + add $1, %bl + add $20, %di + cmp %bl, (E820NR) + je calc_highmem_done + jmp calc_highmem_loop +calc_highmem_done: + +bail820: + +# method E801H: +# memory size is in 1k chunksizes, to avoid confusing loadlin. + +meme801: + 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 mem88 + + 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 + andl $0xffff, %ecx # clear sign extend + addl %ecx, %edx + + cmpl %cs:highmem_size, %edx # store extended mem size + jl mem88 # if it's bigger than + movl %edx, %cs:highmem_size # what we already have + +# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or +# 64mb, depending on the bios) in ax. +mem88: + movb $0x88, %ah + int $0x15 + + andl $0xffff, %eax # clear sign extend + cmpl %cs:highmem_size, %eax # store extended mem size + jl have_memsize # if it's bigger than + movl %eax, %cs:highmem_size # what we already have + +have_memsize: + +/* Culled: HDD probes, APM, speedstep */ + +# Now we want to move to protected mode ... + cmpw $0, %cs:realmode_swtch + jz rmodeswtch_normal + + lcall *%cs:realmode_swtch + + jmp rmodeswtch_end + +rmodeswtch_normal: + pushw %cs + call default_switch + +rmodeswtch_end: + +/* Culled: code to take the 32bit entry address from the loader */ +/* Culled: code to relocate non-bzImage kernels */ + + # then we load the segment descriptors + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds + +# Check whether we need to be downward compatible with version <=201 + cmpl $0, cmd_line_ptr + jne end_move_self # loader uses version >=202 features + cmpb $0x20, type_of_loader + je end_move_self # bootsect loader, we know of it + +# Boot loader doesnt support boot protocol version 2.02. +# If we have our code not at 0x90000, we need to move it there now. +# We also then need to move the params behind it (commandline) +# Because we would overwrite the code on the current IP, we move +# it in two steps, jumping high after the first one. + movw %cs, %ax + cmpw $SETUPSEG, %ax + je end_move_self + + cli # make sure we really have + # interrupts disabled ! + # because after this the stack + # should not be used + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ss, %dx + cmpw %ax, %dx + jb move_self_1 + + addw $INITSEG, %dx + subw %ax, %dx # this will go into %ss after + # the move +move_self_1: + movw %ax, %ds + movw $INITSEG, %ax # real INITSEG + movw %ax, %es + movw %cs:setup_move_size, %cx + std # we have to move up, so we use + # direction down because the + # areas may overlap + movw %cx, %di + decw %di + movw %di, %si + subw $move_self_here+0x200, %cx + rep + movsb + ljmp $SETUPSEG, $move_self_here + +move_self_here: + movw $move_self_here+0x200, %cx + rep + movsb + movw $SETUPSEG, %ax + movw %ax, %ds + movw %dx, %ss +end_move_self: # now we are at the right place + +# +# Enable A20. This is at the very best an annoying procedure. +# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin. +# AMD Elan bug fix by Robert Schwebel. +# + +#if defined(CONFIG_X86_ELAN) + movb $0x02, %al # alternate A20 gate + outb %al, $0x92 # this works on SC410/SC520 +a20_elan_wait: + call a20_test + jz a20_elan_wait + jmp a20_done +#endif + + +A20_TEST_LOOPS = 32 # Iterations per wait +A20_ENABLE_LOOPS = 255 # Total loops to try + + +#ifndef CONFIG_X86_VOYAGER +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 +#endif /* CONFIG_X86_VOYAGER */ +a20_kbc: + call empty_8042 + +#ifndef CONFIG_X86_VOYAGER + call a20_test # Just in case the BIOS worked + jnz a20_done # but had a delayed reaction. +#endif + + movb $0xD1, %al # command write + outb %al, $0x64 + call empty_8042 + + movb $0xDF, %al # A20 on + outb %al, $0x60 + call empty_8042 + +#ifndef CONFIG_X86_VOYAGER + # 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 # don't 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) + jnz a20_try_loop + + movw $a20_err_msg, %si + call prtstr + +a20_die: + hlt + jmp a20_die + +a20_tries: + .byte A20_ENABLE_LOOPS + +a20_err_msg: + .ascii "linux: fatal error: A20 gate not responding!" + .byte 13, 10, 0 + + # If we get here, all is good +a20_done: + + +#endif /* CONFIG_X86_VOYAGER */ + +/* Another print, to show protected mode and A20 are OK */ + + jmp mb_hello_mess2_end +mb_hello_mess2: + .string "pack " +mb_hello_mess2_end: + lea mb_hello_mess2, %si + call prtstr + +# set up gdt and idt +/* lidt idt_48 # load idt with 0,0 */ +/* Multiboot kernels must set up their own IDT: leave this for now, + * so we can print diagnostics */ + + xorl %eax, %eax # Compute gdt_base + movw %ds, %ax # (Convert %ds:gdt to a linear ptr) + shll $4, %eax + addl $gdt, %eax + movl %eax, (gdt_48+2) + lgdt gdt_48 # load gdt with whatever is + # appropriate + +# make sure any possible coprocessor is properly reset.. + xorw %ax, %ax + outb %al, $0xf0 + call delay + + outb %al, $0xf1 + call delay + + +# well, that went ok, I hope. Now we mask all interrupts - the rest +# is done in init_IRQ(). + movb $0xFF, %al # mask all interrupts for now + outb %al, $0xA1 + call delay + + movb $0xFB, %al # mask all irq's but irq2 which + outb %al, $0x21 # is cascaded + +# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't +# need no steenking BIOS anyway (except for the initial loading :-). +# The BIOS-routine wants lots of unnecessary data, and it's less +# "interesting" anyway. This is how REAL programmers do it. + +/* Tailor the jump below so the target is the 32bit trampoline code */ + + xorl %eax, %eax # Calculate + movw %cs, %ax # the linear + shll $4, %eax # address of + addl $trampoline32, %eax # %cs:trampoline32 + movl %eax, %cs:code32 # Stick it into the jmpi + + /* Load a 32-bit pointer to the entry address into %ecx */ + xorl %ecx, %ecx # Calculate + movw %cs, %cx # the linear + shll $4, %ecx # address of + addl $entry_address, %ecx # %cs:entry_address + +# Well, now's the time to actually move into protected mode. + + lea mb_ready_mess, %si + call prtstr + +/* May as well load this IDT now */ + lidt idt_48 + + xorl %eax, %eax + movw $1, %ax # protected mode (PE) bit + lmsw %ax # This is it! + jmp flush_instr +flush_instr: + + /* Set up segment registers */ + movw $__BOOT_DS, %dx + movw %dx, %ds + movw %dx, %es + movw %dx, %fs + movw %dx, %gs + movw %dx, %ss + + /* Trampoline expects this in %eax */ + movl %ecx, %eax + + /* Jump to the 32-bit trampoline */ + +# NOTE: For high loaded big kernels we need a +# jmpi 0x100000,__BOOT_CS +# +# but we yet haven't reloaded the CS register, so the default size +# of the target offset still is 16 bit. +# However, using an operand prefix (0x66), the CPU will properly +# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference +# Manual, Mixing 16-bit and 32-bit code, page 16-6) + + .byte 0x66, 0xea # prefix + jmpi-opcode +code32: .long 0x1000 # will be set to trampoline32 + # by code above. + .word __BOOT_CS + +# Here's a bunch of information about your current kernel.. + +kernel_version: .string "mbootpack changeling bzImage" +mb_ready_mess: + .ascii MBOOTPACK_VERSION_STRING + .ascii "\r\n" + .byte 0 + +# This is the default real mode switch routine. +# to be called just before protected mode transition +default_switch: + cli # no interrupts allowed ! + movb $0x80, %al # disable NMI for bootup + # sequence + outb %al, $0x70 + lret + + +#ifndef CONFIG_X86_VOYAGER +# 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: + 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 + +#endif /* CONFIG_X86_VOYAGER */ + +# 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: + 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 + +# Read the cmos clock. Return the seconds in al +gettime: + pushw %cx + movb $0x02, %ah + int $0x1a + movb %dh, %al # %dh contains the seconds + andb $0x0f, %al + movb %dh, %ah + movb $0x04, %cl + shrb %cl, %ah + aad + popw %cx + ret + +# Delay is needed after doing I/O +delay: + outb %al,$0x80 + ret + +# Descriptor tables +# +# NOTE: The intel manual says gdt should be sixteen bytes aligned for +# efficiency reasons. However, there are machines which are known not +# to boot with misaligned GDTs, so alter this at your peril! If you alter +# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two +# empty GDT entries (one for NULL and one reserved). +# +# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is +# true for the Voyager Quad CPU card which will not boot without +# This directive. 16 byte aligment is recommended by intel. +# + + +/* The boot-time code segment is set at the jmpi above */ +/* Dont change this without checking everything still matches */ + + .align 16 +gdt: + .fill GDT_ENTRY_BOOT_CS,8,0 + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9A00 # code read/exec + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9200 # data read/write + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) +gdt_end: + .align 4 + + .word 0 # alignment byte +idt_48: + .word 0 # idt limit = 0 + .word 0, 0 # idt base = 0L + + .word 0 # alignment byte +gdt_48: + .word gdt_end - gdt - 1 # gdt limit + .word 0, 0 # gdt base (filled in later) + +# Include video setup & detection code + +/* #include "video.S" */ + +.code32 +trampoline32: + /* Here, %eax = 32-bit pointer to entry_address */ + + /* Check if the bootloader gave us a (non-empty) command line */ + movl -8(%eax), %ebx # cmd_line_ptr + cmpl $0, %ebx + je no_cmd_line + cmpb $0, 0(%ebx) + je no_cmd_line + + /* Find the MBI command line */ + movl %eax, %ecx # &entry_address + addl $(begtext-entry_address), %ecx # --> start of setup + subl $0x9200, %ecx # --> reloc offset + movl %ecx, %esi # (copy offset) + movl %ecx, %ebx # (copy offset) + addl 4(%eax), %ecx # --> current addr of MBI + addl 16(%ecx), %ebx # --> cur. addr of MB cmdline + + /* Overwrite the built-in MBI kernel command line */ + movl -8(%eax), %ecx + movl $0, %edi + + /* Give the kernel a 'self' word, that linux doesn't get */ + movw $0x202E, 0(%ebx) # '. ' + addl $0x2, %ebx + +cmd_line_copy: + movb (%ecx, %edi), %dl + movb %dl, (%ebx, %edi) + inc %edi + cmp $CMD_LINE_SPACE-3, %edi + je cmd_line_copy_end + + cmpb $0x0, %dl + jne cmd_line_copy +cmd_line_copy_end: + movb $0x0, (%ebx, %edi) + subl $0x2, %ebx + + /* Look for '--' in the kernel command line */ +cmd_line_scan: + inc %ebx + cmpb $0x0, 0(%ebx) + je no_cmd_line + cmpl $0x202D2D20, 0(%ebx) # ' -- ' + jne cmd_line_scan + + /* Found it: terminate kernel's command line */ + movb $0x0, 0(%ebx) + inc %ebx + /* Relocate address to where it will be moved to */ + subl %esi, %ebx + + /* Is there a module 0? */ + movl %esi, %ecx # Reloc offset + addl 4(%eax), %ecx # --> current addr of MBI + cmpl $0x0, 20(%ecx) # (check module count) + je no_cmd_line + /* Overwrite module 0's command line */ + movl %esi, %edx # Reloc offset + addl 24(%ecx), %edx # --> cur. add. of Module 0 + movl %ebx, 8(%edx) # --> blat mod. 0's cmdline +no_cmd_line: + + + /* Relocate the MBI from after the setup code to its proper home + * between the MBI pointer and 0xa000 */ + movl %eax, %ecx # &entry_address + addl $(begtext-entry_address), %ecx # --> start of setup + subl $0x9200, %ecx # --> reloc offset + addl 4(%eax), %ecx # --> current addr of MBI + + movl $0xa000, %ebx # End of MBI + subl 4(%eax), %ebx # --> size of MBI + movl %ebx, %edi + + movl 4(%eax), %ebx # Destination of MBI + +mbi_copy: + dec %edi + movb (%ecx, %edi), %dl + movb %dl, (%ebx, %edi) + cmp $0x0, %edi + jne mbi_copy + + /* Copy memory size into MBI structure */ + movl 4(%eax), %ebx # MBI pointer + movl 8(%eax), %ecx # highmem_size + movl %ecx, 8(%ebx) # --> mbi.mem_upper + movl $0x280, %ecx + movl %ecx, 4(%ebx) # --> mbi.mem_lower + /* Set the MB_INFO_MEMORY bit */ + orl $1, 0(%ebx) + + /* Recover the MBI pointer into %ebx */ + movl 4(%eax), %ebx # MBI pointer + /* Extract the load address into %ecx */ + movl 0(%eax), %ecx + /* Let the kernel know we're a multiboot loader */ + movl $0x2BADB002, %eax + /* Jump to the kernel address supplied */ + jmp *%ecx + +# Setup signature -- must be last +setup_sig1: .word SIG1 +setup_sig2: .word SIG2 + +# After this point, there is some free space which is used by the video mode +# handling code to store the temporary mode table (not used by the kernel). + +modelist: + +.text +endtext: +.data +enddata: +.bss +endbss: |