efibootmgr-0.5.4/0040775000175300017530000000000010741755405013547 5ustar mdomschmdomschefibootmgr-0.5.4/AUTHORS0100664000175300017530000000143410716126424014611 0ustar mdomschmdomschMatt Domsch - All .c and .h files Andreas Schwab - Patches to several .c and .h files Richard Hirst - Patch to efichar.c dann frazier - docbook of manpage - Patches to efibootmgr.c - network boot entry creation in efi.c Joshua Giles - walk the PCI path inserting parent bridge device path components for network boot and EDD30 entries. Alex Williamson - Patch to efi.c and efibootmgr.c for handling BootXXXX values using uppercase hex rather than lowercase, per EFI 1.10 spec. Rogerio Timmers - add option -@ for passing extra variable options in from a file, necessary for setting up some boot entries for Microsoft Windows. efibootmgr-0.5.4/COPYING0100664000175300017530000004312710716126424014601 0ustar mdomschmdomsch GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. efibootmgr-0.5.4/INSTALL0100664000175300017530000000015210716126424014566 0ustar mdomschmdomschRunning 'make' builds the file src/efibootmgr/efibootmgr. efibootmgr should be placed into /usr/sbin/. efibootmgr-0.5.4/Makefile0100664000175300017530000000401610737206043015177 0ustar mdomschmdomsch default: all RELEASE_DATE := "03-Jan-2008" RELEASE_MAJOR := 0 RELEASE_MINOR := 5 RELEASE_SUBLEVEL := 4 RELEASE_EXTRALEVEL := RELEASE_NAME := efibootmgr RELEASE_STRING := $(RELEASE_NAME)-$(RELEASE_MAJOR).$(RELEASE_MINOR).$(RELEASE_SUBLEVEL)$(RELEASE_EXTRALEVEL) CFLAGS = $(EXTRA_CFLAGS) -DEFIBOOTMGR_VERSION=\"$(RELEASE_MAJOR).$(RELEASE_MINOR).$(RELEASE_SUBLEVEL)$(RELEASE_EXTRALEVEL)\" \ -Wall -g -D_FILE_OFFSET_BITS=64 MODULES := src BINDIR := /usr/sbin #-------------------------------------------- # Generic Makefile stuff is below. You # should not have to modify any of the stuff # below. #-------------------------------------------- #Included makefiles will add their deps for each stage in these vars: INSTALLDEPS := CLEANDEPS := ALLDEPS := CLEANLIST := #Define the top-level build directory BUILDDIR := $(shell pwd) #Include make rules from each submodule (subdirectory) include $(patsubst %,%/module.mk,$(MODULES)) .PHONY: all clean install_list install install_link post_install tarball echotree default all: $(ALLDEPS) clean: clean_list $(CLEANDEPS) clean_list: rm -f $(CLEANLIST) install_list: echotree $(INSTALLDEPS) install: all @make install_list | tools/install.pl copy install_link: all @make install_list | tools/install.pl link post_install: tarball: clean -rm $(RELEASE_NAME)*.tar.gz cp -a ../$(RELEASE_NAME) ../$(RELEASE_STRING) find ../$(RELEASE_STRING) -name CVS -type d -depth -exec rm -rf \{\} \; sync; sync; sync; cd ..; tar cvzf $(RELEASE_STRING).tar.gz --exclude=.git --exclude=\*~ $(RELEASE_STRING) mv ../$(RELEASE_STRING).tar.gz . rm -rf ../$(RELEASE_STRING) #The rest of the docs... doc_TARGETS += COPYING README INSTALL echotree: @# making directory tree @#RPM FORMAT: @# %defattr(-, user, group) @# %attr(4755,user,group) filename @# filename # Here is a list of variables that are assumed Local to each Makefile. You can # safely stomp on these values without affecting the build. # MODULES # FILES # TARGETS # SOURCES efibootmgr-0.5.4/README0100664000175300017530000001211510716126424014417 0ustar mdomschmdomschThis is efibootmgr, a Linux user-space application to modify the Intel Extensible Firmware Interface (EFI) Boot Manager. This application can create and destroy boot entries, change the boot order, change the next running boot option, and more. Details on the EFI Boot Manager are available from the EFI Specification, v1.02 or above, available from http://developer.intel.com. Note: efibootmgr requires that the kernel module efivars be loaded prior to use. 'modprobe efivars' should do the trick. usage: efibootmgr [options] -a | --active sets bootnum active -A | --inactive sets bootnum inactive -b | --bootnum XXXX modify BootXXXX (hex) -B | --delete-bootnum delete bootnum (hex) -c | --create create new variable bootnum and add to bootorder -d | --disk disk (defaults to /dev/sda) containing loader -e | --edd [1|3|-1] force EDD 1.0 or 3.0 creation variables, or guess -E | --device num EDD 1.0 device number (defaults to 0x80) -g | --gpt force disk w/ invalid PMBR to be treated as GPT -H | --acpi_hid XXXX set the ACPI HID (used with -i) -i | --iface name create a netboot entry for the named interface -l | --loader name (defaults to \elilo.efi) -L | --label label Boot manager display label (defaults to "Linux") -n | --bootnext XXXX set BootNext to XXXX (hex) -N | --delete-bootnext delete BootNext -o | --bootorder XXXX,YYYY,ZZZZ,... explicitly set BootOrder (hex) -O | --delete-bootorder delete BootOrder -p | --part part (defaults to 1) containing loader -q | --quiet be quiet --test filename don't write to NVRAM, write to filename -t | --timeout seconds Boot manager timeout -T | --delete-timeout delete Timeout value -u | --unicode | --UCS-2 pass extra args as UCS-2 (default is ASCII) -U | --acpi_uid XXXX set the ACPI UID (used with -i) -v | --verbose print additional information -V | --version return version and exit -w | --write-signature write unique sig to MBR if needed -@ | --append-binary-args append extra variable args from file (use - to read from stdin). Typical usage: 1) Root can use it to display the current Boot Manager settings. [root@localhost ~]# efibootmgr BootCurrent: 0004 BootNext: 0003 BootOrder: 0004,0000,0001,0002,0003 Timeout: 30 seconds Boot0000* Diskette Drive(device:0) Boot0001* CD-ROM Drive(device:FF) Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233) Boot0003* PXE Boot: MAC(00D0B7C15D91) Boot0004* Linux This shows: BootCurrent - the boot entry used to start the currently running system. BootOrder - the boot order as would appear in the boot manager. The boot manager tries to boot the first active entry on this list. If unsuccessful, it tries the next entry, and so on. BootNext - the boot entry which is scheduled to be run on next boot. This superceeds BootOrder for one boot only, and is deleted by the boot manager after first use. This allows you to change the next boot behavior without changing BootOrder. Timeout - the time in seconds between when the boot manager appears on the screen until when it automatically chooses the startup value from BootNext or BootOrder. Five boot entries (0000 - 0004), the active/inactive flag (* means active), and the name displayed on the screen. 2) An OS installer would call 'efibootmgr -c'. This assumes that /boot/efi is your EFI System Partition, and is mounted at /dev/sda1. This creates a new boot option, called "Linux", and puts it at the top of the boot order list. Options may be passed to modify the default behavior. The default OS Loader is elilo.efi. 3) A system administrator wants to change the boot order. She would call 'efibootmgr -o 3,4' to specify PXE boot first, then Linux boot. 4) A system administrator wants to change the boot order for the next boot only. She would call 'efibootmgr -n 4' to specify that the Linux entry be taken on next boot. 5) A system administrator wants to delete the Linux boot option from the menu. 'efibootmgr -b 4 -B' deletes entry 4 and removes it from BootOrder. 6) A system administrator wants to create a boot option to network boot (PXE). Unfortunately, this requires knowing a little more information about your system than can be easily found by efibootmgr, so you've got to pass additional information - the ACPI HID and UID values. These can generally be found by using the EFI Boot Manager (in the EFI environment) to create a network boot entry, then using efibootmgr to print it verbosely. Here's one example: Boot003* Acpi(PNP0A03,0)/PCI(5|0)/Mac(00D0B7F9F510) \ ACPI(a0341d0,0)PCI(0,5)MAC(00d0b7f9f510,0) In this case, the ACPI HID is "0A0341d0" and the UID is "0". For the zx2000 gigE, the HID is "222F" and the UID is "500". For the rx2000 gigE, the HID is "0002" and the UID is "100". You create the boot entry with: 'efibootmgr -c -i eth0 -H 222F -U 500 -L netboot' Many other uses may be found. Please direct any bugs, features, patches, etc. to Matt Domsch . efibootmgr-0.5.4/doc/0040775000175300017530000000000010741755411014311 5ustar mdomschmdomschefibootmgr-0.5.4/doc/ChangeLog0100664000175300017530000003111010741755345016062 0ustar mdomschmdomschcommit 6e6bf6fc7665851798a6c2c92893ebb629e42aff Author: Matt Domsch Date: Fri Jan 11 15:08:12 2008 -0600 replacing elilo < 3.6-6, not -5 per conversation with clumens. commit 4c1fd35da4d0478074e08c10225eb590576acf91 Author: Matt Domsch Date: Thu Jan 3 12:19:28 2008 -0600 RPM spec rewrite for Fedora inclusion efibootmgr is being split out of the elilo SRPM in Fedora, into its own SRPM. commit 833cf4c1266ef72357948299008a22bfb80aa3f3 Author: Matt Domsch Date: Thu Jan 3 12:18:31 2008 -0600 Makefile cleanups bump version take an EXTRA_CFLAGS argument so rpmbuild can give us it's CFLAGS without overriding ours. exclude .git and *~ files from the tarball. commit f0a8b91ba45ff4cf251805cc29aed4f8672c1801 Author: Matt Domsch Date: Thu Jan 3 12:16:35 2008 -0600 src/lib/efi.c: include linux/types.h patch from Fedora. commit f387d5c5bde5d7129e41638e92faa2d38b7ad5a1 Author: Matt Domsch Date: Thu Jan 3 12:15:18 2008 -0600 make sure GPT_HEADER_SIGNATURE is a 64-bit value patch from Debian / Ubuntu 0.5.3-3ubuntu1. commit 7b53efa45112f28e97451bdc16e6c6a68740bd79 Author: Matt Domsch Date: Mon Nov 12 13:31:32 2007 -0600 avoid more unaligned access warnings commit 048197821f9ae2ef9e0c2bd4065649e72332e2dc Author: Matt Domsch Date: Mon Nov 12 12:25:42 2007 -0600 cleanup a few unaligned access warnings commit fa3942b34f1533659af8fe3f6fffb3b4acf4ee10 Author: Matt Domsch Date: Mon Nov 12 12:12:37 2007 -0600 cleanup exit values a little commit c7e236783a79b6977df0ba03db0f92fabffc4b31 Author: Doug Chapman Date: Mon Nov 12 11:32:12 2007 -0500 patch to make efibootmgr have non-zero exit code on errors We have some automated tools that use efibootmgr which are having a hard time detecting when efibootmgr fails since it exits with 0 on many failures. This patch catches (most) errors and exits with non-zero. I also added several error messages for to make it more obvious what was wrong with the command line arguments. Signed-off-by: Matt Domsch commit ecd3c24cb6bee5072ff6d1292456ee3b2cc91019 Author: Matt Domsch Date: Mon Jul 9 16:47:50 2007 +0000 add -lz to libs, needed when libpci happens to need it commit e192a055e0803263b71f89db732de73d5cf4de9b Author: Matt Domsch Date: Mon Jul 9 16:23:34 2007 +0000 apply patch from Dave Jiang to enable cross-building commit 0ee8ecc10109b91d0a77098d5596f56780c862d8 Author: Matt Domsch Date: Thu Aug 11 17:37:04 2005 +0000 v0.5.2.2 * Thu Aug 11 2005 Matt Domsch - applied patch from Rogerio Timmers which adds a new option -@ , which takes extra variable parameters from , or - from stdin. This lets you pass binary (non-unicode, non-ascii) formatted options to your bootloader. - cleaned up Rogerio's patch some. - moved definition of _FILE_OFFSET_BITS=64 into Makefile and out of the individual .c files. This fixes a bug reported by Red Flag, where variable data was getting incorrectly set with a 32-bit copy of efibootmgr on a 32-bit kernel. - made efi_variable_t.DataSize be an unsigned long to match the kernel. This lets a 32-bit copy of efibootmgr run on a 32-bit kernel. This means you've got to have a 32-bit efibootmgr on a 32-bit kernel, and a 64-bit efibootmgr on a 64-bit kernel, but since efi_status_t is also a long, this was really going to be the case anyway. - valgrind caught the app exiting without freeing some malloc'd structures, fix that. - v0.5.2.2 released for testing * Fri May 20 2005 Matt Domsch - applied patch from Andreas Schwab to properly parse PCI domain:bus:device.fn info in netboot entries. Fixed up return value when creating network boot entries for nonexistant devices, so the creation now fails, rather than succeeding with incorrect data. - v0.5.2 released * Tue Mar 08 2005 Matt Domsch - applied patch from Alex Williamson for handling BootXXXX values using uppercase hex rather than lowercase, per EFI 1.10 spec. - this also allows the full 65k boot entries, rather than requiring all entries to begin with a zero. - v0.5.1 released * Thu Aug 26 2004 Matt Domsch - v0.5.0-test4 released as v0.5.0 with no code changes * Wed Jun 07 2004 Matt Domsch - Fixed bug where read_boot_order() would wrongly return EFI_NOT_FOUND when it needed to create a new BootOrder variable. Reported by Micah Parrish. - Added code to recursively walk the PCI bus putting parent PCI bridges in. This is necessary for Dell PowerEdge 3250 and 7250 servers and Intel Tiger2 and Tiger4 platforms when creating PXE boot entries for the onboard NICs, and if creating EDD30 boot path entries. Work by Matt and Joshua Giles. - Note, efibootmgr now requires libpci for building. - Released v0.5.0-test4 * Sat Apr 24 2004 Matt Domsch - Fixed reversed logic of create_or_edit_variable which prevented object creation or editing on sysfs. - Removed debug printfs in sysfs read/write commands. - Released v0.5.0-test3 * Thu Feb 04 2004 Matt Domsch - removed -t short option for --test - added -t and -T delete timeout options - updated man page and README about the timeout options - Released v0.5.0-test2 * Tue Sep 09 2003 Matt Domsch - Released v0.5.0-test1 * Thu Sep 04 2003 Matt Domsch - Seperated access to variables through /proc into efivars_procfs.[ch] - Added efivars_sysfs.h to access variables through sysfs. - Moved around some functions, cleaned up some duplication. * Thu Sep 04 2003 Matt Domsch - released v0.4.2-test2 as v0.4.2 without additional changes. * Mon Aug 11 2003 Matt Domsch - fixed unaligned access errors - removed extraneous printing of mac addr when creating netboot entries - sync docbook to README - whitespace cleanups * Thu Jul 31 2003 Matt Domsch - Applied patch from Dann Frazier to enable creating netboot entries. - update AUTHORS with Dann's netboot contribution. - Until we can get the ACPI HID and UID programatically, make the user pass them in when creating a netboot entry. - Add O_DIRECT support for reading the disk. - Fix unparse_hardware_path() for the PCI case - the device and function values were printed in reverse order. - Fix the README file to reflect all the options that can be passed, and add a new item for netboot entries. - whitespace cleanups * Fri Oct 25 2002 Matt Domsch - trivial patch from Fabien Lebaillif - Delamare increases the length of the boot option description from 40 to 64 bytes. * Tue Oct 22 2002 Matt Domsch - ran docbook2man on the man page Dann Frazier created - Added man page to spec file - Added patches from Dann Frazier - Removes the requirement to be root to run efibootmgr. This lets mortal users run efibootmgr to check the version, and see the --help output. It should also allow efibootmgr to work under security systems without the strict root/non-root dichotomy. - Checks to see if a boot option was specified when a boot option deletion was requested. - Released version 0.4.1 * Sun Jul 21 2002 Matt Domsch - Added kernel_has_blkgetsize64() test, now uses BLKGETSIZE64 if on a known-good kernel. This is important when the Large Block Device (64-bit block address) patch gets merged into the 2.5 kernel. * Wed May 1 2002 Matt Domsch - Released version 0.4.0 * Tue Apr 30 2002 Matt Domsch - Added some printfs to compare_gpts(). * Mon Apr 08 2002 Matt Domsch - Make sure partition number arg is in the GPT disk. - Added a few more _FILE_OFFSET_BITS defines where needed * Fri Apr 05 2002 Matt Domsch - Added syncs to make tarball target so NFS is current and CVS dirs get deleted before the tarball is made. - Added a few __leXX_to_cpu() calls in code currently commented out in gpt.c * Tue Apr 02 2002 Matt Domsch - finished conversion to GPT code * Sat Mar 30 2002 Matt Domsch - began conversion to GPT code in post-2.4.18 and post-2.5.7 kernels. - added manpage contributed by dannf@fc.hp.com * Mon Feb 11 2002 Matt Domsch - BLKGETSIZE64 is fixed in 2.4.18-pre8 and 2.5.4-pre3. Wait a bit longer before using though. - added list_for_each_safe() routine. It's needed in the boot var deletion routine, though it was already breaking out once found. - changed struct list_head to list_t - released v0.4.0-test4 * Fri Jan 18 2002 Matt Domsch - commented out BLKGETSIZE64 ioctl use for now. Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 don't return the right value. * Thu Jan 3 2002 Matt Domsch - added back in read last sector IOCTL hack, but only after read() fails. - released v0.4.0-test4 * Thu Jan 3 2002 Matt Domsch - more cleanups - released v0.4.0-test3 * Wed Jan 2 2002 Matt Domsch - Changed PROC_DIR_EFI to PROC_DIR_EFI_VARS - write_variable() now searches /proc/efi/vars for a variable that's not the one being written. The EFI 1.1 sample implementation changed the name of the "victim" being written to (was Efi-xxxxx, now EFI-xxxxx), so previous versions of efibootmgr don't work with the new firmware. This should fix that up. - released v0.4.0-test2 * Fri Dec 7 2001 Matt Domsch - Removed read last sector ioctl hack, it's not needed anymore. The kernel takes care of it for us with a new patch. - Added test for valid PMBR, similar to parted and the kernel. - Added test for returning size of block device as a u64. - Added test for returning sector size as int, and use that. - Changed GPT struct and member names to be more Linux-like. - added -g option to force disk with invalid PMBR to be treated as GPT anyhow. - released v0.4.0-test1 * Thu Aug 9 2001 Matt Domsch - Added some uniqueness to the MBR signature. - removed ExclusiveArch from spec file - released v0.3.4 * Mon Aug 6 2001 Matt Domsch - applied patch from Richard Hirst to fix efichar_char_strcmp(). * Fri Aug 3 2001 Matt Domsch - By request, warn when creating a new boot entry with the same name as another boot entry. - released v0.3.3 * Mon Jul 30 2001 Matt Domsch - Added test for non-zero signature on MBR-style disks, and new -w flag to write a unique signature to the disk if so. - released v0.3.3-test4 - Fixed counting of optional data length (extra args) - released v0.3.3-test5 * Fri Jul 27 2001 Matt Domsch - Added test for running as root - released v0.3.3-test3 * Thu Jul 26 2001 Matt Domsch - Unparse extra args being passed to bootloader too. - released v0.3.3-test2 * Wed Jul 25 2001 Matt Domsch - Added -u option to pass extra args to the bootloader in unicode (default is to pass in ASCII) - Added -t option to allow writing to a file (for testing) - released v0.3.3-test1 * Tue May 22 2001 Matt Domsch - Applied patch from Andreas Schwab. remove_from_boot_order() called read_boot_order() without checking the return status. - Changed README to remove os loader args comment - Changed efi_status_t to be unsigned long (not uint64_t) as per EFI spec. This allows efibootmgr to be recompiled as a 32-bit or 64-bit app depending on its running on 32-bit or 64-bit Linux. Note: this changes the size of the structure returned in /proc/efi/vars to match the kernel implementation. 32-bit efibootmgr won't work on 64-bit Linux and vice versa. - release v0.3.2 * Fri May 18 2001 Matt Domsch - changed usage() to *not* let you think you can pass args to the OS loader - release v0.3.1 * Fri May 18 2001 Matt Domsch - Padded HARDDRIVE_DEVICE_PATH out to please EFI Boot Manager. - Incorporated patches from Andreas Schwab - replace __u{8,16,32,64} with uint{8,16,32,64}_t - use _FILE_OFFSET_BITS - fix a segfault - release v0.3.0 * Tue May 15 2001 Matt Domsch - initial external release v0.2.0 efibootmgr-0.5.4/doc/TODO0100664000175300017530000000004310716126424014771 0ustar mdomschmdomsch* MS-DOS style extended partitions efibootmgr-0.5.4/efibootmgr.spec0100644000175300017530000000313510741754406016555 0ustar mdomschmdomschSummary: EFI Boot Manager Name: efibootmgr Version: 0.5.4 Release: 1%{?dist} Group: System Environment/Base License: GPLv2+ URL: http://linux.dell.com/%{name}/ BuildRequires: pciutils-devel, zlib-devel BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXXXX) # EFI/UEFI don't exist on PPC ExclusiveArch: i386 x86_64 ia64 # for RHEL / Fedora when efibootmgr was part of the elilo package Conflicts: elilo < 3.6-6 Obsoletes: elilo < 3.6-6 Source0: http://linux.dell.com/%{name}/permalink/%{name}-%{version}.tar.gz %description %{name} displays and allows the user to edit the Intel Extensible Firmware Interface (EFI) Boot Manager variables. Additional information about EFI can be found at http://developer.intel.com/technology/efi/efi.htm and http://uefi.org/. %prep %setup -q %build make %{?_smp_mflags} EXTRA_CFLAGS='%{optflags}' %install rm -rf %{buildroot} mkdir -p %{buildroot}%{_sbindir} %{buildroot}%{_mandir}/man8 install -p --mode 755 src/%{name}/%{name} %{buildroot}%{_sbindir} gzip -9 -c src/man/man8/%{name}.8 > src/man/man8/%{name}.8.gz touch -r src/man/man8/%{name}.8 src/man/man8/%{name}.8.gz install -p --mode 644 src/man/man8/%{name}.8.gz %{buildroot}%{_mandir}/man8 %clean rm -rf %{buildroot} %files %defattr(-,root,root,-) %{_sbindir}/%{name} %{_mandir}/man8/%{name}.8.gz %doc README INSTALL COPYING %changelog * Thu Jan 3 2008 Matt Domsch 0.5.4-1 - split efibootmgr into its own RPM for Fedora/RHEL. * Thu Aug 24 2004 Matt Domsch - new home linux.dell.com * Fri May 18 2001 Matt Domsch - See doc/ChangeLog efibootmgr-0.5.4/filelist-rpm0100664000175300017530000000020510716126424016066 0ustar mdomschmdomsch %attr(0755,root,root) /usr/sbin %attr(0755,root,root) /usr/sbin/efibootmgr %attr(0444,root,root) /usr/share/man/man8/efibootmgr.8 efibootmgr-0.5.4/src/0040775000175300017530000000000010716126424014331 5ustar mdomschmdomschefibootmgr-0.5.4/src/Makefile0100664000175300017530000000002410716126424015762 0ustar mdomschmdomsch%: +make -C ../ $* efibootmgr-0.5.4/src/efibootmgr/0040775000175300017530000000000010737223475016475 5ustar mdomschmdomschefibootmgr-0.5.4/src/efibootmgr/Makefile0100664000175300017530000000002410716126424020117 0ustar mdomschmdomsch%: +make -C ../ $* efibootmgr-0.5.4/src/efibootmgr/efibootmgr.c0100664000175300017530000006452710716127204020777 0ustar mdomschmdomsch/* efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars Copyright (C) 2001-2004 Dell, 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 This must tie the EFI_DEVICE_PATH to /boot/efi/elilo.efi The EFI_DEVICE_PATH will look something like: ACPI device path, length 12 bytes Hardware Device Path, PCI, length 6 bytes Messaging Device Path, SCSI, length 8 bytes, or ATAPI, length ?? Media Device Path, Hard Drive, partition XX, length 30 bytes Media Device Path, File Path, length ?? End of Hardware Device Path, length 4 Arguments passed to elilo, as UCS-2 characters, length ?? */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "efi.h" #include "efichar.h" #include "unparse_path.h" #include "disk.h" #include "efibootmgr.h" #ifndef EFIBOOTMGR_VERSION #define EFIBOOTMGR_VERSION "unknown (fix Makefile!)" #endif typedef struct _var_entry { struct dirent *name; uint16_t num; efi_variable_t var_data; list_t list; } var_entry_t; /* global variables */ static LIST_HEAD(boot_entry_list); static LIST_HEAD(blk_list); efibootmgr_opt_t opts; static inline void var_num_from_name(const char *pattern, char *name, uint16_t *num) { sscanf(name, pattern, num); } static void fill_bootvar_name(char *dest, size_t len, const char *name) { efi_guid_t guid = EFI_GLOBAL_VARIABLE; char text_uuid[40]; efi_guid_unparse(&guid, text_uuid); snprintf(dest, len, "%s-%s", name, text_uuid); } static void fill_var(efi_variable_t *var, const char *name) { efi_guid_t guid = EFI_GLOBAL_VARIABLE; efichar_from_char(var->VariableName, name, 1024); memcpy(&var->VendorGuid, &guid, sizeof(guid)); var->Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; } static void free_vars(list_t *head) { list_t *pos, *n; var_entry_t *boot; list_for_each_safe(pos, n, head) { boot = list_entry(pos, var_entry_t, list); list_del(&(boot->list)); free(boot); } } static void read_vars(struct dirent **namelist, int num_boot_names, list_t *head) { efi_status_t status; var_entry_t *entry; int i; if (!namelist) return; for (i=0; i < num_boot_names; i++) { if (namelist[i]) { entry = malloc(sizeof(var_entry_t)); if (!entry) return; memset(entry, 0, sizeof(var_entry_t)); status = read_variable(namelist[i]->d_name, &entry->var_data); if (status != EFI_SUCCESS) break; entry->name = namelist[i]; list_add_tail(&entry->list, head); } } return; } static void free_dirents(struct dirent **ptr, int num_dirents) { int i; if (!ptr) return; for (i=0; i < num_dirents; i++) { if (ptr[i]) { free(ptr[i]); ptr[i] = NULL; } } free(ptr); } static int compare(const void *a, const void *b) { int rc = -1; uint32_t n1, n2; memcpy(&n1, a, sizeof(n1)); memcpy(&n2, b, sizeof(n2)); if (n1 < n2) rc = -1; if (n1 == n2) rc = 0; if (n2 > n2) rc = 1; return rc; } /* Return an available boot variable number, or -1 on failure. */ static int find_free_boot_var(list_t *boot_list) { int num_vars=0, i=0, found; uint16_t *vars, free_number; list_t *pos; var_entry_t *boot; list_for_each(pos, boot_list) { num_vars++; } vars = malloc(sizeof(uint16_t) * num_vars); if (!vars) return -1; memset(vars, 0, sizeof(uint16_t) * num_vars); list_for_each(pos, boot_list) { boot = list_entry(pos, var_entry_t, list); vars[i] = boot->num; i++; } qsort(vars, i, sizeof(uint16_t), compare); found = 1; num_vars = i; for (free_number = 0; free_number < num_vars && found; free_number++) { found = 0; list_for_each(pos, boot_list) { boot = list_entry(pos, var_entry_t, list); if (boot->num == free_number) { found = 1; break; } } if (!found) break; } if (found && num_vars) free_number = vars[num_vars-1] + 1; free(vars); return free_number; } static void warn_duplicate_name(list_t *boot_list) { list_t *pos; var_entry_t *boot; EFI_LOAD_OPTION *load_option; list_for_each(pos, boot_list) { boot = list_entry(pos, var_entry_t, list); load_option = (EFI_LOAD_OPTION *) boot->var_data.Data; if (!efichar_char_strcmp(opts.label, load_option->description)) { fprintf(stderr, "** Warning ** : %.8s has same label %s\n", boot->name->d_name, opts.label); } } } static var_entry_t * make_boot_var(list_t *boot_list) { var_entry_t *boot; int free_number; list_t *pos; if (opts.bootnum == -1) free_number = find_free_boot_var(boot_list); else { list_for_each(pos, boot_list) { boot = list_entry(pos, var_entry_t, list); if (boot->num == opts.bootnum) { fprintf(stderr, "** Warning ** : bootnum %04X " "already exists\n", opts.bootnum); return NULL; } } free_number = opts.bootnum; } if (free_number == -1) return NULL; /* Create a new var_entry_t object and populate it. */ boot = malloc(sizeof(*boot)); if (!boot) return NULL; memset(boot, 0, sizeof(*boot)); boot->num = free_number; if (!make_linux_efi_variable(&boot->var_data, free_number)) { free(boot); return NULL; } create_variable(&boot->var_data); list_add_tail(&boot->list, boot_list); return boot; } static efi_status_t read_boot(efi_variable_t *var, const char *name) { char name_guid[PATH_MAX]; memset(var, 0, sizeof(*var)); fill_bootvar_name(name_guid, sizeof(name_guid), name); return read_variable(name_guid, var); } static efi_status_t read_boot_order(efi_variable_t *boot_order) { efi_status_t status; status = read_boot(boot_order, "BootOrder"); if (status != EFI_SUCCESS && status != EFI_NOT_FOUND) return status; if (status == EFI_NOT_FOUND) { fill_var(boot_order, "BootOrder"); } return EFI_SUCCESS; } static efi_status_t add_to_boot_order(uint16_t num) { efi_status_t status; efi_variable_t boot_order; uint64_t new_data_size; uint16_t *new_data, *old_data; status = read_boot_order(&boot_order); if (status != EFI_SUCCESS) return status; /* We've now got an array (in boot_order.Data) of the boot order. First add our entry, then copy the old array. */ old_data = (uint16_t *)&(boot_order.Data); new_data_size = boot_order.DataSize + sizeof(uint16_t); new_data = malloc(new_data_size); new_data[0] = num; memcpy(new_data+1, old_data, boot_order.DataSize); /* Now new_data has what we need */ memcpy(&(boot_order.Data), new_data, new_data_size); boot_order.DataSize = new_data_size; return create_or_edit_variable(&boot_order); } static efi_status_t remove_from_boot_order(uint16_t num) { efi_status_t status; efi_variable_t boot_order; uint64_t new_data_size; uint16_t *new_data, *old_data; int old_i,new_i; char boot_order_name[PATH_MAX]; status = read_boot_order(&boot_order); if (status != EFI_SUCCESS) return status; /* If it's empty, yea! */ if (!boot_order.DataSize) return EFI_SUCCESS; fill_bootvar_name(boot_order_name, sizeof(boot_order_name), "BootOrder"); /* We've now got an array (in boot_order.Data) of the boot order. Simply copy the array, skipping the entry we're deleting. */ old_data = (uint16_t *)&(boot_order.Data); /* Start with the same size */ new_data_size = boot_order.DataSize; new_data = malloc(new_data_size); for (old_i=0,new_i=0; old_i < boot_order.DataSize / sizeof(uint16_t); old_i++) { if (old_data[old_i] != num) { /* Copy this value */ new_data[new_i] = old_data[old_i]; new_i++; } } /* Now new_data has what we need */ new_data_size = new_i * sizeof(uint16_t); memset(&(boot_order.Data), 0, boot_order.DataSize); memcpy(&(boot_order.Data), new_data, new_data_size); boot_order.DataSize = new_data_size; return edit_variable(&boot_order); } static efi_status_t delete_var(const char *name) { efi_variable_t var; memset(&var, 0, sizeof(var)); fill_var(&var, name); return delete_variable(&var); } static int read_boot_u16(const char *name) { efi_status_t status; efi_variable_t var; uint16_t *n = (uint16_t *)(var.Data); memset(&var, 0, sizeof(var)); status = read_boot(&var, name); if (status) return -1; return *n; } static efi_status_t set_boot_u16(const char *name, uint16_t num) { efi_variable_t var; uint16_t *n = (uint16_t *)var.Data; memset(&var, 0, sizeof(var)); fill_var(&var, name); *n = num; var.DataSize = sizeof(uint16_t); return create_or_edit_variable(&var); } static efi_status_t delete_boot_var(uint16_t num) { efi_status_t status; efi_variable_t var; char name[16]; list_t *pos, *n; var_entry_t *boot; snprintf(name, sizeof(name), "Boot%04X", num); memset(&var, 0, sizeof(var)); fill_var(&var, name); status = delete_variable(&var); /* For backwards compatibility, try to delete abcdef entries as well */ if (status) { snprintf(name, sizeof(name), "Boot%04x", num); memset(&var, 0, sizeof(var)); fill_var(&var, name); status = delete_variable(&var); } if (status) { fprintf (stderr,"\nboot entry: %X not found\n\n",num); return status; } list_for_each_safe(pos, n, &boot_entry_list) { boot = list_entry(pos, var_entry_t, list); if (boot->num == num) { status = remove_from_boot_order(num); if (status) return status; list_del(&(boot->list)); break; /* short-circuit since it was found */ } } return EFI_SUCCESS; } static void set_var_nums(const char *pattern, list_t *list) { list_t *pos; var_entry_t *var; int num=0, rc; char *name; int warn=0; list_for_each(pos, list) { var = list_entry(pos, var_entry_t, list); rc = sscanf(var->name->d_name, pattern, &num); if (rc == 1) { var->num = num; name = var->name->d_name; /* shorter name */ if ((isalpha(name[4]) && islower(name[4])) || (isalpha(name[5]) && islower(name[5])) || (isalpha(name[6]) && islower(name[6])) || (isalpha(name[7]) && islower(name[7]))) { fprintf(stderr, "** Warning ** : %.8s is not " "EFI 1.10 compliant (lowercase hex in name)\n", name); warn++; } } } if (warn) { fprintf(stderr, "** Warning ** : please recreate these using efibootmgr to remove this warning.\n"); } } #if 0 static efi_variable_t * find_pci_scsi_disk_blk(int fd, int bus, int device, int func, list_t *blk_list) { list_t *pos; int rc; Scsi_Idlun idlun; unsigned char host, channel, id, lun; var_entry_t *blk; efi_variable_t *blk_var; long size = 0; memset(&idlun, 0, sizeof(idlun)); rc = get_scsi_idlun(fd, &idlun); if (rc) return NULL; rc = disk_get_size(fd, &size); idlun_to_components(&idlun, &host, &channel, &id, &lun); list_for_each(pos, blk_list) { blk = list_entry(pos, var_entry_t, list); blk_var = blk->var_data; if (!compare_pci_scsi_disk_blk(blk_var, bus, device, func, host, channel, id, lun, 0, size)) { return blk_var; } } return NULL; } /* The right blkX variable contains: 1) the PCI and SCSI information for the disk passed in disk_name 2) Does not contain a partition field */ static efi_variable_t * find_disk_blk(char *disk_name, list_t *blk_list) { efi_variable_t *disk_blk = NULL; int fd, rc; unsigned char bus=0,device=0,func=0; int interface_type=interface_type_unknown; unsigned int controllernum=0, disknum=0; unsigned char part=0; fd = open(disk_name, O_RDONLY|O_DIRECT); rc = disk_get_pci(fd, &bus, &device, &func); if (rc) { fprintf(stderr, "disk_get_pci() failed.\n"); return NULL; } rc = disk_info_from_fd(fd, &interface_type, &controllernum, &disknum, &part); if (rc) { fprintf(stderr, "disk_info_from_fd() failed.\n"); return NULL; } switch (interface_type) { case scsi: return find_pci_scsi_disk_blk(fd,bus,device,func,blk_list); break; case ata: return find_pci_ata_disk_blk(fd,bus,device,func,blk_list); break; case i2o: return find_pci_i2o_disk_blk(fd,bus,device,func,blk_list); break; case md: return find_pci_md_disk_blk(fd,bus,device,func,blk_list); break; default: break; } return NULL; } #endif static void unparse_boot_order(uint16_t *order, int length) { int i; printf("BootOrder: "); for (i=0; inum == b) return 1; } return 0; } static int parse_boot_order(char *buffer, uint16_t *order, int length) { int i; int num, rc; for (i=0; ivar_data.Data; efichar_to_char(description, load_option->description, sizeof(description)); memset(text_path, 0, sizeof(text_path)); path = load_option_path(load_option); if (boot->name) printf("%.8s", boot->name->d_name); else printf("Boot%04X", boot->num); if (load_option->attributes & LOAD_OPTION_ACTIVE) printf("* "); else printf(" "); printf("%s", description); if (opts.verbose) { unparse_path(text_path, path, load_option->file_path_list_length); /* Print optional data */ optional_data_len = boot->var_data.DataSize - load_option->file_path_list_length - ((char *)path - (char *)load_option); if (optional_data_len) { p = text_path; p += strlen(text_path); unparse_raw_text(p, ((uint8_t *)path) + load_option->file_path_list_length, optional_data_len); } printf("\t%s", text_path); } printf("\n"); } } static void show_boot_order() { efi_status_t status; efi_variable_t boot_order; uint16_t *data; status = read_boot_order(&boot_order); if (status != EFI_SUCCESS) { perror("show_boot_order()"); return; } /* We've now got an array (in boot_order.Data) of the boot order. First add our entry, then copy the old array. */ data = (uint16_t *)&(boot_order.Data); if (boot_order.DataSize) unparse_boot_order(data, boot_order.DataSize / sizeof(uint16_t)); } static efi_status_t set_active_state() { list_t *pos; var_entry_t *boot; EFI_LOAD_OPTION *load_option; list_for_each(pos, &boot_entry_list) { boot = list_entry(pos, var_entry_t, list); load_option = (EFI_LOAD_OPTION *) boot->var_data.Data; if (boot->num == opts.bootnum) { if (opts.active == 1) { if (load_option->attributes & LOAD_OPTION_ACTIVE) return EFI_SUCCESS; else { load_option->attributes |= LOAD_OPTION_ACTIVE; return edit_variable(&boot->var_data); } } else if (opts.active == 0) { if (!(load_option->attributes & LOAD_OPTION_ACTIVE)) return EFI_SUCCESS; else { load_option->attributes &= ~LOAD_OPTION_ACTIVE; return edit_variable(&boot->var_data); } } } } /* if we reach here then the bootnumber supplied was not found */ fprintf(stderr,"\nboot entry %x not found\n\n",opts.bootnum); return EFI_NOT_FOUND; } static void usage() { printf("efibootmgr version %s\n", EFIBOOTMGR_VERSION); printf("usage: efibootmgr [options]\n"); printf("\t-a | --active sets bootnum active\n"); printf("\t-A | --inactive sets bootnum inactive\n"); printf("\t-b | --bootnum XXXX modify BootXXXX (hex)\n"); printf("\t-B | --delete-bootnum delete bootnum (hex)\n"); printf("\t-c | --create create new variable bootnum and add to bootorder\n"); printf("\t-d | --disk disk (defaults to /dev/sda) containing loader\n"); printf("\t-e | --edd [1|3|-1] force EDD 1.0 or 3.0 creation variables, or guess\n"); printf("\t-E | --device num EDD 1.0 device number (defaults to 0x80)\n"); printf("\t-g | --gpt force disk with invalid PMBR to be treated as GPT\n"); printf("\t-H | --acpi_hid XXXX set the ACPI HID (used with -i)\n"); printf("\t-i | --iface name create a netboot entry for the named interface\n"); printf("\t-l | --loader name (defaults to \\elilo.efi)\n"); printf("\t-L | --label label Boot manager display label (defaults to \"Linux\")\n"); printf("\t-n | --bootnext XXXX set BootNext to XXXX (hex)\n"); printf("\t-N | --delete-bootnext delete BootNext\n"); printf("\t-o | --bootorder XXXX,YYYY,ZZZZ,... explicitly set BootOrder (hex)\n"); printf("\t-O | --delete-bootorder delete BootOrder\n"); printf("\t-p | --part part (defaults to 1) containing loader\n"); printf("\t-q | --quiet be quiet\n"); printf("\t | --test filename don't write to NVRAM, write to filename.\n"); printf("\t-t | --timeout seconds set boot manager timeout waiting for user input.\n"); printf("\t-T | --delete-timeout delete Timeout.\n"); printf("\t-u | --unicode | --UCS-2 pass extra args as UCS-2 (default is ASCII)\n"); printf("\t-U | --acpi_uid XXXX set the ACPI UID (used with -i)\n"); printf("\t-v | --verbose print additional information\n"); printf("\t-V | --version return version and exit\n"); printf("\t-w | --write-signature write unique sig to MBR if needed\n"); printf("\t-@ | --append-binary-args file append extra args from file (use \"-\" for stdin)\n"); } static void set_default_opts() { memset(&opts, 0, sizeof(opts)); opts.bootnum = -1; /* auto-detect */ opts.bootnext = -1; /* Don't set it */ opts.active = -1; /* Don't set it */ opts.timeout = -1; /* Don't set it */ opts.edd10_devicenum = 0x80; opts.loader = "\\elilo.efi"; opts.label = "Linux"; opts.disk = "/dev/sda"; opts.iface = NULL; opts.part = 1; opts.acpi_hid = -1; opts.acpi_uid = -1; } static void parse_opts(int argc, char **argv) { int c, num, rc; int option_index = 0; while (1) { static struct option long_options[] = /* name, has_arg, flag, val */ { {"active", no_argument, 0, 'a'}, {"inactive", no_argument, 0, 'A'}, {"bootnum", required_argument, 0, 'b'}, {"delete-bootnum", no_argument, 0, 'B'}, {"create", no_argument, 0, 'c'}, {"disk", required_argument, 0, 'd'}, {"iface", required_argument, 0, 'i'}, {"acpi_hid", required_argument, 0, 'H'}, {"edd-device", required_argument, 0, 'E'}, {"edd30", required_argument, 0, 'e'}, {"gpt", no_argument, 0, 'g'}, {"loader", required_argument, 0, 'l'}, {"label", required_argument, 0, 'L'}, {"bootnext", required_argument, 0, 'n'}, {"delete-bootnext", no_argument, 0, 'N'}, {"bootorder", required_argument, 0, 'o'}, {"delete-bootorder", no_argument, 0, 'O'}, {"part", required_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, {"test", required_argument, 0, 1}, {"timeout", required_argument, 0, 't'}, {"delete-timeout", no_argument, 0, 'T'}, {"unicode", no_argument, 0, 'u'}, {"UCS-2", no_argument, 0, 'u'}, {"acpi_uid", required_argument, 0, 'U'}, {"verbose", optional_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"write-signature", no_argument, 0, 'w'}, {"append-binary-args", required_argument, 0, '@'}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw@:", long_options, &option_index); if (c == -1) break; switch (c) { case '@': opts.extra_opts_file = optarg; break; case 'a': opts.active = 1; break; case 'A': opts.active = 0; break; case 'B': opts.delete_boot = 1; break; case 'b': rc = sscanf(optarg, "%X", &num); if (rc == 1) opts.bootnum = num; else { fprintf (stderr,"invalid hex value %s\n",optarg); exit(1); } break; case 'c': opts.create = 1; break; case 'd': opts.disk = optarg; break; case 'e': rc = sscanf(optarg, "%d", &num); if (rc == 1) opts.edd_version = num; else { fprintf (stderr,"invalid numeric value %s\n",optarg); exit(1); } break; case 'E': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.edd10_devicenum = num; else { fprintf (stderr,"invalid hex value %s\n",optarg); exit(1); } break; case 'g': opts.forcegpt = 1; break; case 'H': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.acpi_hid = num; else { fprintf (stderr,"invalid hex value %s\n",optarg); exit(1); } break; case 'i': opts.iface = optarg; break; case 'l': opts.loader = optarg; break; case 'L': opts.label = optarg; break; case 'N': opts.delete_bootnext = 1; break; case 'n': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.bootnext = num; else { fprintf (stderr,"invalid hex value %s\n",optarg); exit(1); } break; case 'o': opts.bootorder = optarg; break; case 'O': opts.delete_bootorder = 1; break; case 'p': rc = sscanf(optarg, "%u", &num); if (rc == 1) opts.part = num; else { fprintf (stderr,"invalid numeric value %s\n",optarg); exit(1); } break; case 'q': opts.quiet = 1; break; case 1: opts.testfile = optarg; break; case 't': rc = sscanf(optarg, "%u", &num); if (rc == 1) { opts.timeout = num; opts.set_timeout = 1; } else { fprintf (stderr,"invalid numeric value %s\n",optarg); exit(1); } break; case 'T': opts.delete_timeout = 1; break; case 'u': opts.unicode = 1; break; case 'U': rc = sscanf(optarg, "%x", &num); if (rc == 1) opts.acpi_uid = num; else { fprintf (stderr,"invalid hex value %s\n",optarg); exit(1); } break; case 'v': opts.verbose = 1; if (optarg) { if (!strcmp(optarg, "v")) opts.verbose = 2; if (!strcmp(optarg, "vv")) opts.verbose = 3; rc = sscanf(optarg, "%d", &num); if (rc == 1) opts.verbose = num; else { fprintf (stderr,"invalid numeric value %s\n",optarg); exit(1); } } break; case 'V': opts.showversion = 1; break; case 'w': opts.write_signature = 1; break; default: usage(); exit(1); } } if (optind < argc) { opts.argc = argc; opts.argv = argv; opts.optind = optind; } } int main(int argc, char **argv) { struct dirent **boot_names = NULL; var_entry_t *new_boot = NULL; int num, num_boot_names=0; efi_status_t ret=0; set_default_opts(); parse_opts(argc, argv); if (opts.showversion) { printf("version %s\n", EFIBOOTMGR_VERSION); return 0; } if (opts.iface && opts.acpi_hid == -1 && opts.acpi_uid == -1) { fprintf(stderr, "\nYou must specify the ACPI HID and UID when using -i.\n\n"); return 1; } if (!opts.testfile) set_fs_kernel_calls(); if (!opts.testfile) { num_boot_names = read_boot_var_names(&boot_names); read_vars(boot_names, num_boot_names, &boot_entry_list); set_var_nums("Boot%04X-%*s", &boot_entry_list); if (opts.delete_boot) { if (opts.bootnum == -1) { fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n"); return 1; } else ret = delete_boot_var(opts.bootnum); } if (opts.active >= 0) { if (opts.bootnum == -1) { fprintf(stderr, "\nYou must specify a boot entry to delete (see the -b option).\n\n"); return 1; } else ret=set_active_state(); } } if (opts.create) { warn_duplicate_name(&boot_entry_list); new_boot = make_boot_var(&boot_entry_list); if (!new_boot) return 1; /* Put this boot var in the right BootOrder */ if (!opts.testfile && new_boot) ret=add_to_boot_order(new_boot->num); } if (!opts.testfile) { if (opts.delete_bootorder) { ret=delete_var("BootOrder"); } if (opts.bootorder) { ret=set_boot_order(); } if (opts.delete_bootnext) { ret=delete_var("BootNext"); } if (opts.delete_timeout) { ret=delete_var("Timeout"); } if (opts.bootnext >= 0) { if (!is_current_boot_entry(opts.bootnext & 0xFFFF)){ fprintf (stderr,"\n\nboot entry %X does not exist\n\n", opts.bootnext); return 1; } ret=set_boot_u16("BootNext", opts.bootnext & 0xFFFF); } if (opts.set_timeout) { ret=set_boot_u16("Timeout", opts.timeout); } if (!opts.quiet && ret == 0) { num = read_boot_u16("BootNext"); if (num != -1 ) { printf("BootNext: %04X\n", num); } num = read_boot_u16("BootCurrent"); if (num != -1) { printf("BootCurrent: %04X\n", num); } num = read_boot_u16("Timeout"); if (num != -1) { printf("Timeout: %u seconds\n", num); } show_boot_order(); show_boot_vars(); } } free_dirents(boot_names, num_boot_names); free_vars(&boot_entry_list); if (ret) return 1; return 0; } efibootmgr-0.5.4/src/efibootmgr/module.mk0100644000175300017530000000155010737222652020303 0ustar mdomschmdomschefibootmgr_SRCDIR := src/efibootmgr efibootmgr_OBJECTS := efibootmgr.o efibootmgr_TARGETS := efibootmgr efibootmgr_FULLTARGET := \ $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_TARGETS)) efibootmgr_FULLOBJECT := \ $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_OBJECT)) efibootmgr_LIBS := crc32.o disk.o efi.o efichar.o gpt.o scsi_ioctls.o \ unparse_path.o efivars_procfs.o efivars_sysfs.o efibootmgr_LIBDIR := src/lib efibootmgr_FULLLIB := \ $(patsubst %,$(efibootmgr_LIBDIR)/%,$(efibootmgr_LIBS)) LIBS = -lpci -lz ALLDEPS += $(efibootmgr_FULLTARGET) CLEANLIST += $(efibootmgr_FULLTARGET) CLEANLIST += $(efibootmgr_FULLOBJECT) bindir_TARGETS += $(efibootmgr_FULLTARGET) $(efibootmgr_FULLTARGET): \ $(efibootmgr_FULLOBJECT) \ $(efibootmgr_FULLLIB) $(CC) $(CFLAGS) $(LDFLAGS) $(efibootmgr_SRCDIR)/efibootmgr.c $^ $(LIBS) -o $@ efibootmgr-0.5.4/src/include/0040775000175300017530000000000010737223475015763 5ustar mdomschmdomschefibootmgr-0.5.4/src/include/crc32.h0100664000175300017530000000216110716126424017036 0ustar mdomschmdomsch/* libparted - a library for manipulating disk partitions Copyright (C) 1998-2000 Free Software Foundation, Inc. crc32.h 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 */ #ifndef _CRC32_H #define _CRC32_H #include /* * This computes a 32 bit CRC of the data in the buffer, and returns the CRC. * The polynomial used is 0xedb88320. */ extern uint32_t crc32 (const void *buf, unsigned long len, uint32_t seed); #endif /* _CRC32_H */ efibootmgr-0.5.4/src/include/disk.h0100664000175300017530000000502710716126424017060 0ustar mdomschmdomsch/* disk.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _DISK_H #define _DISK_H #include /* Snagged from linux/include/asm-ia64/ioctl.h */ #define _IOC_NRBITS 8 #define _IOC_TYPEBITS 8 #define _IOC_SIZEBITS 14 #define _IOC_DIRBITS 2 #define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) #define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) #define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) #define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) #define _IOC_NRSHIFT 0 #define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) #define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) #define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) /* * Direction bits. */ #define _IOC_NONE 0U #define _IOC_WRITE 1U #define _IOC_READ 2U #define _IOC(dir,type,nr,size) \ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ ((size) << _IOC_SIZESHIFT)) /* used to create numbers */ #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) /* Snagged from linux/include/linux/fs.h */ #define BLKGETSIZE _IO(0x12,96) /* return device size */ enum _bus_type {bus_type_unknown, isa, pci}; enum _interface_type {interface_type_unknown, ata, atapi, scsi, usb, i1394, fibre, i2o, md}; int disk_get_pci(int fd, unsigned char *bus, unsigned char *device, unsigned char *function); int disk_info_from_fd(int fd, int *interface_type, unsigned int *controllernum, unsigned int *disknum, unsigned char *part); int disk_get_partition_info (int fd, uint32_t num, uint64_t *start, uint64_t *size, char *signature, uint8_t *mbr_type, uint8_t *signature_type); int disk_get_size(int fd, long *size); int get_sector_size(int fd); #endif efibootmgr-0.5.4/src/include/efi.h0100664000175300017530000002221510716126424016667 0ustar mdomschmdomsch/* efi.[ch] - Extensible Firmware Interface definitions Copyright (C) 2001, 2003 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EFI_H #define EFI_H /* * Extensible Firmware Interface * Based on 'Extensible Firmware Interface Specification' * version 1.02, 12 December, 2000 */ #include #include #define BITS_PER_LONG (sizeof(unsigned long) * 8) #define EFI_ERROR(x) ((x) | (1L << (BITS_PER_LONG - 1))) #define EFI_SUCCESS 0 #define EFI_LOAD_ERROR EFI_ERROR(1) #define EFI_INVALID_PARAMETER EFI_ERROR(2) #define EFI_UNSUPPORTED EFI_ERROR(3) #define EFI_BAD_BUFFER_SIZE EFI_ERROR(4) #define EFI_BUFFER_TOO_SMALL EFI_ERROR(5) #define EFI_NOT_FOUND EFI_ERROR(14) #define EFI_OUT_OF_RESOURCES EFI_ERROR(15) /******************************************************* * Boot Option Attributes *******************************************************/ #define LOAD_OPTION_ACTIVE 0x00000001 /****************************************************** * EFI Variable Attributes ******************************************************/ #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 typedef struct { uint8_t b[16]; } efi_guid_t; #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ ((efi_guid_t) \ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ (b) & 0xff, ((b) >> 8) & 0xff, \ (c) & 0xff, ((c) >> 8) & 0xff, \ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) /****************************************************** * GUIDs ******************************************************/ #define DEVICE_PATH_PROTOCOL \ EFI_GUID( 0x09576e91, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define EFI_GLOBAL_VARIABLE \ EFI_GUID( 0x8BE4DF61, 0x93CA, 0x11d2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C) #define EDD10_HARDWARE_VENDOR_PATH_GUID \ EFI_GUID( 0xCF31FAC5, 0xC24E, 0x11d2, 0x85, 0xF3, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) #define BLKX_UNKNOWN_GUID \ EFI_GUID( 0x47c7b225, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define DIR_UNKNOWN_GUID \ EFI_GUID( 0x47c7b227, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) #define ESP_UNKNOWN_GUID \ EFI_GUID( 0x47c7b226, 0xc42a, 0x11d2, 0x8e, 0x57, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) static inline int efi_guidcmp(efi_guid_t left, efi_guid_t right) { return memcmp(&left, &right, sizeof (efi_guid_t)); } typedef unsigned long efi_status_t; typedef uint8_t efi_bool_t; typedef uint16_t efi_char16_t; /* UNICODE character */ typedef struct _efi_variable_t { efi_char16_t VariableName[1024/sizeof(efi_char16_t)]; efi_guid_t VendorGuid; unsigned long DataSize; uint8_t Data[1024]; efi_status_t Status; uint32_t Attributes; } __attribute__((packed)) efi_variable_t; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint8_t data[1]; } __attribute__((packed)) EFI_DEVICE_PATH; typedef struct { uint32_t attributes; uint16_t file_path_list_length; efi_char16_t description[1]; EFI_DEVICE_PATH _unused_file_path_list[1]; } __attribute__((packed)) EFI_LOAD_OPTION; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t _HID; uint32_t _UID; } __attribute__((packed)) ACPI_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; efi_guid_t vendor_guid; uint8_t data[1]; } __attribute__((packed)) VENDOR_DEVICE_PATH; #define EDD10_HARDWARE_VENDOR_PATH_LENGTH 24 typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint8_t function; uint8_t device; } __attribute__((packed)) PCI_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint8_t socket; } __attribute__((packed)) PCCARD_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t memory_type; uint64_t start; uint64_t end; } __attribute__((packed)) MEMORY_MAPPED_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t controller; } __attribute__((packed)) CONTROLLER_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint16_t id; uint16_t lun; } __attribute__((packed)) SCSI_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint8_t primary_secondary; uint8_t slave_master; uint16_t lun; } __attribute__((packed)) ATAPI_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t reserved; uint64_t wwn; uint64_t lun; } __attribute__((packed)) FIBRE_CHANNEL_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t reserved; uint64_t guid; } __attribute__((packed)) I1394_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint8_t port; uint8_t endpoint; } __attribute__((packed)) USB_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint16_t vendor; uint16_t product; uint8_t class; uint8_t subclass; uint8_t protocol; } __attribute__((packed)) USB_CLASS_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t tid; } __attribute__((packed)) I2O_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint8_t macaddr[32]; uint8_t iftype; } __attribute__((packed)) MAC_ADDR_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t local_ip; uint32_t remote_ip; uint16_t local_port; uint16_t remote_port; uint16_t protocol; uint8_t static_addr; } __attribute__((packed)) IPv4_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint8_t local_ip[16]; uint8_t remote_ip[16]; uint16_t local_port; uint16_t remote_port; uint16_t protocol; uint8_t static_addr; } __attribute__((packed)) IPv6_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t reserved; uint64_t node_guid; uint64_t ioc_guid; uint64_t id; } __attribute__((packed)) INFINIBAND_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t reserved; uint64_t baud_rate; uint8_t data_bits; uint8_t parity; uint8_t stop_bits; } __attribute__((packed)) UART_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t part_num; uint64_t start; uint64_t size; uint8_t signature[16]; uint8_t mbr_type; uint8_t signature_type; uint8_t padding[6]; /* Emperically needed */ } __attribute__((packed)) HARDDRIVE_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint32_t boot_entry; uint64_t start; uint64_t size; } __attribute__((packed)) CDROM_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; efi_char16_t path_name[1]; } __attribute__((packed)) FILE_PATH_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; efi_guid_t guid; } __attribute__((packed)) MEDIA_PROTOCOL_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; uint16_t device_type; uint16_t status_flag; uint8_t description[1]; } __attribute__((packed)) BIOS_BOOT_SPEC_DEVICE_PATH; typedef struct { uint8_t type; uint8_t subtype; uint16_t length; } __attribute__((packed)) END_DEVICE_PATH; struct efivar_kernel_calls { efi_status_t (*read)(const char *name, efi_variable_t *var); efi_status_t (*edit)(const char *name, efi_variable_t *var); efi_status_t (*create)(efi_variable_t *var); efi_status_t (*delete)(efi_variable_t *var); char *path; }; /* Used for ACPI _HID */ #define EISAID_PNP0A03 0xa0341d0 /* Exported functions */ extern int make_linux_efi_variable(efi_variable_t *var, unsigned int free_number); extern char * efi_guid_unparse(efi_guid_t *guid, char *out); extern EFI_DEVICE_PATH *load_option_path(EFI_LOAD_OPTION *option); extern efi_status_t read_variable(const char *name, efi_variable_t *var); extern efi_status_t edit_variable(efi_variable_t *var); extern efi_status_t create_variable(efi_variable_t *var); extern efi_status_t delete_variable(efi_variable_t *var); extern efi_status_t create_or_edit_variable(efi_variable_t *var); extern void set_fs_kernel_calls(); extern int read_boot_var_names(struct dirent ***namelist); extern int variable_to_name(efi_variable_t *var, char *name); extern int var_name_to_path(const char *name, char *path); #endif /* EFI_H */ efibootmgr-0.5.4/src/include/efibootmgr.h0100664000175300017530000000315710716126424020265 0ustar mdomschmdomsch/* efibootmgr.h - Manipulates EFI variables as exported in /proc/efi/vars Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _EFIBOOTMGR_H #define _EFIBOOTMGR_H typedef struct { int argc; char **argv; int optind; char *disk; char *iface; char *loader; char *label; char *bootorder; char *testfile; char *extra_opts_file; uint32_t part; int edd_version; int edd10_devicenum; int bootnum; int bootnext; int verbose; int active; uint32_t acpi_hid; uint32_t acpi_uid; unsigned int delete_boot:1; unsigned int delete_bootorder:1; unsigned int delete_bootnext:1; unsigned int quiet:1; unsigned int showversion:1; unsigned int create:1; unsigned int unicode:1; unsigned int write_signature:1; unsigned int forcegpt:1; unsigned int set_timeout:1; unsigned int delete_timeout:1; unsigned short int timeout; } efibootmgr_opt_t; extern efibootmgr_opt_t opts; #endif efibootmgr-0.5.4/src/include/efichar.h0100664000175300017530000000247010716126424017526 0ustar mdomschmdomsch/* efichar.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _EFICHAR_H #define _EFICHAR_H int efichar_strlen(const efi_char16_t *p, int max); int efichar_strsize(const efi_char16_t *p); unsigned long efichar_from_char(efi_char16_t *dest, const char *src, size_t dest_len); unsigned long efichar_to_char(char *dest, const efi_char16_t *src, size_t dest_len); int efichar_strcmp(const efi_char16_t *s1, const efi_char16_t *s2); int efichar_char_strcmp(const char *s1, const efi_char16_t *s2); int efichar_strncpy(efi_char16_t *s1, const efi_char16_t *s2, int max); #endif efibootmgr-0.5.4/src/include/efivars_procfs.h0100664000175300017530000000205410716126424021136 0ustar mdomschmdomsch/* efivars_procfs.h - EFI Variables accessed through /proc/efi/vars Copyright (C) 2003 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EFIVARS_PROCFS_H #define EFIVARS_PROCFS_H #include "efi.h" #define PROCFS_DIR_EFI_VARS "/proc/efi/vars" extern struct efivar_kernel_calls procfs_kernel_calls; #endif /* EFIVARS_PROCFS_H */ efibootmgr-0.5.4/src/include/efivars_sysfs.h0100664000175300017530000000206610716126424021014 0ustar mdomschmdomsch/* efivars_sysfs.h - EFI Variables accessed through /sys/firmware/efi/vars Copyright (C) 2003 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef EFIVARS_SYSFS_H #define EFIVARS_SYSFS_H #include "efi.h" #define SYSFS_DIR_EFI_VARS "/sys/firmware/efi/vars" extern struct efivar_kernel_calls sysfs_kernel_calls; #endif /* EFIVARS_SYSFS_H */ efibootmgr-0.5.4/src/include/gpt.h0100664000175300017530000001412510737221712016716 0ustar mdomschmdomsch/* gpt.[ch] Copyright (C) 2000-2001 Dell Computer Corporation EFI GUID Partition Table handling Per Intel EFI Specification v1.02 http://developer.intel.com/technology/efi/efi.htm 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 */ #ifndef _GPT_H #define _GPT_H #include #include "efi.h" #define EFI_PMBR_OSTYPE_EFI 0xEF #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE #define MSDOS_MBR_SIGNATURE 0xaa55 #define GPT_BLOCK_SIZE 512 #define GPT_HEADER_SIGNATURE ((uint64_t)(0x5452415020494645LL)) #define GPT_HEADER_REVISION_V1_02 0x00010200 #define GPT_HEADER_REVISION_V1_00 0x00010000 #define GPT_HEADER_REVISION_V0_99 0x00009900 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1 #define PARTITION_SYSTEM_GUID \ EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \ 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) #define LEGACY_MBR_PARTITION_GUID \ EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \ 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F) #define PARTITION_MSFT_RESERVED_GUID \ EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \ 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE) #define PARTITION_BASIC_DATA_GUID \ EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \ 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) #define PARTITION_LINUX_RAID_GUID \ EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \ 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e) #define PARTITION_LINUX_SWAP_GUID \ EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \ 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f) #define PARTITION_LINUX_LVM_GUID \ EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) typedef struct _gpt_header { uint64_t signature; uint32_t revision; uint32_t header_size; uint32_t header_crc32; uint32_t reserved1; uint64_t my_lba; uint64_t alternate_lba; uint64_t first_usable_lba; uint64_t last_usable_lba; efi_guid_t disk_guid; uint64_t partition_entry_lba; uint32_t num_partition_entries; uint32_t sizeof_partition_entry; uint32_t partition_entry_array_crc32; uint8_t reserved2[GPT_BLOCK_SIZE - 92]; } __attribute__ ((packed)) gpt_header; typedef struct _gpt_entry_attributes { uint64_t required_to_function:1; uint64_t reserved:47; uint64_t type_guid_specific:16; } __attribute__ ((packed)) gpt_entry_attributes; typedef struct _gpt_entry { efi_guid_t partition_type_guid; efi_guid_t unique_partition_guid; uint64_t starting_lba; uint64_t ending_lba; gpt_entry_attributes attributes; efi_char16_t partition_name[72 / sizeof(efi_char16_t)]; } __attribute__ ((packed)) gpt_entry; /* These values are only defaults. The actual on-disk structures may define different sizes, so use those unless creating a new GPT disk! */ #define GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE 16384 /* Number of actual partition entries should be calculated as: */ #define GPT_DEFAULT_RESERVED_PARTITION_ENTRIES \ (GPT_DEFAULT_RESERVED_PARTITION_ENTRY_ARRAY_SIZE / \ sizeof(gpt_entry)) typedef struct _partition_record { uint8_t boot_indicator; /* Not used by EFI firmware. Set to 0x80 to indicate that this is the bootable legacy partition. */ uint8_t start_head; /* Start of partition in CHS address, not used by EFI firmware. */ uint8_t start_sector; /* Start of partition in CHS address, not used by EFI firmware. */ uint8_t start_track; /* Start of partition in CHS address, not used by EFI firmware. */ uint8_t os_type; /* OS type. A value of 0xEF defines an EFI system partition. Other values are reserved for legacy operating systems, and allocated independently of the EFI specification. */ uint8_t end_head; /* End of partition in CHS address, not used by EFI firmware. */ uint8_t end_sector; /* End of partition in CHS address, not used by EFI firmware. */ uint8_t end_track; /* End of partition in CHS address, not used by EFI firmware. */ uint32_t starting_lba; /* Starting LBA address of the partition on the disk. Used by EFI firmware to define the start of the partition. */ uint32_t size_in_lba; /* Size of partition in LBA. Used by EFI firmware to determine the size of the partition. */ } __attribute__ ((packed)) partition_record; /* Protected Master Boot Record & Legacy MBR share same structure */ /* Needs to be packed because the u16s force misalignment. */ typedef struct _legacy_mbr { uint8_t bootcode[440]; uint32_t unique_mbr_signature; uint16_t unknown; partition_record partition[4]; uint16_t signature; } __attribute__ ((packed)) legacy_mbr; #define EFI_GPT_PRIMARY_PARTITION_TABLE_LBA 1 /* Functions */ int gpt_disk_get_partition_info (int fd, uint32_t num, uint64_t *start, uint64_t *size, char *signature, uint8_t *mbr_type, uint8_t *signature_type); #endif /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */ efibootmgr-0.5.4/src/include/list.h0100664000175300017530000001010610716126424017073 0ustar mdomschmdomsch/* Copied from the Linux 2.4.4 kernel, in linux/include/linux/list.h */ #ifndef _LINUX_LIST_H #define _LINUX_LIST_H /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; typedef struct list_head list_t; #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) #define INIT_LIST_HEAD(ptr) do { \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ } while (0) /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_add(struct list_head * new, struct list_head * prev, struct list_head * next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static __inline__ void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static __inline__ void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty on entry does not return true after this, the entry is in an undefined state. */ static __inline__ void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static __inline__ void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static __inline__ int list_empty(struct list_head *head) { return head->next == head; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static __inline__ void list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; if (first != list) { struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #endif efibootmgr-0.5.4/src/include/module.mk0100664000175300017530000000003010716126424017560 0ustar mdomschmdomschCFLAGS += -Isrc/include efibootmgr-0.5.4/src/include/scsi_ioctls.h0100664000175300017530000000251210716126424020440 0ustar mdomschmdomsch/* scsi_ioctls.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _SCSI_IOCTLS_H #define _SCSI_IOCTLS_H #include /* Snagged from linux/include/scsi/scsi.h */ #define SCSI_IOCTL_GET_IDLUN 0x5382 #define SCSI_IOCTL_GET_PCI 0x5387 typedef struct scsi_idlun { uint32_t dev_id; uint32_t host_unique_id; } Scsi_Idlun; inline int get_scsi_idlun(int fd, Scsi_Idlun *idlun); inline int get_scsi_pci(int fd, char *slot_name); int idlun_to_components (Scsi_Idlun *idlun, unsigned char *host, unsigned char *channel, unsigned char *id, unsigned char *lun); #endif efibootmgr-0.5.4/src/include/unparse_path.h0100664000175300017530000000242010716126424020611 0ustar mdomschmdomsch/* unparse_path.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _UNPARSE_PATH_H #define _UNPARSE_PATH_H #include #include "efi.h" #define OFFSET_OF(struct_type, member) \ ((unsigned long) ((char *) &((struct_type*) 0)->member)) uint64_t unparse_path(char *buffer, EFI_DEVICE_PATH *path, uint16_t pathsize); void dump_raw_data(void *data, uint64_t length); unsigned long unparse_raw(char *buffer, uint8_t *p, uint64_t length); unsigned long unparse_raw_text(char *buffer, uint8_t *p, uint64_t length); #endif efibootmgr-0.5.4/src/lib/0040775000175300017530000000000010737203536015102 5ustar mdomschmdomschefibootmgr-0.5.4/src/lib/Makefile0100664000175300017530000000002410716126424016530 0ustar mdomschmdomsch%: +make -C ../ $* efibootmgr-0.5.4/src/lib/crc32.c0100664000175300017530000001640510716126424016162 0ustar mdomschmdomsch/* * Dec 5, 2000 Matt Domsch * - Copied crc32.c from the linux/drivers/net/cipe directory. * - Now pass seed as an arg * - changed len to be an unsigned long * - changed crc32val to be a register * - License remains unchanged! It's still GPL-compatable! */ /* ============================================================= */ /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ /* code or tables extracted from it, as desired without restriction. */ /* */ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ /* polynomial $edb88320 */ /* */ /* -------------------------------------------------------------------- */ #include static uint32_t crc32_tab[] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; /* Return a 32-bit CRC of the contents of the buffer. */ uint32_t crc32(const void *buf, unsigned long len, uint32_t seed) { unsigned long i; register uint32_t crc32val; const unsigned char *s = buf; crc32val = seed; for (i = 0; i < len; i ++) { crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8); } return crc32val; } efibootmgr-0.5.4/src/lib/disk.c0100664000175300017530000002767010716126424016206 0ustar mdomschmdomsch/* disk.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include "disk.h" #include "scsi_ioctls.h" #include "gpt.h" #include "efibootmgr.h" #define BLKSSZGET _IO(0x12,104) /* get block device sector size */ int disk_info_from_fd(int fd, int *interface_type, unsigned int *controllernum, unsigned int *disknum, unsigned char *part) { struct stat buf; int rc; uint64_t major; unsigned char minor; memset(&buf, 0, sizeof(struct stat)); rc = fstat(fd, &buf); if (rc == -1) { perror("stat"); return 1; } if (!(S_ISBLK(buf.st_mode) || S_ISREG(buf.st_mode))) { printf("Cannot stat non-block or non-regular file\n"); return 1; } major = buf.st_dev >> 8; minor = buf.st_dev && 0xFF; /* IDE disks can have up to 64 partitions, or 6 bits worth, * and have one bit for the disk number. * This leaves an extra bit at the top. */ if (major == 3) { *disknum = (minor >> 6) & 1; *controllernum = (major - 3 + 0) + *disknum; *interface_type = ata; *part = minor & 0x3F; return 0; } else if (major == 22) { *disknum = (minor >> 6) & 1; *controllernum = (major - 22 + 2) + *disknum; *interface_type = ata; *part = minor & 0x3F; return 0; } else if (major >= 33 && major <= 34) { *disknum = (minor >> 6) & 1; *controllernum = (major - 33 + 4) + *disknum; *interface_type = ata; *part = minor & 0x3F; return 0; } else if (major >= 56 && major <= 57) { *disknum = (minor >> 6) & 1; *controllernum = (major - 56 + 8) + *disknum; *interface_type = ata; *part = minor & 0x3F; return 0; } else if (major >= 88 && major <= 91) { *disknum = (minor >> 6) & 1; *controllernum = (major - 88 + 12) + *disknum; *interface_type = ata; *part = minor & 0x3F; return 0; } /* I2O disks can have up to 16 partitions, or 4 bits worth. */ if (major >= 80 && major <= 87) { *interface_type = i2o; *disknum = 16*(major-80) + (minor >> 4); *part = (minor & 0xF); return 0; } /* SCSI disks can have up to 16 partitions, or 4 bits worth * and have one bit for the disk number. */ if (major == 8) { *interface_type = scsi; *disknum = (minor >> 4); *part = (minor & 0xF); return 0; } else if ( major >= 65 && major <= 71) { *interface_type = scsi; *disknum = 16*(major-64) + (minor >> 4); *part = (minor & 0xF); return 0; } printf("Unknown interface type.\n"); return 1; } static int disk_get_scsi_pci(int fd, unsigned char *bus, unsigned char *device, unsigned char *function) { int rc, usefd=fd; struct stat buf; char slot_name[8]; unsigned int b=0,d=0,f=0; memset(&buf, 0, sizeof(buf)); rc = fstat(fd, &buf); if (rc == -1) { perror("stat"); return 1; } if (S_ISREG(buf.st_mode)) { /* can't call ioctl() on this file and have it succeed. * instead, need to open the block device * from /dev/. */ fprintf(stderr, "You must call this program with " "a file name such as /dev/sda.\n"); return 1; } rc = get_scsi_pci(usefd, slot_name); if (rc) { perror("get_scsi_pci"); return rc; } rc = sscanf(slot_name, "%x:%x.%x", &b,&d,&f); if (rc != 3) { printf("sscanf failed\n"); return 1; } *bus = b & 0xFF; *device = d & 0xFF; *function = f & 0xFF; return 0; } /* * The PCI interface treats multi-function devices as independent * devices. The slot/function address of each device is encoded * in a single byte as follows: * * 7:3 = slot * 2:0 = function * * pci bus 00 device 39 vid 8086 did 7111 channel 1 * 00:07.1 */ #define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) #define PCI_FUNC(devfn) ((devfn) & 0x07) static int disk_get_ide_pci(int fd, unsigned char *bus, unsigned char *device, unsigned char *function) { int num_scanned, procfd; unsigned int b=0,d=0,disknum=0, controllernum=0; unsigned char part=0; char procname[80], infoline[80]; size_t read_count; int interface_type; int rc; rc = disk_info_from_fd(fd, &interface_type, &controllernum, &disknum, &part); if (rc) return rc; sprintf(procname, "/proc/ide/ide%d/config", controllernum); procfd = open(procname, O_RDONLY); if (!procfd) { perror("opening /proc/ide/ide*/config"); return 1; } read_count = read(procfd, infoline, sizeof(infoline)-1); close(procfd); num_scanned = sscanf(infoline, "pci bus %x device %x vid %*x did %*x channel %*x", &b, &d); if (num_scanned == 2) { *bus = b; *device = PCI_SLOT(d); *function = PCI_FUNC(d); } return 0; } #if 0 /* this is a list of devices */ static int disk_get_md_parts(int fd) { return 0; } #endif int disk_get_pci(int fd, unsigned char *bus, unsigned char *device, unsigned char *function) { int interface_type=interface_type_unknown; unsigned int controllernum=0, disknum=0; unsigned char part=0; disk_info_from_fd(fd, &interface_type, &controllernum, &disknum, &part); switch (interface_type) { case ata: return disk_get_ide_pci(fd, bus, device, function); break; case scsi: return disk_get_scsi_pci(fd, bus, device, function); break; case i2o: break; case md: break; default: break; } return 1; } int disk_get_size(int fd, long *size) { return ioctl(fd, BLKGETSIZE, size); } /** * is_mbr_valid(): test MBR for validity * @mbr: pointer to a legacy mbr structure * * Description: Returns 1 if MBR is valid, 0 otherwise. * Validity depends on one thing: * 1) MSDOS signature is in the last two bytes of the MBR */ static int is_mbr_valid(legacy_mbr *mbr) { if (!mbr) return 0; return (mbr->signature == MSDOS_MBR_SIGNATURE); } /************************************************************ * msdos_disk_get_extended partition_info() * Requires: * - open file descriptor fd * - start, size * Modifies: all these * Returns: * 0 on success * non-zero on failure * ************************************************************/ static int msdos_disk_get_extended_partition_info (int fd, legacy_mbr *mbr, uint32_t num, uint64_t *start, uint64_t *size) { /* Until I can handle these... */ fprintf(stderr, "Extended partition info not supported.\n"); return 1; } /************************************************************ * msdos_disk_get_partition_info() * Requires: * - mbr * - open file descriptor fd (for extended partitions) * - start, size, signature, mbr_type, signature_type * Modifies: all these * Returns: * 0 on success * non-zero on failure * ************************************************************/ static int msdos_disk_get_partition_info (int fd, legacy_mbr *mbr, uint32_t num, uint64_t *start, uint64_t *size, char *signature, uint8_t *mbr_type, uint8_t *signature_type) { int rc; long disk_size=0; struct stat stat; struct timeval tv; if (!mbr) return 1; if (!is_mbr_valid(mbr)) return 1; *mbr_type = 0x01; *signature_type = 0x01; if (!mbr->unique_mbr_signature && !opts.write_signature) { printf("\n\n******************************************************\n"); printf("Warning! This MBR disk does not have a unique signature.\n"); printf("If this is not the first disk found by EFI, you may not be able\n"); printf("to boot from it without a unique signature.\n"); printf("Run efibootmgr with the -w flag to write a unique signature\n"); printf("to the disk.\n"); printf("******************************************************\n\n"); } else if (opts.write_signature) { /* MBR Signatures must be unique for the EFI Boot Manager to find the right disk to boot from */ rc = fstat(fd, &stat); if (rc == -1) { perror("stat disk"); } rc = gettimeofday(&tv, NULL); if (rc == -1) { perror("gettimeofday"); } /* Write the device type to the signature. This should be unique per disk per system */ mbr->unique_mbr_signature = tv.tv_usec << 16; mbr->unique_mbr_signature |= stat.st_rdev & 0xFFFF; /* Write it to the disk */ lseek(fd, 0, SEEK_SET); write(fd, mbr, sizeof(*mbr)); } *(uint32_t *)signature = mbr->unique_mbr_signature; if (num > 4) { /* Extended partition */ return msdos_disk_get_extended_partition_info(fd, mbr, num, start, size); } else if (num == 0) { /* Whole disk */ *start = 0; disk_get_size(fd, &disk_size); *size = disk_size; } else if (num >= 1 && num <= 4) { /* Primary partition */ *start = mbr->partition[num-1].starting_lba; *size = mbr->partition[num-1].size_in_lba; } return 0; } /************************************************************ * get_sector_size * Requires: * - filedes is an open file descriptor, suitable for reading * Modifies: nothing * Returns: * sector size, or 512. ************************************************************/ int get_sector_size(int filedes) { int rc, sector_size = 512; rc = ioctl(filedes, BLKSSZGET, §or_size); if (rc) sector_size = 512; return sector_size; } /** * disk_get_partition_info() * @fd - open file descriptor to disk * @num - partition number (1 is first partition on the disk) * @start - partition starting sector returned * @size - partition size (in sectors) returned * @signature - partition signature returned * @mbr_type - partition type returned * @signature_type - signature type returned * * Description: Finds partition table info for given partition on given disk. * Both GPT and MSDOS partition tables are tested for. * Returns 0 on success, non-zero on failure */ int disk_get_partition_info (int fd, uint32_t num, uint64_t *start, uint64_t *size, char *signature, uint8_t *mbr_type, uint8_t *signature_type) { legacy_mbr *mbr; void *mbr_unaligned; off_t offset; int this_bytes_read = 0; int gpt_invalid=0, mbr_invalid=0; int rc=0; int sector_size = get_sector_size(fd); if (sizeof(*mbr) != sector_size) return 1; mbr_unaligned = malloc(sizeof(*mbr)+sector_size-1); mbr = (legacy_mbr *) (((unsigned long)mbr_unaligned + sector_size - 1) & ~(unsigned long)(sector_size-1)); memset(mbr, 0, sizeof(*mbr)); offset = lseek(fd, 0, SEEK_SET); this_bytes_read = read(fd, mbr, sizeof(*mbr)); if (this_bytes_read < sizeof(*mbr)) { rc=1; goto error_free_mbr; } gpt_invalid = gpt_disk_get_partition_info(fd, num, start, size, signature, mbr_type, signature_type); if (gpt_invalid) { mbr_invalid = msdos_disk_get_partition_info(fd, mbr, num, start, size, signature, mbr_type, signature_type); if (mbr_invalid) { rc=1; goto error_free_mbr; } } error_free_mbr: free(mbr_unaligned); return rc; } #ifdef DISK_EXE int main (int argc, char *argv[]) { int fd, rc; unsigned char bus=0,device=0,func=0; if (argc <= 1) return 1; fd = open(argv[1], O_RDONLY|O_DIRECT); rc = disk_get_pci(fd, &bus, &device, &func); if (!rc) { printf("PCI %02x:%02x.%02x\n", bus, device, func); } return rc; } #endif efibootmgr-0.5.4/src/lib/efi.c0100664000175300017530000004461010737171131016006 0ustar mdomschmdomsch/* efivars_proc.[ch] - Manipulates EFI variables as exported in /proc/efi/vars Copyright (C) 2001,2003 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "efi.h" #include "efichar.h" #include "scsi_ioctls.h" #include "disk.h" #include "efibootmgr.h" #include "efivars_procfs.h" #include "efivars_sysfs.h" #include "list.h" static struct efivar_kernel_calls *fs_kernel_calls; EFI_DEVICE_PATH * load_option_path(EFI_LOAD_OPTION *option) { char *p = (char *) option; return (EFI_DEVICE_PATH *) (p + sizeof(uint32_t) /* Attributes */ + sizeof(uint16_t) /* FilePathListLength*/ + efichar_strsize(option->description)); /* Description */ } char * efi_guid_unparse(efi_guid_t *guid, char *out) { sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->b[3], guid->b[2], guid->b[1], guid->b[0], guid->b[5], guid->b[4], guid->b[7], guid->b[6], guid->b[8], guid->b[9], guid->b[10], guid->b[11], guid->b[12], guid->b[13], guid->b[14], guid->b[15]); return out; } void set_fs_kernel_calls() { char name[PATH_MAX]; DIR *dir; snprintf(name, PATH_MAX, "%s", SYSFS_DIR_EFI_VARS); dir = opendir(name); if (dir) { closedir(dir); fs_kernel_calls = &sysfs_kernel_calls; return; } snprintf(name, PATH_MAX, "%s", PROCFS_DIR_EFI_VARS); dir = opendir(name); if (dir) { closedir(dir); fs_kernel_calls = &procfs_kernel_calls; return; } fprintf(stderr, "Fatal: Couldn't open either sysfs or procfs directories for accessing EFI variables.\n"); fprintf(stderr, "Try 'modprobe efivars' as root.\n"); exit(1); } static efi_status_t write_variable_to_file(efi_variable_t *var) { int fd, byteswritten; if (!var || !opts.testfile) return EFI_INVALID_PARAMETER; printf("Test mode: Writing to %s\n", opts.testfile); fd = creat(opts.testfile, S_IRWXU); if (fd == -1) { perror("Couldn't write to testfile"); return EFI_INVALID_PARAMETER; } byteswritten = write(fd, var, sizeof(*var)); if (byteswritten == -1) { perror("Writing to testfile"); } close(fd); return EFI_SUCCESS; } efi_status_t read_variable(const char *name, efi_variable_t *var) { if (!name || !var) return EFI_INVALID_PARAMETER; return fs_kernel_calls->read(name, var); } efi_status_t create_variable(efi_variable_t *var) { if (!var) return EFI_INVALID_PARAMETER; if (opts.testfile) return write_variable_to_file(var); return fs_kernel_calls->create(var); } efi_status_t delete_variable(efi_variable_t *var) { if (!var) return EFI_INVALID_PARAMETER; if (opts.testfile) return write_variable_to_file(var); return fs_kernel_calls->delete(var); } efi_status_t edit_variable(efi_variable_t *var) { char name[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; if (opts.testfile) return write_variable_to_file(var); variable_to_name(var, name); return fs_kernel_calls->edit(name, var); } efi_status_t create_or_edit_variable(efi_variable_t *var) { efi_variable_t testvar; char name[PATH_MAX]; memcpy(&testvar, var, sizeof(*var)); variable_to_name(var, name); if (read_variable(name, &testvar) == EFI_SUCCESS) return edit_variable(var); else return create_variable(var); } static int select_boot_var_names(const struct dirent *d) { if (!strncmp(d->d_name, "Boot", 4) && isxdigit(d->d_name[4]) && isxdigit(d->d_name[5]) && isxdigit(d->d_name[6]) && isxdigit(d->d_name[7]) && d->d_name[8] == '-') return 1; return 0; } int read_boot_var_names(struct dirent ***namelist) { if (!fs_kernel_calls || !namelist) return -1; return scandir(fs_kernel_calls->path, namelist, select_boot_var_names, alphasort); } static int get_edd_version() { efi_status_t status; efi_variable_t var; efi_guid_t guid = BLKX_UNKNOWN_GUID; char name[80], text_guid[40]; ACPI_DEVICE_PATH *path = (ACPI_DEVICE_PATH *)&(var.Data); int rc = 0; /* Allow global user option override */ switch (opts.edd_version) { case 0: /* No EDD information */ return 0; break; case 1: /* EDD 1.0 */ return 1; break; case 3: /* EDD 3.0 */ return 3; break; default: break; } memset(&var, 0, sizeof(efi_variable_t)); efi_guid_unparse(&guid, text_guid); sprintf(name, "blk0-%s", text_guid); status = read_variable(name, &var); if (status != EFI_SUCCESS) { return 0; } if (path->type == 2 && path->subtype == 1) rc = 3; else rc = 1; return rc; } /* EFI_DEVICE_PATH, 0x01 (Hardware), 0x04 (Vendor), length 0x0018 This needs to know what EFI device has the boot device. */ static uint16_t make_edd10_device_path(void *dest, uint32_t hardware_device) { VENDOR_DEVICE_PATH *hw; char buffer[EDD10_HARDWARE_VENDOR_PATH_LENGTH]; efi_guid_t guid = EDD10_HARDWARE_VENDOR_PATH_GUID; uint32_t *data; memset(buffer, 0, sizeof(buffer)); hw = (VENDOR_DEVICE_PATH *)buffer; data = (uint32_t *)hw->data; hw->type = 0x01; /* Hardware Device Path */ hw->subtype = 0x04; /* Vendor */ hw->length = EDD10_HARDWARE_VENDOR_PATH_LENGTH; memcpy(&(hw->vendor_guid), &guid, sizeof(guid)); *data = hardware_device; memcpy(dest, buffer, hw->length); return hw->length; } static uint16_t make_end_device_path(void *dest) { END_DEVICE_PATH p; memset(&p, 0, sizeof(p)); p.type = 0x7F; /* End of Hardware Device Path */ p.subtype = 0xFF; /* End Entire Device Path */ p.length = sizeof(p); memcpy(dest, &p, p.length); return p.length; } static uint16_t make_acpi_device_path(void *dest, uint32_t _HID, uint32_t _UID) { ACPI_DEVICE_PATH p; memset(&p, 0, sizeof(p)); p.type = 2; p.subtype = 1; p.length = sizeof(p); p._HID = _HID; p._UID = _UID; memcpy(dest, &p, p.length); return p.length; } static uint16_t make_mac_addr_device_path(void *dest, char *mac, uint8_t iftype) { int i; MAC_ADDR_DEVICE_PATH p; memset(&p, 0, sizeof(p)); p.type = 3; p.subtype = 11; p.length = sizeof(p); for (i=0; i < 14; i++) { p.macaddr[i] = mac[i]; } p.iftype = iftype; memcpy(dest, &p, p.length); return p.length; } struct device { struct pci_dev *pci_dev; struct list_head node; }; static struct device * is_parent_bridge(struct pci_dev *p, unsigned int target_bus) { struct device *d; unsigned int primary, secondary; if ( (pci_read_word(p, PCI_HEADER_TYPE) & 0x7f) != PCI_HEADER_TYPE_BRIDGE) return NULL; primary=pci_read_byte(p, PCI_PRIMARY_BUS); secondary=pci_read_byte(p, PCI_SECONDARY_BUS); if (secondary != target_bus) return NULL; d = malloc(sizeof(struct device)); if (!d) return NULL; memset(d, 0, sizeof(*d)); INIT_LIST_HEAD(&d->node); d->pci_dev = p; return d; } static struct device * find_parent(struct pci_access *pacc, unsigned int target_bus) { struct device *dev; struct pci_dev *p; for (p=pacc->devices; p; p=p->next) { dev = is_parent_bridge(p, target_bus); if (dev) return dev; } return NULL; } static uint16_t make_one_pci_device_path(void *dest, uint8_t device, uint8_t function) { PCI_DEVICE_PATH p; memset(&p, 0, sizeof(p)); p.type = 1; p.subtype = 1; p.length = sizeof(p); p.device = device; p.function = function; memcpy(dest, &p, p.length); return p.length; } static uint16_t make_pci_device_path(void *dest, uint8_t bus, uint8_t device, uint8_t function) { struct device *dev; struct pci_access *pacc; struct list_head *pos, *n; LIST_HEAD(pci_parent_list); char *p = dest; pacc = pci_alloc(); if (!pacc) return 0; pci_init(pacc); pci_scan_bus(pacc); do { dev = find_parent(pacc, bus); if (dev) { list_add(&pci_parent_list, &dev->node); bus = dev->pci_dev->bus; } } while (dev && bus); list_for_each_safe(pos, n, &pci_parent_list) { dev = list_entry(pos, struct device, node); p += make_one_pci_device_path(p, dev->pci_dev->dev, dev->pci_dev->func); list_del(&dev->node); free(dev); } p += make_one_pci_device_path(p, device, function); pci_cleanup(pacc); return ((void *)p - dest); } static uint16_t make_scsi_device_path(void *dest, uint16_t id, uint16_t lun) { SCSI_DEVICE_PATH p; memset(&p, 0, sizeof(p)); p.type = 3; p.subtype = 2; p.length = sizeof(p); p.id = id; p.lun = lun; memcpy(dest, &p, p.length); return p.length; } static uint16_t make_harddrive_device_path(void *dest, uint32_t num, uint64_t start, uint64_t size, uint8_t *signature, uint8_t mbr_type, uint8_t signature_type) { HARDDRIVE_DEVICE_PATH p; memset(&p, 0, sizeof(p)); p.type = 4; p.subtype = 1; p.length = sizeof(p); p.part_num = num; p.start = start; p.size = size; if (signature) memcpy(p.signature, signature, 16); p.mbr_type = mbr_type; p.signature_type = signature_type; memcpy(dest, &p, p.length); return p.length; } static uint16_t make_file_path_device_path(void *dest, efi_char16_t *name) { FILE_PATH_DEVICE_PATH *p; char buffer[1024]; int namelen = efichar_strlen(name, -1); int namesize = efichar_strsize(name); memset(buffer, 0, sizeof(buffer)); p = (FILE_PATH_DEVICE_PATH *)buffer; p->type = 4; p->subtype = 4; p->length = 4 + namesize; efichar_strncpy(p->path_name, name, namelen); memcpy(dest, buffer, p->length); return p->length; } static long make_edd30_device_path(int fd, void *buffer) { int rc=0; unsigned char bus=0, device=0, function=0; Scsi_Idlun idlun; unsigned char host=0, channel=0, id=0, lun=0; char *p = buffer; rc = disk_get_pci(fd, &bus, &device, &function); if (rc) return 0; memset(&idlun, 0, sizeof(idlun)); rc = get_scsi_idlun(fd, &idlun); if (rc) return 0; idlun_to_components(&idlun, &host, &channel, &id, &lun); p += make_acpi_device_path (p, EISAID_PNP0A03, bus); p += make_pci_device_path (p, bus, device, function); p += make_scsi_device_path (p, id, lun); return ((void *)p - buffer); } /** * make_disk_load_option() * @disk disk * * Returns 0 on error, length of load option created on success. */ char *make_disk_load_option(char *p, char *disk) { int disk_fd=0; char buffer[80]; char signature[16]; int rc, edd_version=0; uint8_t mbr_type=0, signature_type=0; uint64_t start=0, size=0; efi_char16_t os_loader_path[40]; memset(signature, 0, sizeof(signature)); disk_fd = open(opts.disk, O_RDWR); if (disk_fd == -1) { sprintf(buffer, "Could not open disk %s", opts.disk); perror(buffer); return 0; } if (opts.edd_version) { edd_version = get_edd_version(); if (edd_version == 3) { p += make_edd30_device_path(disk_fd, p); } else if (edd_version == 1) { p += make_edd10_device_path(p, opts.edd10_devicenum); } } rc = disk_get_partition_info (disk_fd, opts.part, &start, &size, signature, &mbr_type, &signature_type); close(disk_fd); if (rc) { fprintf(stderr, "Error: no partition information on disk %s.\n" " Cowardly refusing to create a boot option.\n", opts.disk); return 0; } p += make_harddrive_device_path (p, opts.part, start, size, signature, mbr_type, signature_type); efichar_from_char(os_loader_path, opts.loader, sizeof(os_loader_path)); p += make_file_path_device_path (p, os_loader_path); p += make_end_device_path (p); return(p); } /** * make_net_load_option() * @data - load option returned * * Returns NULL on error, or p advanced by length of load option * created on success. */ char *make_net_load_option(char *p, char *iface) { /* copied pretty much verbatim from the ethtool source */ int fd = 0, err; int bus, slot, func; struct ifreq ifr; struct ethtool_drvinfo drvinfo; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, iface); drvinfo.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (caddr_t)&drvinfo; /* Open control socket */ fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("Cannot get control socket"); goto out; } err = ioctl(fd, SIOCETHTOOL, &ifr); if (err < 0) { perror("Cannot get driver information"); goto out; } /* The domain part was added in 2.6 kernels. Test for that first. */ err = sscanf(drvinfo.bus_info, "%*x:%2x:%2x.%x", &bus, &slot, &func); if (err != 3) { err = sscanf(drvinfo.bus_info, "%2x:%2x.%x", &bus, &slot, &func); if (err != 3) { perror("Couldn't parse device location string."); goto out; } } err = ioctl(fd, SIOCGIFHWADDR, &ifr); if (err < 0) { perror("Cannot get hardware address."); goto out; } p += make_acpi_device_path(p, opts.acpi_hid, opts.acpi_uid); p += make_pci_device_path(p, bus, (uint8_t)slot, (uint8_t)func); p += make_mac_addr_device_path(p, ifr.ifr_ifru.ifru_hwaddr.sa_data, 0); p += make_end_device_path (p); return(p); out: return NULL; } /** * make_linux_load_option() * @data - load option returned * * Returns 0 on error, length of load option created on success. */ static unsigned long make_linux_load_option(void *data) { EFI_LOAD_OPTION *load_option = data; char *p = data, *q; efi_char16_t description[64]; unsigned long datasize=0; /* Write Attributes */ if (opts.active) load_option->attributes = LOAD_OPTION_ACTIVE; else load_option->attributes = 0; p += sizeof(uint32_t); /* skip writing file_path_list_length */ p += sizeof(uint16_t); /* Write description. This is the text that appears on the screen for the load option. */ memset(description, 0, sizeof(description)); efichar_from_char(description, opts.label, sizeof(description)); efichar_strncpy(load_option->description, description, sizeof(description)); p += efichar_strsize(load_option->description); q = p; if (opts.iface) { p = (char *)make_net_load_option(p, opts.iface); } else { p = (char *)make_disk_load_option(p, opts.iface); } if (p == NULL) return 0; load_option->file_path_list_length = p - q; datasize = (uint8_t *)p - (uint8_t *)data; return datasize; } /* * append_extra_args() * appends all arguments from argv[] not snarfed by getopt * as one long string onto data, up to maxchars. allow for nulls */ static unsigned long append_extra_args_ascii(void *data, unsigned long maxchars) { char *p = data; int i, appended=0; unsigned long usedchars=0; if (!data) return 0; for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) { p = strncpy(p, opts.argv[i], maxchars-usedchars-1); p += strlen(p); appended=1; usedchars = p - (char *)data; /* Put a space between args */ if (i < (opts.argc-1)) { p = strncpy(p, " ", maxchars-usedchars-1); p += strlen(p); usedchars = p - (char *)data; } } /* Remember the NULL */ if (appended) return strlen(data) + 1; return 0; } static unsigned long append_extra_args_unicode(void *data, unsigned long maxchars) { char *p = data; int i, appended=0; unsigned long usedchars=0; if (!data) return 0; for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) { p += efichar_from_char((efi_char16_t *)p, opts.argv[i], maxchars-usedchars); usedchars = efichar_strsize(data) - sizeof(efi_char16_t); appended=1; /* Put a space between args */ if (i < (opts.argc-1)) { p += efichar_from_char((efi_char16_t *)p, " ", maxchars-usedchars); usedchars = efichar_strsize(data) - sizeof(efi_char16_t); } } if (appended) return efichar_strsize( (efi_char16_t *)data ); return 0; } static unsigned long append_extra_args_file(void *data, unsigned long maxchars) { char *p = data; char *file = opts.extra_opts_file; int fd = STDIN_FILENO; ssize_t num_read=0; unsigned long appended=0; if (!data) return 0; if (file && strncmp(file, "-", 1)) fd = open(file, O_RDONLY); if (fd == -1) { perror("Failed to open extra arguments file"); exit(1); } do { num_read = read(fd, p, maxchars - appended); if (num_read < 0) { perror("Error reading extra arguments file"); break; } else if (num_read>0) { appended += num_read; p += num_read; } } while (num_read > 0 && ((maxchars - appended) > 0)); if (fd != STDIN_FILENO) close(fd); return appended; } static unsigned long append_extra_args(void *data, unsigned long maxchars) { unsigned long bytes_written=0; if (opts.extra_opts_file) bytes_written += append_extra_args_file(data, maxchars); if (opts.unicode) bytes_written += append_extra_args_unicode(data, maxchars - bytes_written); else bytes_written += append_extra_args_ascii(data, maxchars - bytes_written); return bytes_written; } int make_linux_efi_variable(efi_variable_t *var, unsigned int free_number) { efi_guid_t guid = EFI_GLOBAL_VARIABLE; char buffer[16]; unsigned char *optional_data=NULL; unsigned long load_option_size = 0, opt_data_size=0; memset(buffer, 0, sizeof(buffer)); /* VariableName needs to be BootXXXX */ sprintf(buffer, "Boot%04X", free_number); efichar_from_char(var->VariableName, buffer, 1024); memcpy(&(var->VendorGuid), &guid, sizeof(guid)); var->Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; /* Set Data[] and DataSize */ load_option_size = make_linux_load_option(var->Data); if (!load_option_size) return 0; /* Set OptionalData (passed as binary to the called app) */ optional_data = var->Data + load_option_size; opt_data_size = append_extra_args(optional_data, sizeof(var->Data) - load_option_size); var->DataSize = load_option_size + opt_data_size; return var->DataSize; } int variable_to_name(efi_variable_t *var, char *name) { char *p = name; efichar_to_char(p, var->VariableName, PATH_MAX); p += strlen(p); p += sprintf(p, "-"); efi_guid_unparse(&var->VendorGuid, p); return strlen(name); } efibootmgr-0.5.4/src/lib/efichar.c0100664000175300017530000000572010716126424016645 0ustar mdomschmdomsch/* efichar.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Best as I can tell, efi_char16_t characters are unicode characters, but are encoded in little-endian UCS-2 http://www.cl.cam.ac.uk/~mgk25/unicode.html. libunicode expects characters to be encoded in UTF-8, so I can't use that. Therefore, we need a UCS-2 library. */ #include #include #include "efi.h" #include "efichar.h" int efichar_char_strcmp(const char *s1, const efi_char16_t *s2) { int i, rc; char *buffer; int s2_len = efichar_strlen(s2, -1); buffer = malloc(s2_len+1); if (!buffer) return -1; memset(buffer, 0, s2_len+1); for (i=0; i<(s2_len); i++) { buffer[i] = s2[i] & 0xFF; } buffer[i] = '\0'; rc = strcmp(s1, buffer); free(buffer); return rc; } int efichar_strcmp(const efi_char16_t *s1, const efi_char16_t *s2) { int i; int s1_len = efichar_strlen(s1, -1); int s2_len = efichar_strlen(s2, -1); for (i=0; i < s1_len && i < s2_len; i++) { if (s1[i] < s2[i]) return -1; if (s1[i] > s2[i]) return 1; } /* Hit the end of one string */ if (i == s1_len && i != s2_len) return -1; if (i != s1_len && i == s2_len) return 1; return 0; } unsigned long efichar_from_char(efi_char16_t *dest, const char *src, size_t dest_len) { int i, src_len = strlen(src); for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) { dest[i] = src[i]; } dest[i] = 0; return i * sizeof(*dest); } unsigned long efichar_to_char(char *dest, const efi_char16_t *src, size_t dest_len) { int i, src_len = efichar_strlen(src, -1); for (i=0; i < src_len && i < (dest_len/sizeof(*dest)) - 1; i++) { dest[i] = src[i]; } dest[i] = 0; return i; } int efichar_strlen(const efi_char16_t *p, int max) { int len=0; const efi_char16_t *start = p; if (!p || !*p) return 0; while ((max < 0 || p - start < max) && *(p+len)) { ++len; } return len; } #ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #endif int efichar_strncpy(efi_char16_t *dest, const efi_char16_t *src, int max) { int i; int src_len = efichar_strlen(src, max); for (i=0; i < MIN(max,src_len); i++) { dest[i] = src[i]; } dest[i] = 0; return i; } int efichar_strsize(const efi_char16_t *p) { return (efichar_strlen(p, -1) + 1) * sizeof(efi_char16_t); } efibootmgr-0.5.4/src/lib/efivars_procfs.c0100664000175300017530000001012210716126424020247 0ustar mdomschmdomsch/* efivars_procfs.[ch] - Manipulates EFI variables as exported in /proc/efi/vars Copyright (C) 2001,2003 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include "efi.h" #include "efichar.h" #include "efibootmgr.h" #include "efivars_procfs.h" static efi_status_t procfs_read_variable(const char *name, efi_variable_t *var) { char filename[PATH_MAX]; int fd; size_t readsize; if (!name || !var) return EFI_INVALID_PARAMETER; snprintf(filename, PATH_MAX-1, "%s/%s", PROCFS_DIR_EFI_VARS,name); fd = open(filename, O_RDONLY); if (fd == -1) { return EFI_NOT_FOUND; } readsize = read(fd, var, sizeof(*var)); if (readsize != sizeof(*var)) { close(fd); return EFI_INVALID_PARAMETER; } close(fd); return var->Status; } /** * select_variable_names() * @d - dirent to compare against * * This ignores "." and ".." entries, and selects all others. */ static int select_variable_names(const struct dirent *d) { if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) return 0; return 1; } /** * find_write_victim() * @var - variable to be written * @file - name of file to open for writing @var is returned. * * This ignores "." and ".." entries, and selects all others. */ static char * find_write_victim(efi_variable_t *var, char file[PATH_MAX]) { struct dirent **namelist = NULL; int i, n, found=0; char testname[PATH_MAX], *p; memset(testname, 0, sizeof(testname)); n = scandir(PROCFS_DIR_EFI_VARS, &namelist, select_variable_names, alphasort); if (n < 0) return NULL; p = testname; efichar_to_char(p, var->VariableName, PATH_MAX); p += strlen(p); p += sprintf(p, "-"); efi_guid_unparse(&var->VendorGuid, p); for (i=0; id_name, sizeof(testname))) { found++; sprintf(file, "%s/%s", PROCFS_DIR_EFI_VARS, namelist[i]->d_name); break; } } while (n--) { if (namelist[n]) { free(namelist[n]); namelist[n] = NULL; } } free(namelist); if (!found) return NULL; return file; } static efi_status_t procfs_write_variable(efi_variable_t *var) { int fd; size_t writesize; char buffer[PATH_MAX], name[PATH_MAX], *p = NULL; if (!var) return EFI_INVALID_PARAMETER; memset(buffer, 0, sizeof(buffer)); memset(name, 0, sizeof(name)); p = find_write_victim(var, name); if (!p) return EFI_INVALID_PARAMETER; fd = open(name, O_WRONLY); if (fd == -1) { sprintf(buffer, "write_variable():open(%s)", name); perror(buffer); return EFI_INVALID_PARAMETER; } writesize = write(fd, var, sizeof(*var)); if (writesize != sizeof(*var)) { close(fd); return EFI_INVALID_PARAMETER; } close(fd); return EFI_SUCCESS; } static efi_status_t procfs_delete_variable(efi_variable_t *var) { if (!var) return EFI_INVALID_PARAMETER; var->DataSize = 0; var->Attributes = 0; return procfs_write_variable(var); } static efi_status_t procfs_edit_variable(const char *unused, efi_variable_t *var) { if (!var) return EFI_INVALID_PARAMETER; return procfs_write_variable(var); } struct efivar_kernel_calls procfs_kernel_calls = { .read = procfs_read_variable, .edit = procfs_edit_variable, .create = procfs_write_variable, .delete = procfs_delete_variable, .path = PROCFS_DIR_EFI_VARS, }; efibootmgr-0.5.4/src/lib/efivars_sysfs.c0100664000175300017530000000620610716126424020132 0ustar mdomschmdomsch/* efivars_sysfs.[ch] - Manipulates EFI variables as exported in /sys/firmware/efi/vars Copyright (C) 2001,2003 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include "efi.h" #include "efichar.h" #include "efibootmgr.h" #include "efivars_sysfs.h" static efi_status_t sysfs_read_variable(const char *name, efi_variable_t *var) { char filename[PATH_MAX]; int fd; size_t readsize; char buffer[PATH_MAX+40]; if (!name || !var) return EFI_INVALID_PARAMETER; memset(buffer, 0, sizeof(buffer)); snprintf(filename, PATH_MAX-1, "%s/%s/raw_var", SYSFS_DIR_EFI_VARS,name); fd = open(filename, O_RDONLY); if (fd == -1) { return EFI_NOT_FOUND; } readsize = read(fd, var, sizeof(*var)); if (readsize != sizeof(*var)) { close(fd); return EFI_INVALID_PARAMETER; } close(fd); return var->Status; } static efi_status_t sysfs_write_variable(const char *filename, efi_variable_t *var) { int fd; size_t writesize; char buffer[PATH_MAX+40]; if (!filename || !var) return EFI_INVALID_PARAMETER; memset(buffer, 0, sizeof(buffer)); fd = open(filename, O_WRONLY); if (fd == -1) { return EFI_INVALID_PARAMETER; } writesize = write(fd, var, sizeof(*var)); if (writesize != sizeof(*var)) { close(fd); return EFI_INVALID_PARAMETER; } close(fd); return EFI_SUCCESS; } static efi_status_t sysfs_edit_variable(const char *name, efi_variable_t *var) { char filename[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; snprintf(filename, PATH_MAX-1, "%s/%s/raw_var", SYSFS_DIR_EFI_VARS,name); return sysfs_write_variable(filename, var); } static efi_status_t sysfs_create_variable(efi_variable_t *var) { char filename[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_DIR_EFI_VARS,"new_var"); return sysfs_write_variable(filename, var); } static efi_status_t sysfs_delete_variable(efi_variable_t *var) { char filename[PATH_MAX]; if (!var) return EFI_INVALID_PARAMETER; snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_DIR_EFI_VARS,"del_var"); return sysfs_write_variable(filename, var); } struct efivar_kernel_calls sysfs_kernel_calls = { .read = sysfs_read_variable, .edit = sysfs_edit_variable, .create = sysfs_create_variable, .delete = sysfs_delete_variable, .path = SYSFS_DIR_EFI_VARS, }; efibootmgr-0.5.4/src/lib/gpt.c0100664000175300017530000004710610716126433016042 0ustar mdomschmdomsch/* gpt.[ch] Copyright (C) 2000-2001 Dell Computer Corporation EFI GUID Partition Table handling Per Intel EFI Specification v1.02 http://developer.intel.com/technology/efi/efi.htm This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include "crc32.h" #include "disk.h" #include "gpt.h" #include "efibootmgr.h" #define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */ #define BLKGETSIZE _IO(0x12,96) /* return device size */ #define BLKSSZGET _IO(0x12,104) /* get block device sector size */ #define BLKGETSIZE64 _IOR(0x12,114,uint64_t) /* return device size in bytes (u64 *arg) */ struct blkdev_ioctl_param { unsigned int block; size_t content_length; char * block_contents; }; /** * efi_crc32() - EFI version of crc32 function * @buf: buffer to calculate crc32 of * @len - length of buf * * Description: Returns EFI-style CRC32 value for @buf * * This function uses the little endian Ethernet polynomial * but seeds the function with ~0, and xor's with ~0 at the end. * Note, the EFI Specification, v1.02, has a reference to * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). */ static inline uint32_t efi_crc32(const void *buf, unsigned long len) { return (crc32(buf, len, ~0L) ^ ~0L); } /** * is_pmbr_valid(): test Protective MBR for validity * @mbr: pointer to a legacy mbr structure * * Description: Returns 1 if PMBR is valid, 0 otherwise. * Validity depends on two things: * 1) MSDOS signature is in the last two bytes of the MBR * 2) One partition of type 0xEE is found */ static int is_pmbr_valid(legacy_mbr *mbr) { int i, found = 0, signature = 0; if (!mbr) return 0; signature = (__le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE); for (i = 0; signature && i < 4; i++) { if (mbr->partition[i].os_type == EFI_PMBR_OSTYPE_EFI_GPT) { found = 1; break; } } return (signature && found); } /** * kernel_has_blkgetsize64() * * Returns: 0 on false, 1 on true * True means kernel is 2.4.x, x>=18, or * is 2.5.x, x>4, or * is > 2.5 */ static int kernel_has_blkgetsize64(void) { int major=0, minor=0, patch=0, parsed; int rc; struct utsname u; memset(&u, 0, sizeof(u)); rc = uname(&u); if (rc) return 0; parsed = sscanf(u.release, "%d.%d.%d", &major, &minor, &patch); if (parsed < 3) return 0; if (major > 2) return 1; if (major == 2 && minor > 5) return 1; if (major == 2 && minor == 5 && patch >= 4) return 1; if (major == 2 && minor == 4 && patch >= 18) return 1; return 0; } /************************************************************ * _get_num_sectors * Requires: * - filedes is an open file descriptor, suitable for reading * Modifies: nothing * Returns: * Last LBA value on success * 0 on error * * Try getting BLKGETSIZE64 and BLKSSZGET first, * then BLKGETSIZE if necessary. * Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64 * which returns the number of 512-byte sectors, not the size of * the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3. ************************************************************/ static uint64_t _get_num_sectors(int filedes) { unsigned long sectors=0; uint64_t bytes=0; int rc; if (kernel_has_blkgetsize64()) { rc = ioctl(filedes, BLKGETSIZE64, &bytes); if (!rc) return bytes / get_sector_size(filedes); } rc = ioctl(filedes, BLKGETSIZE, §ors); if (rc) return 0; return sectors; } /************************************************************ * last_lba(): return number of last logical block of device * * @fd * * Description: returns Last LBA value on success, 0 on error. * Notes: The value st_blocks gives the size of the file * in 512-byte blocks, which is OK if * EFI_BLOCK_SIZE_SHIFT == 9. ************************************************************/ static uint64_t last_lba(int filedes) { int rc; uint64_t sectors = 0; struct stat s; memset(&s, 0, sizeof (s)); rc = fstat(filedes, &s); if (rc == -1) { fprintf(stderr, "last_lba() could not stat: %s\n", strerror(errno)); return 0; } if (S_ISBLK(s.st_mode)) { sectors = _get_num_sectors(filedes); } else { fprintf(stderr, "last_lba(): I don't know how to handle files with mode %x\n", s.st_mode); sectors = 1; } return sectors - 1; } static ssize_t read_lastoddsector(int fd, uint64_t lba, void *buffer, size_t count) { int rc; struct blkdev_ioctl_param ioctl_param; if (!buffer) return 0; ioctl_param.block = 0; /* read the last sector */ ioctl_param.content_length = count; ioctl_param.block_contents = buffer; rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param); if (rc == -1) perror("read failed"); return !rc; } static ssize_t read_lba(int fd, uint64_t lba, void *buffer, size_t bytes) { int sector_size = get_sector_size(fd); off_t offset = lba * sector_size; ssize_t bytesread; void *aligned; void *unaligned; if (bytes % sector_size) return EINVAL; unaligned = malloc(bytes+sector_size-1); aligned = (void *) (((unsigned long)unaligned + sector_size - 1) & ~(unsigned long)(sector_size-1)); memset(aligned, 0, bytes); lseek(fd, offset, SEEK_SET); bytesread = read(fd, aligned, bytes); memcpy(buffer, aligned, bytesread); free(unaligned); /* Kludge. This is necessary to read/write the last block of an odd-sized disk, until Linux 2.5.x kernel fixes. This is only used by gpt.c, and only to read one sector, so we don't have to be fancy. */ if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) { bytesread = read_lastoddsector(fd, lba, buffer, bytes); } return bytesread; } /** * alloc_read_gpt_entries(): reads partition entries from disk * @fd is an open file descriptor to the whole disk * @gpt is a buffer into which the GPT will be put * Description: Returns ptes on success, NULL on error. * Allocates space for PTEs based on information found in @gpt. * Notes: remember to free pte when you're done! */ static gpt_entry * alloc_read_gpt_entries(int fd, gpt_header * gpt) { gpt_entry *pte; size_t count = __le32_to_cpu(gpt->num_partition_entries) * __le32_to_cpu(gpt->sizeof_partition_entry); if (!count) return NULL; pte = (gpt_entry *)malloc(count); if (!pte) return NULL; memset(pte, 0, count); if (!read_lba(fd, __le64_to_cpu(gpt->partition_entry_lba), pte, count)) { free(pte); return NULL; } return pte; } /** * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk * @fd is an open file descriptor to the whole disk * @lba is the Logical Block Address of the partition table * * Description: returns GPT header on success, NULL on error. Allocates * and fills a GPT header starting at @ from @bdev. * Note: remember to free gpt when finished with it. */ static gpt_header * alloc_read_gpt_header(int fd, uint64_t lba) { gpt_header *gpt; gpt = (gpt_header *) malloc(sizeof (gpt_header)); if (!gpt) return NULL; memset(gpt, 0, sizeof (*gpt)); if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) { free(gpt); return NULL; } return gpt; } /** * is_gpt_valid() - tests one GPT header and PTEs for validity * @fd is an open file descriptor to the whole disk * @lba is the logical block address of the GPT header to test * @gpt is a GPT header ptr, filled on return. * @ptes is a PTEs ptr, filled on return. * * Description: returns 1 if valid, 0 on error. * If valid, returns pointers to newly allocated GPT header and PTEs. */ static int is_gpt_valid(int fd, uint64_t lba, gpt_header ** gpt, gpt_entry ** ptes) { int rc = 0; /* default to not valid */ uint32_t crc, origcrc; if (!gpt || !ptes) return 0; if (!(*gpt = alloc_read_gpt_header(fd, lba))) return 0; /* Check the GUID Partition Table signature */ if (__le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { /* printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n", __le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE); */ free(*gpt); *gpt = NULL; return rc; } /* Check the GUID Partition Table Header CRC */ origcrc = __le32_to_cpu((*gpt)->header_crc32); (*gpt)->header_crc32 = 0; crc = efi_crc32(*gpt, __le32_to_cpu((*gpt)->header_size)); if (crc != origcrc) { // printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc); (*gpt)->header_crc32 = __cpu_to_le32(origcrc); free(*gpt); *gpt = NULL; return 0; } (*gpt)->header_crc32 = __cpu_to_le32(origcrc); /* Check that the my_lba entry points to the LBA * that contains the GPT we read */ if (__le64_to_cpu((*gpt)->my_lba) != lba) { // printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", __le64_to_cpu((*gpt)->my_lba), lba); free(*gpt); *gpt = NULL; return 0; } if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) { free(*gpt); *gpt = NULL; return 0; } /* Check the GUID Partition Entry Array CRC */ crc = efi_crc32(*ptes, __le32_to_cpu((*gpt)->num_partition_entries) * __le32_to_cpu((*gpt)->sizeof_partition_entry)); if (crc != __le32_to_cpu((*gpt)->partition_entry_array_crc32)) { // printf("GUID Partitition Entry Array CRC check failed.\n"); free(*gpt); *gpt = NULL; free(*ptes); *ptes = NULL; return 0; } /* We're done, all's well */ return 1; } /** * compare_gpts() - Search disk for valid GPT headers and PTEs * @pgpt is the primary GPT header * @agpt is the alternate GPT header * @lastlba is the last LBA number * Description: Returns nothing. Sanity checks pgpt and agpt fields * and prints warnings on discrepancies. * */ static void compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba) { int error_found = 0; if (!pgpt || !agpt) return; if (__le64_to_cpu(pgpt->my_lba) != __le64_to_cpu(agpt->alternate_lba)) { fprintf(stderr, "GPT:Primary header LBA != Alt. header alternate_lba\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", __le64_to_cpu(pgpt->my_lba), __le64_to_cpu(agpt->alternate_lba)); error_found++; } if (__le64_to_cpu(pgpt->alternate_lba) != __le64_to_cpu(agpt->my_lba)) { fprintf(stderr, "GPT:Primary header alternate_lba != Alt. header my_lba\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", __le64_to_cpu(pgpt->alternate_lba), __le64_to_cpu(agpt->my_lba)); error_found++; } if (__le64_to_cpu(pgpt->first_usable_lba) != __le64_to_cpu(agpt->first_usable_lba)) { fprintf(stderr, "GPT:first_usable_lbas don't match.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", __le64_to_cpu(pgpt->first_usable_lba), __le64_to_cpu(agpt->first_usable_lba)); error_found++; } if (__le64_to_cpu(pgpt->last_usable_lba) != __le64_to_cpu(agpt->last_usable_lba)) { fprintf(stderr, "GPT:last_usable_lbas don't match.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", __le64_to_cpu(pgpt->last_usable_lba), __le64_to_cpu(agpt->last_usable_lba)); error_found++; } if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) { fprintf(stderr, "GPT:disk_guids don't match.\n"); error_found++; } if (__le32_to_cpu(pgpt->num_partition_entries) != __le32_to_cpu(agpt->num_partition_entries)) { fprintf(stderr, "GPT:num_partition_entries don't match: " "0x%x != 0x%x\n", __le32_to_cpu(pgpt->num_partition_entries), __le32_to_cpu(agpt->num_partition_entries)); error_found++; } if (__le32_to_cpu(pgpt->sizeof_partition_entry) != __le32_to_cpu(agpt->sizeof_partition_entry)) { fprintf(stderr, "GPT:sizeof_partition_entry values don't match: " "0x%x != 0x%x\n", __le32_to_cpu(pgpt->sizeof_partition_entry), __le32_to_cpu(agpt->sizeof_partition_entry)); error_found++; } if (__le32_to_cpu(pgpt->partition_entry_array_crc32) != __le32_to_cpu(agpt->partition_entry_array_crc32)) { fprintf(stderr, "GPT:partition_entry_array_crc32 values don't match: " "0x%x != 0x%x\n", __le32_to_cpu(pgpt->partition_entry_array_crc32), __le32_to_cpu(agpt->partition_entry_array_crc32)); error_found++; } if (__le64_to_cpu(pgpt->alternate_lba) != lastlba) { fprintf(stderr, "GPT:Primary header thinks Alt. header is not at the end of the disk.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", __le64_to_cpu(pgpt->alternate_lba), lastlba); error_found++; } if (__le64_to_cpu(agpt->my_lba) != lastlba) { fprintf(stderr, "GPT:Alternate GPT header not at the end of the disk.\n"); fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n", __le64_to_cpu(agpt->my_lba), lastlba); error_found++; } if (error_found) fprintf(stderr, "GPT: Use GNU Parted to correct GPT errors.\n"); return; } /** * find_valid_gpt() - Search disk for valid GPT headers and PTEs * @fd is an open file descriptor to the whole disk * @gpt is a GPT header ptr, filled on return. * @ptes is a PTEs ptr, filled on return. * Description: Returns 1 if valid, 0 on error. * If valid, returns pointers to newly allocated GPT header and PTEs. * Validity depends on finding either the Primary GPT header and PTEs valid, * or the Alternate GPT header and PTEs valid, and the PMBR valid. */ static int find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr = NULL; uint64_t lastlba; if (!gpt || !ptes) return 0; lastlba = last_lba(fd); good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) { good_agpt = is_gpt_valid(fd, __le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt) { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } } else { good_agpt = is_gpt_valid(fd, lastlba, &agpt, &aptes); } /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) { goto fail; } /* This will be added to the EFI Spec. per Intel after v1.02. */ legacymbr = malloc(sizeof (*legacymbr)); if (legacymbr) { memset(legacymbr, 0, sizeof (*legacymbr)); read_lba(fd, 0, (uint8_t *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); free(legacymbr); legacymbr=NULL; } /* Failure due to bad PMBR */ if ((good_pgpt || good_agpt) && !good_pmbr && !opts.forcegpt) { fprintf(stderr, " Warning: Disk has a valid GPT signature " "but invalid PMBR.\n" " Assuming this disk is *not* a GPT disk anymore.\n" " Use gpt kernel option to override. " "Use GNU Parted to correct disk.\n"); goto fail; } /* Would fail due to bad PMBR, but force GPT anyhow */ if ((good_pgpt || good_agpt) && !good_pmbr && opts.forcegpt) { fprintf(stderr, " Warning: Disk has a valid GPT signature but " "invalid PMBR.\n" " Use GNU Parted to correct disk.\n" " gpt option taken, disk treated as GPT.\n"); } compare_gpts(pgpt, agpt, lastlba); /* The good cases */ if (good_pgpt && (good_pmbr || opts.forcegpt)) { *gpt = pgpt; *ptes = pptes; if (agpt) { free(agpt); agpt = NULL; } if (aptes) { free(aptes); aptes = NULL; } if (!good_agpt) { fprintf(stderr, "Alternate GPT is invalid, " "using primary GPT.\n"); } return 1; } else if (good_agpt && (good_pmbr || opts.forcegpt)) { *gpt = agpt; *ptes = aptes; if (pgpt) { free(pgpt); pgpt = NULL; } if (pptes) { free(pptes); pptes = NULL; } fprintf(stderr, "Primary GPT is invalid, using alternate GPT.\n"); return 1; } fail: if (pgpt) { free(pgpt); pgpt=NULL; } if (agpt) { free(agpt); agpt=NULL; } if (pptes) { free(pptes); pptes=NULL; } if (aptes) { free(aptes); aptes=NULL; } *gpt = NULL; *ptes = NULL; return 0; } /************************************************************ * gpt_disk_get_partition_info() * Requires: * - open file descriptor fd * - start, size, signature, mbr_type, signature_type * Modifies: all these * Returns: * 0 on success * non-zero on failure * ************************************************************/ int gpt_disk_get_partition_info(int fd, uint32_t num, uint64_t * start, uint64_t * size, char *signature, uint8_t * mbr_type, uint8_t * signature_type) { gpt_header *gpt = NULL; gpt_entry *ptes = NULL, *p; if (!find_valid_gpt(fd, &gpt, &ptes)) return 1; *mbr_type = 0x02; *signature_type = 0x02; if (num > 0 && num <= __le32_to_cpu(gpt->num_partition_entries)) { p = &ptes[num - 1]; *start = __le64_to_cpu(p->starting_lba); *size = __le64_to_cpu(p->ending_lba) - __le64_to_cpu(p->starting_lba) + 1; memcpy(signature, &p->unique_partition_guid, sizeof (p->unique_partition_guid)); } else { fprintf (stderr,"partition %d is not valid\n", num); return 1; } return 0; } /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */ efibootmgr-0.5.4/src/lib/module.mk0100664000175300017530000000005610716126424016713 0ustar mdomschmdomschCFLAGS += -Isrc/lib CLEANLIST += src/lib/*.o efibootmgr-0.5.4/src/lib/scsi_ioctls.c0100664000175300017530000000475510716126424017571 0ustar mdomschmdomsch/* scsi_ioctls.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "scsi_ioctls.h" int idlun_to_components (Scsi_Idlun *idlun, unsigned char *host, unsigned char *channel, unsigned char *id, unsigned char *lun) { if (!idlun || !host || !channel || !id || !lun) return 1; *host = (idlun->dev_id >> 24) & 0xFF; *channel = (idlun->dev_id >> 16) & 0xFF; *id = (idlun->dev_id ) & 0xFF; *lun = (idlun->dev_id >> 8) & 0xFF; return 0; } inline int get_scsi_idlun(int fd, Scsi_Idlun *idlun) { return ioctl(fd, SCSI_IOCTL_GET_IDLUN, idlun); } inline int get_scsi_pci(int fd, char *slot_name) { return ioctl(fd, SCSI_IOCTL_GET_PCI, slot_name); } #ifdef SCSI_IOCTLS_EXE static void usage(char **argv) { printf("Usage: %s /dev/sdX where sdX is a SCSI device node.\n", argv[0]); } int main(int argc, char **argv) { Scsi_Idlun idlun; char slot_name[8]; int fd = 0, rc = 0; memset(&idlun, 0, sizeof(idlun)); if (argc < 2) {usage(argv); exit(1);} fd = open(argv[1], O_RDONLY); if (fd == -1) { perror("Unable to open file"); exit(1); } rc = get_scsi_pci(fd, slot_name); if (rc) { perror("Unable to get_scsi_pci()"); } rc = get_scsi_idlun(fd, &idlun); if (rc) { perror("Unable to get_scsi_idlun()"); } printf("Device: %s\n", argv[1]); printf("PCI: %s\n", slot_name); printf("SCSI: host %d channel %d id %d lun %d, unique ID %x\n", (idlun.dev_id >> 24) & 0xFF, // host (idlun.dev_id >> 16) & 0xFF, // channel idlun.dev_id & 0xFF, // id (idlun.dev_id >> 8) & 0xFF, // lun idlun.host_unique_id); return 0; } #endif efibootmgr-0.5.4/src/lib/unparse_path.c0100664000175300017530000003070110716127217017733 0ustar mdomschmdomsch/* unparse_path.[ch] Copyright (C) 2001 Dell Computer Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* For PRIx64 */ #define __STDC_FORMAT_MACROS #include #include #include #include #include #include #include "efi.h" #include "unparse_path.h" #include "efichar.h" /* Avoid unaligned access warnings */ #define get(buf, obj) *(typeof(obj) *)memcpy(buf, &obj, sizeof(obj)) void dump_raw_data(void *data, uint64_t length) { char buffer1[80], buffer2[80], *b1, *b2, c; unsigned char *p = data; unsigned long column=0; uint64_t length_printed = 0; const char maxcolumn = 16; while (length_printed < length) { b1 = buffer1; b2 = buffer2; for (column = 0; column < maxcolumn && length_printed < length; column ++) { b1 += sprintf(b1, "%02x ",(unsigned int) *p); if (*p < 32 || *p > 126) c = '.'; else c = *p; b2 += sprintf(b2, "%c", c); p++; length_printed++; } /* pad out the line */ for (; column < maxcolumn; column++) { b1 += sprintf(b1, " "); b2 += sprintf(b2, " "); } printf("%s\t%s\n", buffer1, buffer2); } } unsigned long unparse_raw(char *buffer, uint8_t *p, uint64_t length) { uint64_t i; char a[1]; char *q = buffer; for (i=0; i 127) c = '.'; q += sprintf(q, "%c", c); } return q - buffer; } static int unparse_ipv4_port(char *buffer, uint32_t ipaddr, uint16_t port) { unsigned char *ip; // ipaddr = nltoh(ipaddr); // port = nstoh(port); ip = (unsigned char *)&ipaddr; return sprintf(buffer, "%hhu.%hhu.%hhu.%hhu:%hu", ip[0], ip[1], ip[2], ip[3], port); } static int unparse_acpi_path(char *buffer, EFI_DEVICE_PATH *path) { ACPI_DEVICE_PATH *acpi = (ACPI_DEVICE_PATH *)path; char a[16], b[16]; switch (path->subtype) { case 1: return sprintf(buffer, "ACPI(%x,%x)", get(a, acpi->_HID), get(b, acpi->_UID)); break; default: return unparse_raw(buffer, (uint8_t *)path, path->length); break; } return 0; } static int unparse_vendor_path(char *buffer, VENDOR_DEVICE_PATH *path) { char text_guid[40], *p = buffer; unsigned char *q = (uint8_t *)path + 20; efi_guid_unparse(&path->vendor_guid, text_guid); p += sprintf(p, "Vendor(%s,", text_guid); p += unparse_raw(p, q, path->length - 20); p += sprintf(p, ")"); return p - buffer; } static int unparse_hardware_path(char *buffer, EFI_DEVICE_PATH *path) { PCI_DEVICE_PATH *pci = (PCI_DEVICE_PATH *)path; PCCARD_DEVICE_PATH *pccard = (PCCARD_DEVICE_PATH *)path; MEMORY_MAPPED_DEVICE_PATH *mm = (MEMORY_MAPPED_DEVICE_PATH *)path; CONTROLLER_DEVICE_PATH *ctlr = (CONTROLLER_DEVICE_PATH *)path; char a[16], b[16], c[16]; switch (path->subtype) { case 1: return sprintf(buffer, "PCI(%x,%x)", get(a, pci->device), get(b, pci->function)); break; case 2: return sprintf(buffer, "PCCARD(%x)", get(a, pccard->socket)); break; case 3: return sprintf(buffer, "MM(%x,%" PRIx64 ",%" PRIx64 ")", get(a, mm->memory_type), get(b, mm->start), get(c, mm->end)); break; case 4: return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path); break; case 5: return sprintf(buffer, "Controller(%x)", get(a, ctlr->controller)); break; default: return unparse_raw(buffer, (uint8_t *)path, path->length); } return 0; } static int unparse_messaging_path(char *buffer, EFI_DEVICE_PATH *path) { ATAPI_DEVICE_PATH *atapi = (ATAPI_DEVICE_PATH *)path; SCSI_DEVICE_PATH *scsi = (SCSI_DEVICE_PATH *)path; FIBRE_CHANNEL_DEVICE_PATH *fc = (FIBRE_CHANNEL_DEVICE_PATH *)path; I1394_DEVICE_PATH *i1394 = (I1394_DEVICE_PATH *)path; USB_DEVICE_PATH *usb = (USB_DEVICE_PATH *)path; MAC_ADDR_DEVICE_PATH *mac = (MAC_ADDR_DEVICE_PATH *)path; USB_CLASS_DEVICE_PATH *usbclass = (USB_CLASS_DEVICE_PATH *)path; I2O_DEVICE_PATH *i2o = (I2O_DEVICE_PATH *)path; IPv4_DEVICE_PATH *ipv4 = (IPv4_DEVICE_PATH *)path; /* IPv6_DEVICE_PATH *ipv6 = (IPv6_DEVICE_PATH *)path; */ char *p = buffer; char a[16], b[16], c[16], d[16], e[16]; switch (path->subtype) { case 1: return sprintf(buffer, "ATAPI(%x,%x,%x)", get(a, atapi->primary_secondary), get(b, atapi->slave_master), get(c, atapi->lun)); break; case 2: return sprintf(buffer, "SCSI(%x,%x)", get(a, scsi->id), get(b, scsi->lun)); break; case 3: return sprintf(buffer, "FC(%" PRIx64 ",%" PRIx64 ")", get(a, fc->wwn), get(b, fc->lun)); break; case 4: return sprintf(buffer, "1394(%" PRIx64 ")", get(a, i1394->guid)); break; case 5: return sprintf(buffer, "USB(%x,%x)", get(a, usb->port), get(b, usb->endpoint)); break; case 6: return sprintf(buffer, "I2O(%x)", get(a, i2o->tid)); break; case 11: p += sprintf(p, "MAC("); p += unparse_raw(p, mac->macaddr, 6); p += sprintf(p, ",%hhx)", get(a, mac->iftype)); return (int) (p - buffer); break; case 12: p += sprintf(p, "IPv4("); p += unparse_ipv4_port(p, ipv4->local_ip, ipv4->local_port); p += sprintf(p, "<->"); p += unparse_ipv4_port(p, ipv4->remote_ip, ipv4->remote_port); p += sprintf(p, ",%hx, %hhx", get(a, ipv4->protocol), get(b, ipv4->static_addr)); return (int) (p - buffer); break; case 15: return sprintf(buffer, "USBClass(%hx,%hx,%hhx,%hhx,%hhx)", get(a, usbclass->vendor), get(b, usbclass->product), get(c, usbclass->class), get(d, usbclass->subclass), get(e, usbclass->protocol)); break; default: return unparse_raw(buffer, (uint8_t *)path, path->length); break; } return 0; } static int unparse_media_hard_drive_path(char *buffer, EFI_DEVICE_PATH *path) { HARDDRIVE_DEVICE_PATH *hd = (HARDDRIVE_DEVICE_PATH *)path; char text_uuid[40], *sig=text_uuid; char a[16], b[16], c[16]; switch (hd->signature_type) { case 0x00: sprintf(sig, "None"); break; case 0x01: sprintf(sig, "%08x", *(uint32_t *)memcpy(a, &hd->signature, sizeof(hd->signature))); break; case 0x02: /* GPT */ efi_guid_unparse((efi_guid_t *)hd->signature, sig); break; default: break; } return sprintf(buffer, "HD(%x,%" PRIx64 ",%" PRIx64 ",%s)", get(a, hd->part_num), get(b, hd->start), get(c, hd->size), sig); } static int unparse_media_path(char *buffer, EFI_DEVICE_PATH *path) { CDROM_DEVICE_PATH *cdrom = (CDROM_DEVICE_PATH *)path; MEDIA_PROTOCOL_DEVICE_PATH *media = (MEDIA_PROTOCOL_DEVICE_PATH *)path; FILE_PATH_DEVICE_PATH *file = (FILE_PATH_DEVICE_PATH *)path; char text_guid[40], *p = buffer; char file_name[80]; memset(file_name, 0, sizeof(file_name)); char a[16], b[16], c[16]; switch (path->subtype) { case 1: return unparse_media_hard_drive_path(buffer, path); break; case 2: return sprintf(buffer, "CD-ROM(%x,%" PRIx64 ",%" PRIx64 ")", get(a, cdrom->boot_entry), get(b, cdrom->start), get(c, cdrom->size)); break; case 3: return unparse_vendor_path(buffer, (VENDOR_DEVICE_PATH *)path); break; case 4: efichar_to_char(file_name, file->path_name, 80); return sprintf(p, "File(%s)", file_name); break; case 5: efi_guid_unparse(&media->guid, text_guid); return sprintf(buffer, "Media(%s)", text_guid); break; default: break; } return 0; } static int unparse_bios_path(char *buffer, EFI_DEVICE_PATH *path) { BIOS_BOOT_SPEC_DEVICE_PATH *bios = (BIOS_BOOT_SPEC_DEVICE_PATH *)path; char *p = buffer; unsigned char *q = (uint8_t *)path + 8; char a[16], b[16]; p += sprintf(p, "BIOS(%x,%x,", get(a, bios->device_type), get(b, bios->status_flag)); p += unparse_raw(p, q, path->length - 8); p += sprintf(p, ")"); return p - buffer; } uint64_t unparse_path(char *buffer, EFI_DEVICE_PATH *path, uint16_t pathsize) { uint16_t parsed_length = 0; char *p = buffer; int exit_now = 0; while (parsed_length < pathsize && !exit_now) { switch (path->type) { case 0x01: p += unparse_hardware_path(p, path); break; case 0x02: p += unparse_acpi_path(p, path); break; case 0x03: p += unparse_messaging_path(p, path); break; case 0x04: p += unparse_media_path(p, path); break; case 0x05: p += unparse_bios_path(p, path); break; case 0x7F: exit_now = 1; break; case 0xFF: exit_now = 1; break; default: printf("\nwierd path"); dump_raw_data(path, 4); break; } // p += sprintf(p, "\\"); parsed_length += path->length; path = (EFI_DEVICE_PATH *) ((uint8_t *)path + path->length); } return p - buffer; } #if 0 static void unparse_var(efi_variable_t *var) { char buffer[1024]; memset(buffer, 0, sizeof(buffer)); unparse_path(buffer, (EFI_DEVICE_PATH *)var->Data, var->DataSize); printf("%s\n", buffer); } static int compare_hardware_path_pci(EFI_DEVICE_PATH *path, int device, int func) { uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data); uint8_t path_device, path_func; switch (path->subtype) { case 1: /* PCI */ path_func = *(uint8_t *)p; path_device = *(uint8_t *)(p+1); return !(path_func == func && path_device == device); break; default: break; } return 1; } static int compare_hardware_path_scsi(EFI_DEVICE_PATH *path, int id, int lun) { uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data); uint16_t path_id, path_lun; switch (path->subtype) { case 2: /* SCSI */ path_id = *(uint16_t *)p; path_lun = *(uint16_t *)(p+2); return !(path_id == id && path_lun == lun); break; default: break; } return 1; } static int compare_hardware_path_acpi(EFI_DEVICE_PATH *path, int bus) { uint8_t *p = ((void *)path) + OFFSET_OF(EFI_DEVICE_PATH, data); uint32_t _HID, _UID; switch (path->subtype) { case 1: /* ACPI */ _HID = *(uint32_t *)p; _UID = *(uint32_t *)(p+4); /* FIXME: Need to convert _HID and _UID to bus number */ return 0; break; default: break; } return 1; } static int compare_media_path_harddrive(EFI_DEVICE_PATH *path, uint32_t num, uint64_t start, uint64_t size) { HARDDRIVE_DEVICE_PATH *p = (HARDDRIVE_DEVICE_PATH *)path; switch (path->subtype) { case 1: /* Hard Drive */ return !(p->part_num == num && p->start == start && p->size == size); break; default: break; } return 1; } int compare_pci_scsi_disk_blk(efi_variable_t *var, int bus, int device, int func, int host, int channel, int id, int lun, uint64_t start, uint64_t size) { EFI_DEVICE_PATH *path = (EFI_DEVICE_PATH *) var->Data; uint64_t parsed_length = 0; int exit_now = 0; int rc = 0; while (parsed_length < var->DataSize && !exit_now && !rc) { switch (path->type) { case 0x01: /* Hardware (PCI) */ rc = compare_hardware_path_pci(path, device, func); break; case 0x02: /* ACPI */ rc = compare_hardware_path_acpi(path, bus); break; case 0x03: /* Messaging (SCSI) */ rc = compare_messaging_path_scsi(path, id, lun); break; case 0x04: /* Media (Hard Drive) */ rc = compare_media_path_harddrive(path, 0, start, size); break; case 0x7F: case 0xFF: exit_now = 1; break; case 0x05: /* BIOS */ default: break; } parsed_length += path->length; path = var->Data + parsed_length; } return rc; } #endif #ifdef UNPARSE_PATH static void usage(void) { printf("Usage: dumppath filename\n"); printf("\t where filename is a blkXXXX EFI variable from /proc/efi/vars\n"); } int main(int argc, char **argv) { int fd = 0; ssize_t size; efi_variable_t var; if (argc == 1) { usage(); exit(-1); } fd = open(argv[1], O_RDONLY); if (fd == -1) { perror("Failed to open file."); exit(-1); } size = read(fd, &var, sizeof(var)); if (size == -1 || size < sizeof(var)) { perror("Failed to read file."); close(fd); exit(-1); } unparse_var(&var); return 0; } #endif efibootmgr-0.5.4/src/man/0040775000175300017530000000000010716126424015104 5ustar mdomschmdomschefibootmgr-0.5.4/src/man/man8/0040775000175300017530000000000010716126424015747 5ustar mdomschmdomschefibootmgr-0.5.4/src/man/man8/efibootmgr.80100664000175300017530000001620010716126424020171 0ustar mdomschmdomsch.\" This manpage has been automatically generated by docbook2man .\" from a DocBook document. This tool can be found at: .\" .\" Please send any bug reports, improvements, comments, patches, .\" etc. to Steve Cheng . .TH "EFIBOOTMGR" "8" "11 August 2005" "" "" .SH NAME efibootmgr \- manipulate the EFI Boot Manager .SH SYNOPSIS \fBefibootmgr\fR [ \fB-a\fR ] [ \fB-A\fR ] [ \fB-b \fIXXXX\fB\fR ] [ \fB-B \fIXXXX\fB\fR ] [ \fB-c\fR ] [ \fB-d \fIDISK\fB\fR ] [ \fB-e \fI1|3|-1\fB\fR ] [ \fB-E \fINUM\fB\fR ] [ \fB-g\fR ] [ \fB-H \fIXXXX\fB\fR ] [ \fB-i \fINAME\fB\fR ] [ \fB-l \fINAME\fB\fR ] [ \fB-L \fILABEL\fB\fR ] [ \fB-n \fIXXXX\fB\fR ] [ \fB-N\fR ] [ \fB-o \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR\fI ...\fR ] [ \fB-O\fR ] [ \fB-p \fIPART\fB\fR ] [ \fB-q\fR ] [ \fB-t \fIseconds\fB\fR ] [ \fB-T\fR ] [ \fB-u\fR ] [ \fB-U \fIXXXX\fB\fR ] [ \fB-v\fR ] [ \fB-V\fR ] [ \fB-w\fR ] [ \fB-@ \fIfile\fB\fR ] .SH "DESCRIPTION" .PP \fBefibootmgr\fR is a userspace application used to modify the Intel Extensible Firmware Interface (EFI) Boot Manager. This application can create and destroy boot entries, change the boot order, change the next running boot option, and more. .PP Details on the EFI Boot Manager are available from the EFI Specification, v1.02 or later, available from: .sp .RS .B "Note:" efibootmgr requires that the kernel support access to EFI non-volatile variables (through \fI/proc/efi/vars\fR on 2.4 kernels, \fI/sys/firmware/efi/vars\fR on 2.6 kernels). \fBmodprobe efivars\fR should do the trick. .RE .SH "OPTIONS" .PP The following is a list of options accepted by efibootmgr: .TP \fB-a | --active\fR Sets bootnum active .TP \fB-A | --inactive\fR Sets bootnum inactive .TP \fB-b | --bootnum \fIXXXX\fB\fR Modify Boot\fIXXXX\fR (hex) .TP \fB-B | --delete-bootnum\fR Delete bootnum (hex) .TP \fB-c | --create\fR Create new variable bootnum and add to bootorder .TP \fB-d | --disk \fIDISK\fB\fR The disk containing the loader (defaults to \fI/dev/sda\fR) .TP \fB-e | --edd \fI1|3|-1\fB\fR Force EDD 1.0 or 3.0 creation variables, or guess. .TP \fB-E | --device \fINUM\fB\fR EDD 1.0 device number (defaults to 0x80) .TP \fB-g | --gpt\fR Force disk with invalid PMBR to be treated as GPT .TP \fB-H | --acpi_hid \fIXXXX\fB\fR set the ACPI HID (used with \fB-i\fR) .TP \fB-i | --iface \fINAME\fB\fR create a netboot entry for the named interface .TP \fB-l | --loader \fINAME\fB\fR Specify a loader (defaults to \fI\\\\elilo.efi\fR) .TP \fB-L | --label \fILABEL\fB\fR Boot manager display label (defaults to "Linux") .TP \fB-n | --bootnext \fIXXXX\fB\fR Set BootNext to XXXX (hex) .TP \fB-N | --delete-bootnext\fR Delete BootNext .TP \fB-o | --bootorder \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR Explicitly set BootOrder (hex) .TP \fB-O | --delete-bootorder\fR Delete BootOrder .TP \fB-p | --part \fIPART\fB\fR Partition number containing the bootloader (defaults to 1) .TP \fB-q | --quiet\fR Quiet mode - supresses output. .TP \fB--test \fIfilename\fB\fR Don't write to NVRAM, write to \fIfilename\fR\&. .TP \fB-t | --timeout \fIseconds\fB\fR Boot Manager timeout, in \fIseconds\fR\&. .TP \fB-T | --delete-timeout\fR Delete Timeout variable. .TP \fB-u | --unicode | --UCS-2 \fR pass extra command line arguments as UCS-2 (default is ASCII) .TP \fB-U | --acpi_uid \fIXXXX\fB\fR set the ACPI UID (used with \fB-i\fR) .TP \fB-v | --verbose\fR Verbose mode - prints additional information .TP \fB-V | --version\fR Just print version string and exit. .TP \fB-w | --write-signature\fR write unique signature to the MBR if needed .TP \fB-@ | --append-binary-args \fR append extra variable args from file (use - to read from stdin). Data in file is appended as command line arguments to the boot loader command, with no modification to the data, so you can pass any binary or text data necessary. .SH "EXAMPLES" .TP 3 1. .SS "DISPLAYING THE CURRENT SETTINGS (MUST BE ROOT)." .PP [root@localhost ~]# efibootmgr BootCurrent: 0004 BootNext: 0003 BootOrder: 0004,0000,0001,0002,0003 Timeout: 30 seconds Boot0000* Diskette Drive(device:0) Boot0001* CD-ROM Drive(device:FF) Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233) Boot0003* PXE Boot: MAC(00D0B7C15D91) Boot0004* Linux .PP This shows: .RS .TP 0.2i \(bu BootCurrent - the boot entry used to start the currently running system .TP 0.2i \(bu BootOrder - the boot order as would appear in the boot manager. The boot manager tries to boot the first active entry in this list. If unsuccessful, it tries the next entry, and so on. .TP 0.2i \(bu BootNext - the boot entry which is scheduled to be run on next boot. This supercedes BootOrder for one boot only, and is deleted by the boot manager after first use. This allows you to change the next boot behavior without changing BootOrder. .TP 0.2i \(bu Timeout - the time in seconds between when the boot manager appears on the screen until when it automatically chooses the startup value from BootNext or BootOrder. .TP 0.2i \(bu Five boot entries (0000 - 0004), along with the active/inactive flag (* means active) and the name displayed on the screen. .RE .TP 3 2. .SS "CREATING A NEW BOOT OPTION" .PP An OS installer would call \fBefibootmgr -c\fR\&. This assumes that \fI/boot/efi\fR is your EFI System Partition, and is mounted at \fI/dev/sda1\fR\&. This creates a new boot option, called "Linux", and puts it at the top of the boot order list. Options may be passed to modify the default behavior. The default OS Loader is \fIelilo.efi\fR\&. .TP 3 3. .SS "CHANGING THE BOOT ORDER" .PP Assuming the configuration in Example #1, \fBefibootmgr -o 3,4\fR could be called to specify PXE boot first, then Linux boot. .TP 3 4. .SS "CHANGING THE BOOT ORDER FOR THE NEXT BOOT ONLY" .PP Assuming the configuration in Example #1, \fBefibootmgr -n 4\fR could be called to specify that the Linux entry be taken on next boot. .TP 3 5. .SS "DELETING A BOOT OPTION" .PP Assuming the configuration in Example #1, \fBefibootmgr -b 4 -B\fR could be called to delete entry 4 and remove it from the BootOrder. .TP 3 6. .SS "CREATING NETWORK BOOT ENTRIES" .PP A system administrator wants to create a boot option to network boot (PXE). Unfortunately, this requires knowing a little more information about your system than can be easily found by efibootmgr, so you've got to pass additional information - the ACPI HID and UID values. These can generally be found by using the EFI Boot Manager (in the EFI environment) to create a network boot entry, then using efibootmgr to print it verbosely. Here's one example: Boot003* Acpi(PNP0A03,0)/PCI(5|0)/Mac(00D0B7F9F510) \\ ACPI(a0341d0,0)PCI(0,5)MAC(00d0b7f9f510,0) In this case, the ACPI HID is "0A0341d0" and the UID is "0". For the zx2000 gigE, the HID is "222F" and the UID is "500". For the rx2000 gigE, the HID is "0002" and the UID is "100". You create the boot entry with: \fBefibootmgr -c -i eth0 -H 222F -U 500 -L netboot\fR .SH "BUGS" .PP Please direct any bugs, features, patches, etc. to Matt Domsch \&. .SH "AUTHOR" .PP This man page was generated by dann frazier for the Debian GNU/Linux operating system, but may be used by others. .SH "SEE ALSO" .PP elilo(1) efibootmgr-0.5.4/src/man/man8/efibootmgr.8.docbook0100664000175300017530000004041610716126424021616 0ustar mdomschmdomschdannf@debian.org, and was based on an example constructed by Colin Watson cjwatson@debian.org, which was based on a man page template provided by Tom Christiansen tchrist@jhereg.perl.com and a DocBook man page example by Craig Small csmall@debian.org. The content was mostly taken from the efibootmgr README file in the Debian package, which was written by Matt Domsch Matt_Domsch@dell.com. --> dann"> frazier"> 2005-08-11"> 8"> dannf@debian.org"> EFIBOOTMGR"> ]>
&manemail;
&manfirstname; &mansurname; 2002, 2003, 2004 &manusername; &mandate;
&manucpackage; &mansection; &manpackage; manipulate the EFI Boot Manager &manpackage; -a -A -b XXXX -B XXXX -c -d DISK -e 1|3|-1 -E NUM -g -H XXXX -i NAME -l NAME -L LABEL -n XXXX -N -o XXXX,YYYY,ZZZZ -O -p PART -q -t seconds -T -u -U XXXX -v -V -w -@ file DESCRIPTION &manpackage; is a userspace application used to modify the Intel Extensible Firmware Interface (EFI) Boot Manager. This application can create and destroy boot entries, change the boot order, change the next running boot option, and more. Details on the EFI Boot Manager are available from the EFI Specification, v1.02 or later, available from: &manpackage; requires that the kernel support access to EFI non-volatile variables (through /proc/efi/vars on 2.4 kernels, /sys/firmware/efi/vars on 2.6 kernels). modprobe efivars should do the trick. OPTIONS The following is a list of options accepted by &manpackage;: | Sets bootnum active | Sets bootnum inactive | XXXX Modify BootXXXX (hex) | Delete bootnum (hex) | Create new variable bootnum and add to bootorder | DISK The disk containing the loader (defaults to /dev/sda) | 1|3|-1 Force EDD 1.0 or 3.0 creation variables, or guess. | NUM EDD 1.0 device number (defaults to 0x80) | Force disk with invalid PMBR to be treated as GPT | XXXX set the ACPI HID (used with ) | NAME create a netboot entry for the named interface | NAME Specify a loader (defaults to \\elilo.efi) | LABEL Boot manager display label (defaults to "Linux") | XXXX Set BootNext to XXXX (hex) | Delete BootNext | XXXX,YYYY,ZZZZ Explicitly set BootOrder (hex) | Delete BootOrder | PART Partition number containing the bootloader (defaults to 1) | Quiet mode - supresses output. filename Don't write to NVRAM, write to filename. | seconds Boot Manager timeout, in seconds. | Delete Timeout variable. | | pass extra command line arguments as UCS-2 (default is ASCII) | XXXX set the ACPI UID (used with ) | Verbose mode - prints additional information | Just print version string and exit. | write unique signature to the MBR if needed | append extra variable args from file (use - to read from stdin). Data in file is appended as command line arguments to the boot loader command, with no modification to the data, so you can pass any binary or text data necessary. EXAMPLES Displaying the current settings (must be root). [root@localhost ~]# efibootmgr BootCurrent: 0004 BootNext: 0003 BootOrder: 0004,0000,0001,0002,0003 Timeout: 30 seconds Boot0000* Diskette Drive(device:0) Boot0001* CD-ROM Drive(device:FF) Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233) Boot0003* PXE Boot: MAC(00D0B7C15D91) Boot0004* Linux This shows: BootCurrent - the boot entry used to start the currently running system BootOrder - the boot order as would appear in the boot manager. The boot manager tries to boot the first active entry in this list. If unsuccessful, it tries the next entry, and so on. BootNext - the boot entry which is scheduled to be run on next boot. This supercedes BootOrder for one boot only, and is deleted by the boot manager after first use. This allows you to change the next boot behavior without changing BootOrder. Timeout - the time in seconds between when the boot manager appears on the screen until when it automatically chooses the startup value from BootNext or BootOrder. Five boot entries (0000 - 0004), along with the active/inactive flag (* means active) and the name displayed on the screen. Creating a new boot option An OS installer would call &manpackage; -c. This assumes that /boot/efi is your EFI System Partition, and is mounted at /dev/sda1. This creates a new boot option, called "Linux", and puts it at the top of the boot order list. Options may be passed to modify the default behavior. The default OS Loader is elilo.efi. Changing the Boot Order Assuming the configuration in Example #1, &manpackage; -o 3,4 could be called to specify PXE boot first, then Linux boot. Changing the Boot Order for the Next Boot Only Assuming the configuration in Example #1, &manpackage; -n 4 could be called to specify that the Linux entry be taken on next boot. Deleting a boot option Assuming the configuration in Example #1, &manpackage; -b 4 -B could be called to delete entry 4 and remove it from the BootOrder. Creating network boot entries A system administrator wants to create a boot option to network boot (PXE). Unfortunately, this requires knowing a little more information about your system than can be easily found by efibootmgr, so you've got to pass additional information - the ACPI HID and UID values. These can generally be found by using the EFI Boot Manager (in the EFI environment) to create a network boot entry, then using efibootmgr to print it verbosely. Here's one example: Boot003* Acpi(PNP0A03,0)/PCI(5|0)/Mac(00D0B7F9F510) \ ACPI(a0341d0,0)PCI(0,5)MAC(00d0b7f9f510,0) In this case, the ACPI HID is "0A0341d0" and the UID is "0". For the zx2000 gigE, the HID is "222F" and the UID is "500". For the rx2000 gigE, the HID is "0002" and the UID is "100". You create the boot entry with: efibootmgr -c -i eth0 -H 222F -U 500 -L netboot BUGS Please direct any bugs, features, patches, etc. to Matt Domsch Matt_Domsch@dell.com. AUTHOR This man page was generated by dann frazier &manemail; for the Debian GNU/Linux operating system, but may be used by others. SEE ALSO elilo(1)
efibootmgr-0.5.4/src/module.mk0100664000175300017530000000123710716126424016147 0ustar mdomschmdomsch#add our stuff first... our children need to wait for us to finish INSTALLDEPS += bindir_LIST MODULES := src/efibootmgr src/lib src/include include $(patsubst %,%/module.mk,$(MODULES)) # Common stuff to copy into the common directories # Note that the stuff below bindir_LIST is all on one line... bindir_LIST: @if [ ! -z "$(bindir_TARGETS)" ]; then \ echo "R-M-: %attr(0755,root,root) $(BINDIR)" ;\ for file in $(bindir_TARGETS) ;\ do \ echo "-C--: $(BUILDDIR)/$$file $(BINDIR)/" ;\ echo "R---: %attr(0755,root,root) $(BINDIR)/`basename $$file`" ;\ done ;\ echo ;\ fi efibootmgr-0.5.4/tools/0040775000175300017530000000000010716126424014702 5ustar mdomschmdomschefibootmgr-0.5.4/tools/install.pl0100775000175300017530000000531510716126424016711 0ustar mdomschmdomsch#!/usr/bin/perl -w #Pragmas use strict; #Parse command line... my ($copy, $link); my $type = shift @ARGV; if( $type =~ /^copy$/i ) { $copy = 1; } if( $type =~ /^link$/i ) { $link = 1; } #Main program loop open (RPMOUT, "> filelist-rpm") or die; while( <> ){ chomp; s/^\s*//; s/\s*$//; s/\s*#.*$//; next if m/^$/; my $line = $_; ($line =~ m/^R...:(.*)/) && print RPMOUT $1 . "\n"; ($line =~ m/^..M.:(.*)/) && MakeDir( $1 ); ($line =~ m/^.C..:(.*)/) && ($copy) && CopyFile( $1 ); ($line =~ m/^.C..:(.*)/) && ($link) && LinkFile( $1 ); ($line =~ m/^R...:(.*)/) && ChangeAttrs( $1 ); } sub CopyFile { my ($src, $dst) = ParseCLine( shift ); if( -d $dst ) { $src =~ m|^.*/(.*)$|; my $file = $1; $dst .= "/" if ! ($dst=~m|/$|); $dst .= $file; } if( -e $dst ) { unlink $dst; } open INPUT, "<", $src or goto out1; open OUTPUT, ">", $dst or goto out2; while(){ print OUTPUT $_ } close OUTPUT; print "Installed File: $dst\n"; out2: close INPUT; out1: return; } sub LinkFile { my ($src, $dst) = ParseCLine( shift ); if( -d $dst ) { $src =~ m|^.*/(.*)$|; my $file = $1; $dst .= "/" if ! ($dst=~m|/$|); $dst .= $file; } if( -e $dst ) { unlink $dst; } symlink $src, $dst or warn "Linking $src to $dst failed $!\n"; print "Installed File: $dst\n"; } sub ParseCLine { my $line = shift; $line =~ s/^\s*//; $line =~ s/\s*$//; $line =~ m/^(.*?)\s+(.*?)$/; return ($1, $2); } sub ParseRLine { my $line = shift; my @directives; my @retval; $line =~ s/^\s*//; $line =~ s/\s*$//; my @words = split( /\s+/, $line ); foreach my $word (@words) { if( $word =~ /^\%(.*)/ ) { push @directives, $word; } else { push @retval, $word; } } return \@retval, \@directives; } sub MakeDir { #R-M-: %attr(0755,root,ali) /opt/ali my $line = shift; #$line =~ m/\%attr\((.{1,5}),(\w+),(\w+)\)\s+(.*)/; my ($file_ref, $directive_ref) = ParseRLine( $line ); my $dir = $file_ref->[0]; if( ! -d $dir ) { mkdir $dir or warn "Make Dir: -->$dir<-- failed $!\n"; } print "Made Dir: $dir\n"; } sub GetUID { my $name = shift; my (undef, undef, $uid, undef) = getpwnam( $name ) ; $uid = defined($uid) ? $uid : -1; return $uid; } sub GetGID { my $name = shift; my (undef, undef, $gid, undef) = getgrnam( $name ) ; $gid = defined($gid) ? $gid : -1; return $gid; } sub ChangeAttrs { my $line = shift; my ($file_ref, $directive_ref) = ParseRLine( $line ); my ($attr) = grep { /^\%attr/ } @$directive_ref; $attr =~ m/\%attr\((.{1,5}),(\w+),(\w+)\)/; my $perms = $1; my $owner = $2; my $group = $3; my $file = $file_ref->[0]; my $uid = GetUID($owner); my $gid = GetGID($group); chown $uid, $gid, $file; chmod oct($perms), $file; }