diff options
author | Kay Sievers <kay@vrfy.org> | 2015-07-07 11:35:30 +0200 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2015-07-07 11:35:30 +0200 |
commit | 55df1539c9d330732e88bd196afee386db6e4a1d (patch) | |
tree | c2d157cdf71040efdd79f195fd5e3b6f41e9b8e8 | |
parent | 2bcd919c681c952eb867ef1bdb458f1bc49c2d55 (diff) |
-rw-r--r-- | .gitignore | 40 | ||||
-rw-r--r-- | .vimrc | 4 | ||||
-rw-r--r-- | LICENSE | 502 | ||||
-rw-r--r-- | Makefile.am | 203 | ||||
-rw-r--r-- | README | 26 | ||||
-rw-r--r-- | TODO | 0 | ||||
-rwxr-xr-x | autogen.sh | 36 | ||||
-rw-r--r-- | configure.ac | 155 | ||||
-rw-r--r-- | dead.package | 1 | ||||
-rw-r--r-- | m4/arch.m4 | 13 | ||||
-rw-r--r-- | man/gummiboot.xml | 137 | ||||
-rw-r--r-- | src/efi/console.c | 141 | ||||
-rw-r--r-- | src/efi/console.h | 34 | ||||
-rw-r--r-- | src/efi/graphics.c | 389 | ||||
-rw-r--r-- | src/efi/graphics.h | 26 | ||||
-rw-r--r-- | src/efi/gummiboot.c | 2047 | ||||
-rw-r--r-- | src/efi/linux.c | 130 | ||||
-rw-r--r-- | src/efi/linux.h | 24 | ||||
-rw-r--r-- | src/efi/pefile.c | 172 | ||||
-rw-r--r-- | src/efi/pefile.h | 22 | ||||
-rw-r--r-- | src/efi/stub.c | 106 | ||||
-rw-r--r-- | src/efi/util.c | 342 | ||||
-rw-r--r-- | src/efi/util.h | 50 | ||||
-rw-r--r-- | src/setup/efivars.c | 647 | ||||
-rw-r--r-- | src/setup/efivars.h | 55 | ||||
-rw-r--r-- | src/setup/setup.c | 1425 | ||||
-rw-r--r-- | test/gummiboot.svg | 1327 | ||||
-rw-r--r-- | test/splash.bmp | bin | 289238 -> 0 bytes | |||
-rwxr-xr-x | test/test-create-disk.sh | 43 |
29 files changed, 1 insertions, 8096 deletions
diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d482a5d..0000000 --- a/.gitignore +++ /dev/null @@ -1,40 +0,0 @@ -*~ -*.o -*.so -*.cache -*.log -.deps -.libs -*.8 -.dirstamp -/gummiboot -/gummiboot.so -/gummibootx64.efi -/gummibootia32.efi -/stub.so -/stubx64.efi -/stubia32.efi -/test-disk - -Makefile -aclocal.m4 -stamp-h.in -Makefile.in -configure -config.h -config.h.in -config.guess -config.status -config.sub -stamp-h -stamp-h1 -m4/*.m4 -config.rpath -mkinstalldirs -compile -depcomp -install-sh -missing - -# wanted files -!m4/arch.m4 @@ -1,4 +0,0 @@ -" 'set exrc' in ~/.vimrc will read .vimrc from the current directory -set tabstop=8 -set shiftwidth=8 -set expandtab diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 4362b49..0000000 --- a/LICENSE +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -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 and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, 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 library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete 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 distribute a copy of this License along with the -Library. - - 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 Library or any portion -of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -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 Library, 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 Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you 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. - - If distribution of 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 satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be 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. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library 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. - - 9. 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 Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -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 with -this License. - - 11. 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 Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library 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 Library. - -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. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library 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. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser 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 Library -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 Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -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 - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. 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 LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 6568a35..0000000 --- a/Makefile.am +++ /dev/null @@ -1,203 +0,0 @@ -# -# This file is part of gummiboot -# -# Copyright (C) 2013 Karel Zak <kzak@redhat.com> -# -# gummiboot is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# gummiboot 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with systemd; If not, see <http://www.gnu.org/licenses/>. - -ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} -AM_MAKEFLAGS = --no-print-directory - -gummibootlibdir = $(prefix)/lib/gummiboot - -AM_CPPFLAGS = -include config.h -AM_CFLAGS = \ - -D_GNU_SOURCE \ - -Wall \ - -Wextra \ - -Wmissing-prototypes \ - -Wno-unused-parameter -AM_LDFLAGS = - -EXTRA_DIST = autogen.sh README LICENSE -CLEANFILES = - -# ------------------------------------------------------------------------------ -if HAVE_BLKID -bin_PROGRAMS = gummiboot - -gummiboot_SOURCES = \ - src/setup/setup.c \ - src/setup/efivars.c \ - src/setup/efivars.h - -gummiboot_CPPFLAGS = \ - $(AM_CPPFLAGS) \ - -DMACHINE_TYPE_NAME=\"$(MACHINE_TYPE_NAME)\" \ - -DGUMMIBOOTLIBDIR=\"$(gummibootlibdir)\" - -gummiboot_CFLAGS = \ - $(AM_CFLAGS) \ - $(BLKID_CFLAGS) - -gummiboot_LDADD = \ - $(BLKID_LIBS) -endif - -if ENABLE_MANPAGES -%.8: %.xml - $(AM_V_GEN)$(XSLTPROC) -o $@ --nonet \ - --stringparam man.output.quietly 1 \ - --stringparam man.th.extra1.suppress 1 \ - --stringparam man.authors.section.enabled 0 \ - --stringparam man.copyright.section.enabled 0 \ - http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< - -dist_man_MANS = man/gummiboot.8 -endif - -EXTRA_DIST += man/gummiboot.xml -CLEANFILES += man/gummiboot.8 - -# ------------------------------------------------------------------------------ -# EFI compilation -- this part of the build system uses custom make rules and -# bypasses regular automake to provide absolute control on compiler and linker -# flags. -efi_cppflags = \ - $(EFI_CPPFLAGS) \ - -I$(top_builddir) -include config.h \ - -I$(EFI_INC_DIR)/efi \ - -I$(EFI_INC_DIR)/efi/$(ARCH) \ - -DMACHINE_TYPE_NAME=\"$(MACHINE_TYPE_NAME)\" - -efi_cflags = \ - $(EFI_CFLAGS) \ - -Wall \ - -Wextra \ - -std=gnu90 \ - -nostdinc \ - -ggdb -O0 \ - -fpic \ - -fshort-wchar \ - -nostdinc \ - -ffreestanding \ - -fno-strict-aliasing \ - -fno-stack-protector \ - -Wsign-compare \ - -mno-sse \ - -mno-mmx - -if ARCH_X86_64 -efi_cflags += \ - -mno-red-zone \ - -DEFI_FUNCTION_WRAPPER \ - -DGNU_EFI_USE_MS_ABI -endif - -efi_ldflags = \ - $(EFI_LDFLAGS) \ - -T $(EFI_LDS_DIR)/elf_$(ARCH)_efi.lds \ - -shared \ - -Bsymbolic \ - -nostdlib \ - -znocombreloc \ - -L $(EFI_LIB_DIR) \ - $(EFI_LDS_DIR)/crt0-efi-$(ARCH).o - -# ------------------------------------------------------------------------------ -gummiboot_headers = \ - src/efi/util.h \ - src/efi/console.h \ - src/efi/graphics.h \ - src/efi/pefile.h - -gummiboot_sources = \ - src/efi/util.c \ - src/efi/console.c \ - src/efi/graphics.c \ - src/efi/pefile.c \ - src/efi/gummiboot.c - -gummiboot_objects = $(addprefix $(top_builddir)/,$(gummiboot_sources:.c=.o)) -gummiboot_solib = $(top_builddir)/src/efi/gummiboot.so -gummiboot = gummiboot$(MACHINE_TYPE_NAME).efi - -gummibootlib_DATA = $(gummiboot) -CLEANFILES += $(gummiboot_objects) $(gummiboot_solib) $(gummiboot) -EXTRA_DIST += $(gummiboot_sources) $(gummiboot_headers) - -$(top_builddir)/src/efi/%.o: $(top_srcdir)/src/efi/%.c $(addprefix $(top_srcdir)/,$(gummiboot_headers)) - @$(MKDIR_P) $(top_builddir)/src/efi/ - $(AM_V_CC)$(EFI_CC) $(efi_cppflags) $(efi_cflags) -c $< -o $@ - -$(gummiboot_solib): $(gummiboot_objects) - $(AM_V_CCLD)$(LD) $(efi_ldflags) $(gummiboot_objects) \ - -o $@ -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name); \ - nm -D -u $@ | grep ' U ' && exit 1 || : -.DELETE_ON_ERROR: $(gummboot_solib) - -$(gummiboot): $(gummiboot_solib) - $(AM_V_GEN) objcopy -j .text -j .sdata -j .data -j .dynamic \ - -j .dynsym -j .rel -j .rela -j .reloc \ - --target=efi-app-$(ARCH) $< $@ - -# ------------------------------------------------------------------------------ -stub_headers = \ - src/efi/util.h \ - src/efi/pefile.h \ - src/efi/linux.h - -stub_sources = \ - src/efi/util.c \ - src/efi/pefile.c \ - src/efi/linux.c \ - src/efi/stub.c - -stub_objects = $(addprefix $(top_builddir)/,$(stub_sources:.c=.o)) -stub_solib = $(top_builddir)/src/efi/stub.so -stub = linux$(MACHINE_TYPE_NAME).efi.stub - -gummibootlib_DATA += $(stub) -CLEANFILES += $(stub_objects) $(stub_solib) $(stub) -EXTRA_DIST += $(stub_sources) $(stub_headers) - -$(top_builddir)/src/efi/%.o: $(top_srcdir)/src/efi/%.c $(addprefix $(top_srcdir)/,$(stub_headers)) - @$(MKDIR_P) $(top_builddir)/src/efi/ - $(AM_V_CC)$(EFI_CC) $(efi_cppflags) $(efi_cflags) -c $< -o $@ - -$(stub_solib): $(stub_objects) - $(AM_V_CCLD)$(LD) $(efi_ldflags) $(stub_objects) \ - -o $@ -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name); \ - nm -D -u $@ | grep ' U ' && exit 1 || : -.DELETE_ON_ERROR: $(gummboot_solib) - -$(stub): $(stub_solib) - $(AM_V_GEN) objcopy -j .text -j .sdata -j .data -j .dynamic \ - -j .dynsym -j .rel -j .rela -j .reloc \ - --target=efi-app-$(ARCH) $< $@ - -# ------------------------------------------------------------------------------ -CLEANFILES += test-disk.img -EXTRA_DIST += test/test-create-disk.sh - -test-disk.img: gummiboot$(MACHINE_TYPE_NAME).efi test/test-create-disk.sh - $(AM_V_GEN)test/test-create-disk.sh - -qemu: test-disk.img - $(QEMU) -machine accel=kvm -m 1024 -bios $(QEMU_BIOS) -snapshot test-disk.img - -install-tree: all - rm -rf $(abs_srcdir)/install-tree - $(MAKE) install DESTDIR=$(abs_srcdir)/install-tree - tree $(abs_srcdir)/install-tree @@ -1,26 +0,0 @@ -gummiboot Simple UEFI boot manager - -gummiboot executes EFI images. The default entry is selected by a configured -pattern (glob) or an on-screen menu. - -gummiboot operates on the EFI System Partition (ESP) only. Configuration -file fragments, kernels, initrds, other EFI images need to reside on the -ESP. Linux kernels must be built with CONFIG_EFI_STUB to be able to be -directly executed as an EFI image. - -gummiboot reads simple and entirely generic configurion files; one file -per boot entry to select from. - -Pressing Space (or most other) keys during bootup will show an on-screen -menu with all configured entries to select from. Pressing enter on the -selected entry loads and starts the EFI image. - -If no timeout is configured and no key pressed during bootup, the default -entry is booted right away. - -Further documentation is available in the gummiboot wiki at: - http://freedesktop.org/wiki/Software/gummiboot - -Links: - http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec - http://www.freedesktop.org/software/systemd/man/kernel-install.html diff --git a/autogen.sh b/autogen.sh deleted file mode 100755 index dfe9eba..0000000 --- a/autogen.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -# This file is part of gummiboot. -# -# gummiboot is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# gummiboot 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with systemd; If not, see <http://www.gnu.org/licenses/>. - -set -e - -autoreconf --force --install --symlink - -args="\ ---prefix=/usr" - -if [ "x$1" = "xc" ]; then - ./configure $args - make clean -else - echo - echo "----------------------------------------------------------------" - echo "Initialized build system. For a common configuration please run:" - echo "----------------------------------------------------------------" - echo - echo "./configure $args" - echo -fi diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 27bbe1d..0000000 --- a/configure.ac +++ /dev/null @@ -1,155 +0,0 @@ -# -# This file is part of gummiboot. -# -# Copyright (C) 2013 Karel Zak <kzak@redhat.com> -# -# gummiboot is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# gummiboot 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with systemd; If not, see <http://www.gnu.org/licenses/>. - -AC_INIT([gummiboot], - [48], - [systemd-devel@lists.freedesktop.org], - [gummiboot], - [http://freedesktop.org/wiki/Software/gummiboot]) - -AC_CONFIG_SRCDIR([src/setup/setup.c]) -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_PREFIX_DEFAULT([/usr]) - -AM_INIT_AUTOMAKE([foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects]) -AM_SILENT_RULES([yes]) - -AC_CANONICAL_HOST -AC_SYS_LARGEFILE - -AC_PROG_CC - -dnl Don't try to use things like -std=c99 for efi compilation -EFI_CC=$CC -AC_SUBST([EFI_CC]) - -AC_PROG_CC_C99 -AM_PROG_CC_C_O -AC_PROG_GCC_TRADITIONAL - -AC_PROG_MKDIR_P -AC_PATH_PROG([XSLTPROC], [xsltproc]) - -dnl Define ARCH_<NAME> conditionals -SET_ARCH(IA32, i*86*) -SET_ARCH(X86_64, x86_64*) -SET_ARCH(IA64, ia64*) - -ARCH=`echo $host | sed "s/\(-\).*$//"` - -AM_COND_IF(ARCH_IA32, [ - ARCH=ia32 - MACHINE_TYPE_NAME=ia32]) - -AM_COND_IF(ARCH_X86_64, [ - MACHINE_TYPE_NAME=x64]) - -AC_SUBST([ARCH]) -AC_SUBST([MACHINE_TYPE_NAME]) - -# QEMU and OVMF UEFI firmware -AS_IF([test x"$cross_compiling" = "xyes"], [], [ - AC_PATH_PROG([QEMU], [qemu-system-x86_64]) - AC_CHECK_FILE([/usr/share/qemu/bios-ovmf.bin], [QEMU_BIOS=/usr/share/qemu/bios-ovmf.bin]) - AC_CHECK_FILE([/usr/share/qemu-ovmf/bios.bin], [QEMU_BIOS=/usr/share/qemu-ovmf/bios.bin]) - AC_SUBST([QEMU_BIOS]) -]) - -# ------------------------------------------------------------------------------ -dnl GNU EFI doesn't use relative paths: efi.h includes efibind.h which is in -dnl ${ARCH} relative to efi.h. I can't find a way to get AC_CHECK_HEADERS to -dnl add -I/usr/include/efi/${ARCH} to the conftest.c build. So, just test for -dnl efibind.h as the chances of efi.h not existing if it does are very low. -AC_CHECK_HEADER(efi/${ARCH}/efibind.h, [], - [AC_MSG_ERROR([*** GNU EFI header efibind.h not found])]) - -efiroot=$(echo $(cd /usr/lib/$(gcc -print-multi-os-directory); pwd)) -EFI_LIB_DIR="$efiroot" -AC_ARG_WITH(efi-libdir, - AS_HELP_STRING([--with-efi-libdir=PATH], [Path to efi lib directory]), - [EFI_LIB_DIR="$withval"], [EFI_LIB_DIR="$efiroot"] -) -AC_SUBST([EFI_LIB_DIR]) - -dnl extra objects and linker scripts -AC_ARG_WITH(efi-ldsdir, - AS_HELP_STRING([--with-efi-ldsdir=PATH], [Path to efi lds directory]), - [EFI_LDS_DIR="$withval"], - [ - for EFI_LDS_DIR in "${efiroot}/gnuefi" "${efiroot}"; do - for lds in ${EFI_LDS_DIR}/elf_${ARCH}_efi.lds; do - test -f ${lds} && break 2 - done - done - ] -) -AC_SUBST([EFI_LDS_DIR]) - -AC_ARG_WITH(efi-includedir, - AS_HELP_STRING([--with-efi-includedir=PATH], [Path to efi include directory]), - [EFI_INC_DIR="$withval"], [EFI_INC_DIR="/usr/include"] -) -AC_SUBST([EFI_INC_DIR]) - -# ------------------------------------------------------------------------------ -AC_ARG_ENABLE(blkid, AS_HELP_STRING([--disable-blkid], [disable blkid support])) -if test "x$enable_blkid" != "xno"; then - PKG_CHECK_MODULES(BLKID, [ blkid >= 2.20 ], - [AC_DEFINE(HAVE_BLKID, 1, [Define if blkid is available]) have_blkid=yes], have_blkid=no) - if test "x$have_blkid" = xno -a "x$enable_blkid" = xyes; then - AC_MSG_ERROR([*** blkid support requested but libraries not found]) - fi -fi -AM_CONDITIONAL(HAVE_BLKID, [test "$have_blkid" = "yes"]) - -# ------------------------------------------------------------------------------ -have_manpages=no -AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages], [disable manpages])) -AS_IF([test "x$enable_manpages" != xno], [ - AS_IF([test "x$enable_manpages" = xyes -a "x$XSLTPROC" = x], [ - AC_MSG_ERROR([*** Manpages requested but xsltproc not found]) - ]) - AS_IF([test "x$XSLTPROC" != x], [have_manpages=yes]) -]) -AM_CONDITIONAL(ENABLE_MANPAGES, [test "x$have_manpages" = "xyes"]) - -# ------------------------------------------------------------------------------ -AC_CONFIG_FILES([ - Makefile -]) - -AC_OUTPUT -AC_MSG_RESULT([ - $PACKAGE_NAME $VERSION - - prefix: ${prefix} - arch: $ARCH - EFI machine type: $MACHINE_TYPE_NAME - - EFI libdir: ${EFI_LIB_DIR} - EFI ldsdir: ${EFI_LDS_DIR} - EFI includedir: ${EFI_INC_DIR} - - blkid: ${have_blkid} - man pages: ${have_manpages} - - QEMU: ${QEMU} - QEMU OVMF: ${QEMU_BIOS} -]) diff --git a/dead.package b/dead.package new file mode 100644 index 0000000..dbf503b --- /dev/null +++ b/dead.package @@ -0,0 +1 @@ +obsoleted diff --git a/m4/arch.m4 b/m4/arch.m4 deleted file mode 100644 index f17b427..0000000 --- a/m4/arch.m4 +++ /dev/null @@ -1,13 +0,0 @@ - -dnl SET_ARCH(ARCHNAME, PATTERN) -dnl -dnl Define ARCH_<archname> condition if the pattern match with the current -dnl architecture -dnl -AC_DEFUN([SET_ARCH], [ - cpu_$1=false - case "$host" in - $2) cpu_$1=true ;; - esac - AM_CONDITIONAL(AS_TR_CPP(ARCH_$1), [test "x$cpu_$1" = xtrue]) -]) diff --git a/man/gummiboot.xml b/man/gummiboot.xml deleted file mode 100644 index 36552f8..0000000 --- a/man/gummiboot.xml +++ /dev/null @@ -1,137 +0,0 @@ -<?xml version='1.0'?> <!--*-nxml-*--> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" - "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> - -<!-- - Copyright 2013 Kay Sievers - - gummiboot is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ---> - -<refentry id="gummiboot"> - <refentryinfo> - <title>gummiboot</title> - <productname>gummiboot</productname> - - <authorgroup> - <author> - <contrib>Developer</contrib> - <firstname>Kay</firstname> - <surname>Sievers</surname> - <email>kay@vrfy.org</email> - </author> - </authorgroup> - </refentryinfo> - - <refmeta> - <refentrytitle>gummiboot</refentrytitle> - <manvolnum>8</manvolnum> - </refmeta> - - <refnamediv> - <refname>gummiboot</refname> - <refpurpose>Setup and manage Gummiboot Boot Manager</refpurpose> - </refnamediv> - - <refsynopsisdiv> - <cmdsynopsis> - <command>gummiboot <arg choice="opt" rep="repeat">OPTIONS</arg>status</command> - </cmdsynopsis> - <cmdsynopsis> - <command>gummiboot <arg choice="opt" rep="repeat">OPTIONS</arg>update</command> - </cmdsynopsis> - <cmdsynopsis> - <command>gummiboot <arg choice="opt" rep="repeat">OPTIONS</arg>install</command> - </cmdsynopsis> - <cmdsynopsis> - <command>gummiboot <arg choice="opt" rep="repeat">OPTIONS</arg>remove</command> - </cmdsynopsis> - </refsynopsisdiv> - - <refsect1> - <title>Description</title> - - <para><command>gummiboot</command> checks, updates, - installs or removes the boot loader from the current - system.</para> - - <para><command>gummiboot status</command> checks and prints the - currently installed versions of the boot loader binaries and the - all current EFI boot variables.</para> - - <para><command>gummiboot update</command> updates all installed - versions of gummiboot, if the current version is newer than the - version installed in the EFI system partition. This also includes - the EFI default/fallback loader at /EFI/Boot/boot*.efi. An - gummiboot entry in the EFI boot variables is created, if there - is no current entry. A created entry will be added to the end of - the boot order list.</para> - - <para><command>gummiboot install</command> installs gummiboot into - the EFI system partition. A copy of gummiboot will be stored as - the EFI default/fallback loader at /EFI/Boot/boot*.efi. An gummiboot - entry in the EFI boot variables is created and added to the top - of the boot order list.</para> - - <para><command>gummiboot remove</command> removes all installed - versions of gummiboot from the EFI system partition, and removes - gummiboot from the EFI boot variables.</para> - - <para>If no command is passed <command>status</command> is - implied.</para> - </refsect1> - - <refsect1> - <title>Options</title> - <para>The following options are understood:</para> - - <variablelist> - <varlistentry> - <term><option>-h</option></term> - <term><option>--help</option></term> - - <listitem><para>Prints a short help - text and exits.</para></listitem> - </varlistentry> - - <varlistentry> - <term><option>--path</option></term> - <listitem><para>Path to the EFI system - partition. The default is /boot.</para></listitem> - </varlistentry> - - <varlistentry> - <term><option>--no-variables</option></term> - <listitem><para>Do not touch the EFI boot - variables.</para></listitem> - </varlistentry> - </variablelist> - </refsect1> - - <refsect1> - <title>Exit status</title> - <para>On success 0 is returned, a non-zero failure - code otherwise.</para> - </refsect1> - - <refsect1> - <title>See Also</title> - <para> - <ulink url="http://freedesktop.org/wiki/Software/gummiboot">Gummiboot wiki</ulink> - <ulink url="http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec">Boot loader specification</ulink> - <ulink url="http://www.freedesktop.org/wiki/Software/systemd/BootLoaderInterface">Systemd boot loader interface</ulink> - <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> - </para> - </refsect1> -</refentry> diff --git a/src/efi/console.c b/src/efi/console.c deleted file mode 100644 index 6206c80..0000000 --- a/src/efi/console.c +++ /dev/null @@ -1,141 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> - */ - -#include <efi.h> -#include <efilib.h> - -#include "util.h" -#include "console.h" - -#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ - { 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } } - -struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; - -typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET_EX)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This; - BOOLEAN ExtendedVerification; -); - -typedef UINT8 EFI_KEY_TOGGLE_STATE; - -typedef struct { - UINT32 KeyShiftState; - EFI_KEY_TOGGLE_STATE KeyToggleState; -} EFI_KEY_STATE; - -typedef struct { - EFI_INPUT_KEY Key; - EFI_KEY_STATE KeyState; -} EFI_KEY_DATA; - -typedef EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY_EX)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This; - EFI_KEY_DATA *KeyData; -); - -typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This; - EFI_KEY_TOGGLE_STATE *KeyToggleState; -); - -typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)( - EFI_KEY_DATA *KeyData; -); - -typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This; - EFI_KEY_DATA KeyData; - EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction; - VOID **NotifyHandle; -); - -typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This; - VOID *NotificationHandle; -); - -typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { - EFI_INPUT_RESET_EX Reset; - EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx; - EFI_EVENT WaitForKeyEx; - EFI_SET_STATE SetState; - EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify; - EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify; -} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; - -EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) { - EFI_GUID EfiSimpleTextInputExProtocolGuid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; - static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx; - static BOOLEAN checked; - UINTN index; - EFI_INPUT_KEY k; - EFI_STATUS err; - - if (!checked) { - err = LibLocateProtocol(&EfiSimpleTextInputExProtocolGuid, (VOID **)&TextInputEx); - if (EFI_ERROR(err)) - TextInputEx = NULL; - - checked = TRUE; - } - - /* wait until key is pressed */ - if (wait) { - if (TextInputEx) - uefi_call_wrapper(BS->WaitForEvent, 3, 1, &TextInputEx->WaitForKeyEx, &index); - else - uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index); - } - - if (TextInputEx) { - EFI_KEY_DATA keydata; - UINT64 keypress; - - err = uefi_call_wrapper(TextInputEx->ReadKeyStrokeEx, 2, TextInputEx, &keydata); - if (!EFI_ERROR(err)) { - UINT32 shift = 0; - - /* do not distinguish between left and right keys */ - if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) { - if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED)) - shift |= EFI_CONTROL_PRESSED; - if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED)) - shift |= EFI_ALT_PRESSED; - }; - - /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */ - keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar); - if (keypress > 0) { - *key = keypress; - return 0; - } - } - } - - /* fallback for firmware which does not support SimpleTextInputExProtocol - * - * This is also called in case ReadKeyStrokeEx did not return a key, because - * some broken firmwares offer SimpleTextInputExProtocol, but never acually - * handle any key. */ - err = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &k); - if (EFI_ERROR(err)) - return err; - - *key = KEYPRESS(0, k.ScanCode, k.UnicodeChar); - return 0; -} diff --git a/src/efi/console.h b/src/efi/console.h deleted file mode 100644 index 8c2a31a..0000000 --- a/src/efi/console.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> - */ - -#ifndef __GUMMIBOOT_CONSOLE_H -#define __GUMMIBOOT_CONSOLE_H - -#define EFI_SHIFT_STATE_VALID 0x80000000 -#define EFI_RIGHT_CONTROL_PRESSED 0x00000004 -#define EFI_LEFT_CONTROL_PRESSED 0x00000008 -#define EFI_RIGHT_ALT_PRESSED 0x00000010 -#define EFI_LEFT_ALT_PRESSED 0x00000020 - -#define EFI_CONTROL_PRESSED (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED) -#define EFI_ALT_PRESSED (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED) -#define KEYPRESS(keys, scan, uni) ((((UINT64)keys) << 32) | ((scan) << 16) | (uni)) -#define KEYCHAR(k) ((k) & 0xffff) -#define CHAR_CTRL(c) ((c) - 'a' + 1) - -EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait); -#endif diff --git a/src/efi/graphics.c b/src/efi/graphics.c deleted file mode 100644 index 11305b8..0000000 --- a/src/efi/graphics.c +++ /dev/null @@ -1,389 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> - * Copyright (C) 2013 Intel Corporation - * Authored by Joonas Lahtinen <joonas.lahtinen@linux.intel.com> - */ - -#include <efi.h> -#include <efilib.h> - -#include "util.h" -#include "graphics.h" - -EFI_STATUS graphics_mode(BOOLEAN on) { - #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ - { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } }; - - struct _EFI_CONSOLE_CONTROL_PROTOCOL; - - typedef enum { - EfiConsoleControlScreenText, - EfiConsoleControlScreenGraphics, - EfiConsoleControlScreenMaxValue, - } EFI_CONSOLE_CONTROL_SCREEN_MODE; - - typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE)( - struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, - EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, - BOOLEAN *UgaExists, - BOOLEAN *StdInLocked - ); - - typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE)( - struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, - EFI_CONSOLE_CONTROL_SCREEN_MODE Mode - ); - - typedef EFI_STATUS (EFIAPI *EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN)( - struct _EFI_CONSOLE_CONTROL_PROTOCOL *This, - CHAR16 *Password - ); - - typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL { - EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE GetMode; - EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE SetMode; - EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; - } EFI_CONSOLE_CONTROL_PROTOCOL; - - EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; - EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; - EFI_CONSOLE_CONTROL_SCREEN_MODE new; - EFI_CONSOLE_CONTROL_SCREEN_MODE current; - BOOLEAN uga_exists; - BOOLEAN stdin_locked; - EFI_STATUS err; - - err = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **)&ConsoleControl); - if (EFI_ERROR(err)) { - /* console control protocol is nonstandard and might not exist. */ - return err == EFI_NOT_FOUND ? EFI_SUCCESS : err; - } - - /* check current mode */ - err = uefi_call_wrapper(ConsoleControl->GetMode, 4, ConsoleControl, ¤t, &uga_exists, &stdin_locked); - if (EFI_ERROR(err)) - return err; - - /* do not touch the mode */ - new = on ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText; - if (new == current) - return EFI_SUCCESS; - - err = uefi_call_wrapper(ConsoleControl->SetMode, 2, ConsoleControl, new); - - /* some firmware enables the cursor when switching modes */ - uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE); - - return err; -} - -struct bmp_file { - CHAR8 signature[2]; - UINT32 size; - UINT16 reserved[2]; - UINT32 offset; -} __attribute__((packed)); - -/* we require at least BITMAPINFOHEADER, later versions are - accepted, but their features ignored */ -struct bmp_dib { - UINT32 size; - UINT32 x; - UINT32 y; - UINT16 planes; - UINT16 depth; - UINT32 compression; - UINT32 image_size; - INT32 x_pixel_meter; - INT32 y_pixel_meter; - UINT32 colors_used; - UINT32 colors_important; -} __attribute__((packed)); - -struct bmp_map { - UINT8 blue; - UINT8 green; - UINT8 red; - UINT8 reserved; -} __attribute__((packed)); - -EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib, - struct bmp_map **ret_map, UINT8 **pixmap) { - struct bmp_file *file; - struct bmp_dib *dib; - struct bmp_map *map; - UINTN row_size; - - if (size < sizeof(struct bmp_file) + sizeof(struct bmp_dib)) - return EFI_INVALID_PARAMETER; - - /* check file header */ - file = (struct bmp_file *)bmp; - if (file->signature[0] != 'B' || file->signature[1] != 'M') - return EFI_INVALID_PARAMETER; - if (file->size != size) - return EFI_INVALID_PARAMETER; - if (file->size < file->offset) - return EFI_INVALID_PARAMETER; - - /* check device-independent bitmap */ - dib = (struct bmp_dib *)(bmp + sizeof(struct bmp_file)); - if (dib->size < sizeof(struct bmp_dib)) - return EFI_UNSUPPORTED; - - switch (dib->depth) { - case 1: - case 4: - case 8: - case 24: - if (dib->compression != 0) - return EFI_UNSUPPORTED; - - break; - - case 16: - case 32: - if (dib->compression != 0 && dib->compression != 3) - return EFI_UNSUPPORTED; - - break; - - default: - return EFI_UNSUPPORTED; - } - - row_size = (((dib->depth * dib->x) + 31) / 32) * 4; - if (file->size - file->offset < dib->y * row_size) - return EFI_INVALID_PARAMETER; - if (row_size * dib->y > 64 * 1024 * 1024) - return EFI_INVALID_PARAMETER; - - /* check color table */ - map = (struct bmp_map *)(bmp + sizeof(struct bmp_file) + dib->size); - if (file->offset < sizeof(struct bmp_file) + dib->size) - return EFI_INVALID_PARAMETER; - - if (file->offset > sizeof(struct bmp_file) + dib->size) { - UINT32 map_count; - UINTN map_size; - - if (dib->colors_used) - map_count = dib->colors_used; - else { - switch (dib->depth) { - case 1: - case 4: - case 8: - map_count = 1 << dib->depth; - break; - - default: - map_count = 0; - break; - } - } - - map_size = file->offset - (sizeof(struct bmp_file) + dib->size); - if (map_size != sizeof(struct bmp_map) * map_count) - return EFI_INVALID_PARAMETER; - } - - *ret_map = map; - *ret_dib = dib; - *pixmap = bmp + file->offset; - - return EFI_SUCCESS; -} - -static VOID pixel_blend(UINT32 *dst, const UINT32 source) { - UINT32 alpha, src, src_rb, src_g, dst_rb, dst_g, rb, g; - - alpha = (source & 0xff); - - /* convert src from RGBA to XRGB */ - src = source >> 8; - - /* decompose into RB and G components */ - src_rb = (src & 0xff00ff); - src_g = (src & 0x00ff00); - - dst_rb = (*dst & 0xff00ff); - dst_g = (*dst & 0x00ff00); - - /* blend */ - rb = ((((src_rb - dst_rb) * alpha + 0x800080) >> 8) + dst_rb) & 0xff00ff; - g = ((((src_g - dst_g) * alpha + 0x008000) >> 8) + dst_g) & 0x00ff00; - - *dst = (rb | g); -} - -EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, - struct bmp_dib *dib, struct bmp_map *map, - UINT8 *pixmap) { - UINT8 *in; - UINTN y; - - /* transform and copy pixels */ - in = pixmap; - for (y = 0; y < dib->y; y++) { - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *out; - UINTN row_size; - UINTN x; - - out = &buf[(dib->y - y - 1) * dib->x]; - for (x = 0; x < dib->x; x++, in++, out++) { - switch (dib->depth) { - case 1: { - UINTN i; - - for (i = 0; i < 8 && x < dib->x; i++) { - out->Red = map[((*in) >> (7 - i)) & 1].red; - out->Green = map[((*in) >> (7 - i)) & 1].green; - out->Blue = map[((*in) >> (7 - i)) & 1].blue; - out++; - x++; - } - out--; - x--; - break; - } - - case 4: { - UINTN i; - - i = (*in) >> 4; - out->Red = map[i].red; - out->Green = map[i].green; - out->Blue = map[i].blue; - if (x < (dib->x - 1)) { - out++; - x++; - i = (*in) & 0x0f; - out->Red = map[i].red; - out->Green = map[i].green; - out->Blue = map[i].blue; - } - break; - } - - case 8: - out->Red = map[*in].red; - out->Green = map[*in].green; - out->Blue = map[*in].blue; - break; - - case 16: { - UINT16 i = *(UINT16 *) in; - - out->Red = (i & 0x7c00) >> 7; - out->Green = (i & 0x3e0) >> 2; - out->Blue = (i & 0x1f) << 3; - in += 1; - break; - } - - case 24: - out->Red = in[2]; - out->Green = in[1]; - out->Blue = in[0]; - in += 2; - break; - - case 32: { - UINT32 i = *(UINT32 *) in; - - pixel_blend((UINT32 *)out, i); - - in += 3; - break; - } - } - } - - /* add row padding; new lines always start at 32 bit boundary */ - row_size = in - pixmap; - in += ((row_size + 3) & ~3) - row_size; - } - - return EFI_SUCCESS; -} - -EFI_STATUS graphics_splash(EFI_FILE *root_dir, CHAR16 *path, - const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background) { - EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL; - UINT8 *content; - INTN len; - struct bmp_dib *dib; - struct bmp_map *map; - UINT8 *pixmap; - UINT64 blt_size; - VOID *blt = NULL; - UINTN x_pos = 0; - UINTN y_pos = 0; - EFI_STATUS err; - - err = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput); - if (EFI_ERROR(err)) - return err; - - len = file_read(root_dir, path, 0, 0, &content); - if (len < 0) - return EFI_LOAD_ERROR; - - err = bmp_parse_header(content, len, &dib, &map, &pixmap); - if (EFI_ERROR(err)) - goto err; - - if(dib->x < GraphicsOutput->Mode->Info->HorizontalResolution) - x_pos = (GraphicsOutput->Mode->Info->HorizontalResolution - dib->x) / 2; - if(dib->y < GraphicsOutput->Mode->Info->VerticalResolution) - y_pos = (GraphicsOutput->Mode->Info->VerticalResolution - dib->y) / 2; - - uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput, - (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)background, - EfiBltVideoFill, 0, 0, 0, 0, - GraphicsOutput->Mode->Info->HorizontalResolution, - GraphicsOutput->Mode->Info->VerticalResolution, 0); - - /* EFI buffer */ - blt_size = dib->x * dib->y * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL); - blt = AllocatePool(blt_size); - if (!blt) - return EFI_OUT_OF_RESOURCES; - - err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput, - blt, EfiBltVideoToBltBuffer, x_pos, y_pos, 0, 0, - dib->x, dib->y, 0); - if (EFI_ERROR(err)) - goto err; - - err = bmp_to_blt(blt, dib, map, pixmap); - if (EFI_ERROR(err)) - goto err; - - err = graphics_mode(TRUE); - if (EFI_ERROR(err)) - goto err; - - err = uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput, - blt, EfiBltBufferToVideo, 0, 0, x_pos, y_pos, - dib->x, dib->y, 0); -err: - FreePool(blt); - FreePool(content); - return err; -} diff --git a/src/efi/graphics.h b/src/efi/graphics.h deleted file mode 100644 index edec1f4..0000000 --- a/src/efi/graphics.h +++ /dev/null @@ -1,26 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> - * Copyright (C) 2013 Intel Corporation - * Authored by Joonas Lahtinen <joonas.lahtinen@linux.intel.com> - */ - -#ifndef __GUMMIBOOT_GRAPHICS_H -#define __GUMMIBOOT_GRAPHICS_H - -EFI_STATUS graphics_mode(BOOLEAN on); -EFI_STATUS graphics_splash(EFI_FILE *root_dir, CHAR16 *path, - const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background); -#endif diff --git a/src/efi/gummiboot.c b/src/efi/gummiboot.c deleted file mode 100644 index be5765c..0000000 --- a/src/efi/gummiboot.c +++ /dev/null @@ -1,2047 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * Simple UEFI boot loader which executes configured EFI images, where the - * default entry is selected by a configured pattern (glob) or an on-screen - * menu. - * - * All gummiboot code is LGPL not GPL, to stay out of politics and to give - * the freedom of copying code from programs to possible future libraries. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> - * - * "Any intelligent fool can make things bigger, more complex, and more violent." - * -- Albert Einstein - */ - -#include <efi.h> -#include <efilib.h> - -#include "util.h" -#include "console.h" -#include "graphics.h" -#include "pefile.h" -#include "linux.h" - -#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI -#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL -#endif - -#ifndef EFI_SECURITY_VIOLATION -#define EFI_SECURITY_VIOLATION EFIERR(26) -#endif - -/* magic string to find in the binary image */ -static const char __attribute__((used)) magic[] = "#### LoaderInfo: gummiboot " VERSION " ####"; - -static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; - -enum loader_type { - LOADER_UNDEFINED, - LOADER_EFI, - LOADER_LINUX -}; - -typedef struct { - CHAR16 *file; - CHAR16 *title_show; - CHAR16 *title; - CHAR16 *version; - CHAR16 *machine_id; - EFI_HANDLE *device; - enum loader_type type; - CHAR16 *loader; - CHAR16 *options; - CHAR16 *splash; - CHAR16 key; - EFI_STATUS (*call)(VOID); - BOOLEAN no_autoselect; - BOOLEAN non_unique; -} ConfigEntry; - -typedef struct { - ConfigEntry **entries; - UINTN entry_count; - INTN idx_default; - INTN idx_default_efivar; - UINTN timeout_sec; - UINTN timeout_sec_config; - INTN timeout_sec_efivar; - CHAR16 *entry_default_pattern; - CHAR16 *splash; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background; - CHAR16 *entry_oneshot; - CHAR16 *options_edit; - CHAR16 *entries_auto; - BOOLEAN no_editor; -} Config; - -static VOID cursor_left(UINTN *cursor, UINTN *first) -{ - if ((*cursor) > 0) - (*cursor)--; - else if ((*first) > 0) - (*first)--; -} - -static VOID cursor_right(UINTN *cursor, UINTN *first, UINTN x_max, UINTN len) -{ - if ((*cursor)+1 < x_max) - (*cursor)++; - else if ((*first) + (*cursor) < len) - (*first)++; -} - -static BOOLEAN line_edit(CHAR16 *line_in, CHAR16 **line_out, UINTN x_max, UINTN y_pos) { - CHAR16 *line; - UINTN size; - UINTN len; - UINTN first; - CHAR16 *print; - UINTN cursor; - UINTN clear; - BOOLEAN exit; - BOOLEAN enter; - - if (!line_in) - line_in = L""; - size = StrLen(line_in) + 1024; - line = AllocatePool(size * sizeof(CHAR16)); - StrCpy(line, line_in); - len = StrLen(line); - print = AllocatePool((x_max+1) * sizeof(CHAR16)); - - uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, TRUE); - - first = 0; - cursor = 0; - clear = 0; - enter = FALSE; - exit = FALSE; - while (!exit) { - EFI_STATUS err; - UINT64 key; - UINTN i; - - i = len - first; - if (i >= x_max-1) - i = x_max-1; - CopyMem(print, line + first, i * sizeof(CHAR16)); - while (clear > 0 && i < x_max-1) { - clear--; - print[i++] = ' '; - } - print[i] = '\0'; - - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_pos); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, print); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos); - - err = console_key_read(&key, TRUE); - if (EFI_ERROR(err)) - continue; - - switch (key) { - case KEYPRESS(0, SCAN_ESC, 0): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'c'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'g'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('c')): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('g')): - exit = TRUE; - break; - - case KEYPRESS(0, SCAN_HOME, 0): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'a'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('a')): - /* beginning-of-line */ - cursor = 0; - first = 0; - continue; - - case KEYPRESS(0, SCAN_END, 0): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'e'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('e')): - /* end-of-line */ - cursor = len - first; - if (cursor+1 >= x_max) { - cursor = x_max-1; - first = len - (x_max-1); - } - continue; - - case KEYPRESS(0, SCAN_DOWN, 0): - case KEYPRESS(EFI_ALT_PRESSED, 0, 'f'): - case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_RIGHT, 0): - /* forward-word */ - while (line[first + cursor] && line[first + cursor] == ' ') - cursor_right(&cursor, &first, x_max, len); - while (line[first + cursor] && line[first + cursor] != ' ') - cursor_right(&cursor, &first, x_max, len); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos); - continue; - - case KEYPRESS(0, SCAN_UP, 0): - case KEYPRESS(EFI_ALT_PRESSED, 0, 'b'): - case KEYPRESS(EFI_CONTROL_PRESSED, SCAN_LEFT, 0): - /* backward-word */ - if ((first + cursor) > 0 && line[first + cursor-1] == ' ') { - cursor_left(&cursor, &first); - while ((first + cursor) > 0 && line[first + cursor] == ' ') - cursor_left(&cursor, &first); - } - while ((first + cursor) > 0 && line[first + cursor-1] != ' ') - cursor_left(&cursor, &first); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos); - continue; - - case KEYPRESS(0, SCAN_RIGHT, 0): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'f'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('f')): - /* forward-char */ - if (first + cursor == len) - continue; - cursor_right(&cursor, &first, x_max, len); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos); - continue; - - case KEYPRESS(0, SCAN_LEFT, 0): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'b'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('b')): - /* backward-char */ - cursor_left(&cursor, &first); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos); - continue; - - case KEYPRESS(EFI_ALT_PRESSED, 0, 'd'): - /* kill-word */ - clear = 0; - for (i = first + cursor; i < len && line[i] == ' '; i++) - clear++; - for (; i < len && line[i] != ' '; i++) - clear++; - - for (i = first + cursor; i + clear < len; i++) - line[i] = line[i + clear]; - len -= clear; - line[len] = '\0'; - continue; - - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'w'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('w')): - case KEYPRESS(EFI_ALT_PRESSED, 0, CHAR_BACKSPACE): - /* backward-kill-word */ - clear = 0; - if ((first + cursor) > 0 && line[first + cursor-1] == ' ') { - cursor_left(&cursor, &first); - clear++; - while ((first + cursor) > 0 && line[first + cursor] == ' ') { - cursor_left(&cursor, &first); - clear++; - } - } - while ((first + cursor) > 0 && line[first + cursor-1] != ' ') { - cursor_left(&cursor, &first); - clear++; - } - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos); - - for (i = first + cursor; i + clear < len; i++) - line[i] = line[i + clear]; - len -= clear; - line[len] = '\0'; - continue; - - case KEYPRESS(0, SCAN_DELETE, 0): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'd'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('d')): - if (len == 0) - continue; - if (first + cursor == len) - continue; - for (i = first + cursor; i < len; i++) - line[i] = line[i+1]; - clear = 1; - len--; - continue; - - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'k'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('k')): - /* kill-line */ - line[first + cursor] = '\0'; - clear = len - (first + cursor); - len = first + cursor; - continue; - - case KEYPRESS(0, 0, CHAR_LINEFEED): - case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN): - if (StrCmp(line, line_in) != 0) { - *line_out = line; - line = NULL; - } - enter = TRUE; - exit = TRUE; - break; - - case KEYPRESS(0, 0, CHAR_BACKSPACE): - if (len == 0) - continue; - if (first == 0 && cursor == 0) - continue; - for (i = first + cursor-1; i < len; i++) - line[i] = line[i+1]; - clear = 1; - len--; - if (cursor > 0) - cursor--; - if (cursor > 0 || first == 0) - continue; - /* show full line if it fits */ - if (len < x_max) { - cursor = first; - first = 0; - continue; - } - /* jump left to see what we delete */ - if (first > 10) { - first -= 10; - cursor = 10; - } else { - cursor = first; - first = 0; - } - continue; - - case KEYPRESS(0, 0, ' ') ... KEYPRESS(0, 0, '~'): - case KEYPRESS(0, 0, 0x80) ... KEYPRESS(0, 0, 0xffff): - if (len+1 == size) - continue; - for (i = len; i > first + cursor; i--) - line[i] = line[i-1]; - line[first + cursor] = KEYCHAR(key); - len++; - line[len] = '\0'; - if (cursor+1 < x_max) - cursor++; - else if (first + cursor < len) - first++; - continue; - } - } - - uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE); - FreePool(print); - FreePool(line); - return enter; -} - -static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) { - UINTN i; - - if (key == 0) - return -1; - - /* select entry by number key */ - if (key >= '1' && key <= '9') { - i = key - '0'; - if (i > config->entry_count) - i = config->entry_count; - return i-1; - } - - /* find matching key in config entries */ - for (i = start; i < config->entry_count; i++) - if (config->entries[i]->key == key) - return i; - - for (i = 0; i < start; i++) - if (config->entries[i]->key == key) - return i; - - return -1; -} - -static VOID print_status(Config *config, EFI_FILE *root_dir, CHAR16 *loaded_image_path) { - UINT64 key; - UINTN i; - CHAR16 *s; - CHAR8 *b; - UINTN x; - UINTN y; - UINTN size; - EFI_STATUS err; - UINTN color = 0; - const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *pixel = config->background; - - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - - /* show splash and wait for key */ - for (;;) { - static const EFI_GRAPHICS_OUTPUT_BLT_PIXEL colors[] = { - { .Red = 0xff, .Green = 0xff, .Blue = 0xff }, - { .Red = 0xc0, .Green = 0xc0, .Blue = 0xc0 }, - { .Red = 0xff, .Green = 0, .Blue = 0 }, - { .Red = 0, .Green = 0xff, .Blue = 0 }, - { .Red = 0, .Green = 0, .Blue = 0xff }, - { .Red = 0, .Green = 0, .Blue = 0 }, - }; - - err = EFI_NOT_FOUND; - if (config->splash) - err = graphics_splash(root_dir, config->splash, pixel); - if (EFI_ERROR(err)) - err = graphics_splash(root_dir, L"\\EFI\\gummiboot\\splash.bmp", pixel); - if (EFI_ERROR(err)) - break; - - /* 'b' rotates through background colors */ - console_key_read(&key, TRUE); - if (key == KEYPRESS(0, 0, 'b')) { - pixel = &colors[color++]; - if (color == ELEMENTSOF(colors)) - color = 0; - - continue; - } - - graphics_mode(FALSE); - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - break; - } - - Print(L"gummiboot version: " VERSION "\n"); - Print(L"gummiboot architecture: " MACHINE_TYPE_NAME "\n"); - Print(L"loaded image: %s\n", loaded_image_path); - Print(L"UEFI specification: %d.%02d\n", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); - Print(L"firmware vendor: %s\n", ST->FirmwareVendor); - Print(L"firmware version: %d.%02d\n", ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - - if (uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x, &y) == EFI_SUCCESS) - Print(L"console size: %d x %d\n", x, y); - - if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) { - Print(L"SecureBoot: %s\n", yes_no(*b > 0)); - FreePool(b); - } - - if (efivar_get_raw(&global_guid, L"SetupMode", &b, &size) == EFI_SUCCESS) { - Print(L"SetupMode: %s\n", *b > 0 ? L"setup" : L"user"); - FreePool(b); - } - - if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) { - Print(L"OsIndicationsSupported: %d\n", (UINT64)*b); - FreePool(b); - } - Print(L"\n"); - - Print(L"timeout: %d\n", config->timeout_sec); - if (config->timeout_sec_efivar >= 0) - Print(L"timeout (EFI var): %d\n", config->timeout_sec_efivar); - Print(L"timeout (config): %d\n", config->timeout_sec_config); - if (config->entry_default_pattern) - Print(L"default pattern: '%s'\n", config->entry_default_pattern); - if (config->splash) - Print(L"splash '%s'\n", config->splash); - if (config->background) - Print(L"background '#%02x%02x%02x'\n", - config->background->Red, - config->background->Green, - config->background->Blue); - Print(L"editor: %s\n", yes_no(!config->no_editor)); - Print(L"\n"); - - Print(L"config entry count: %d\n", config->entry_count); - Print(L"entry selected idx: %d\n", config->idx_default); - if (config->idx_default_efivar >= 0) - Print(L"entry EFI var idx: %d\n", config->idx_default_efivar); - Print(L"\n"); - - if (efivar_get_int(L"LoaderConfigTimeout", &i) == EFI_SUCCESS) - Print(L"LoaderConfigTimeout: %d\n", i); - if (config->entry_oneshot) - Print(L"LoaderEntryOneShot: %s\n", config->entry_oneshot); - if (efivar_get(L"LoaderDeviceIdentifier", &s) == EFI_SUCCESS) { - Print(L"LoaderDeviceIdentifier: %s\n", s); - FreePool(s); - } - if (efivar_get(L"LoaderDevicePartUUID", &s) == EFI_SUCCESS) { - Print(L"LoaderDevicePartUUID: %s\n", s); - FreePool(s); - } - if (efivar_get(L"LoaderEntryDefault", &s) == EFI_SUCCESS) { - Print(L"LoaderEntryDefault: %s\n", s); - FreePool(s); - } - - Print(L"\n--- press key ---\n\n"); - console_key_read(&key, TRUE); - - for (i = 0; i < config->entry_count; i++) { - ConfigEntry *entry; - - if (key == KEYPRESS(0, SCAN_ESC, 0) || key == KEYPRESS(0, 0, 'q')) - break; - - entry = config->entries[i]; - - if (entry->splash) { - err = graphics_splash(root_dir, entry->splash, config->background); - if (!EFI_ERROR(err)) { - console_key_read(&key, TRUE); - graphics_mode(FALSE); - } - } - - Print(L"config entry: %d/%d\n", i+1, config->entry_count); - if (entry->file) - Print(L"file '%s'\n", entry->file); - Print(L"title show '%s'\n", entry->title_show); - if (entry->title) - Print(L"title '%s'\n", entry->title); - if (entry->version) - Print(L"version '%s'\n", entry->version); - if (entry->machine_id) - Print(L"machine-id '%s'\n", entry->machine_id); - if (entry->device) { - EFI_DEVICE_PATH *device_path; - CHAR16 *str; - - device_path = DevicePathFromHandle(entry->device); - if (device_path) { - str = DevicePathToStr(device_path); - Print(L"device handle '%s'\n", str); - FreePool(str); - } - } - if (entry->loader) - Print(L"loader '%s'\n", entry->loader); - if (entry->options) - Print(L"options '%s'\n", entry->options); - if (entry->splash) - Print(L"splash '%s'\n", entry->splash); - Print(L"auto-select %s\n", yes_no(!entry->no_autoselect)); - if (entry->call) - Print(L"internal call yes\n"); - - Print(L"\n--- press key ---\n\n"); - console_key_read(&key, TRUE); - } - - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); -} - -static BOOLEAN menu_run(Config *config, ConfigEntry **chosen_entry, EFI_FILE *root_dir, CHAR16 *loaded_image_path) { - EFI_STATUS err; - UINTN visible_max; - UINTN idx_highlight; - UINTN idx_highlight_prev; - UINTN idx_first; - UINTN idx_last; - BOOLEAN refresh; - BOOLEAN highlight; - UINTN i; - UINTN line_width; - CHAR16 **lines; - UINTN x_start; - UINTN y_start; - UINTN x_max; - UINTN y_max; - CHAR16 *status; - CHAR16 *clearline; - INTN timeout_remain; - INT16 idx; - BOOLEAN exit = FALSE; - BOOLEAN run = TRUE; - BOOLEAN wait = FALSE; - - graphics_mode(FALSE); - uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE); - uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE); - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); - - /* draw a single character to make ClearScreen work on some firmware */ - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L" "); - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - - err = uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x_max, &y_max); - if (EFI_ERROR(err)) { - x_max = 80; - y_max = 25; - } - - /* we check 10 times per second for a keystroke */ - if (config->timeout_sec > 0) - timeout_remain = config->timeout_sec * 10; - else - timeout_remain = -1; - - idx_highlight = config->idx_default; - idx_highlight_prev = 0; - - visible_max = y_max - 2; - - if ((UINTN)config->idx_default >= visible_max) - idx_first = config->idx_default-1; - else - idx_first = 0; - - idx_last = idx_first + visible_max-1; - - refresh = TRUE; - highlight = FALSE; - - /* length of the longest entry */ - line_width = 5; - for (i = 0; i < config->entry_count; i++) { - UINTN entry_len; - - entry_len = StrLen(config->entries[i]->title_show); - if (line_width < entry_len) - line_width = entry_len; - } - if (line_width > x_max-6) - line_width = x_max-6; - - /* offsets to center the entries on the screen */ - x_start = (x_max - (line_width)) / 2; - if (config->entry_count < visible_max) - y_start = ((visible_max - config->entry_count) / 2) + 1; - else - y_start = 0; - - /* menu entries title lines */ - lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count); - for (i = 0; i < config->entry_count; i++) { - UINTN j, k; - - lines[i] = AllocatePool(((x_max+1) * sizeof(CHAR16))); - for (j = 0; j < x_start; j++) - lines[i][j] = ' '; - - for (k = 0; config->entries[i]->title_show[k] != '\0' && j < x_max; j++, k++) - lines[i][j] = config->entries[i]->title_show[k]; - - for (; j < x_max; j++) - lines[i][j] = ' '; - lines[i][x_max] = '\0'; - } - - status = NULL; - clearline = AllocatePool((x_max+1) * sizeof(CHAR16)); - for (i = 0; i < x_max; i++) - clearline[i] = ' '; - clearline[i] = 0; - - while (!exit) { - UINT64 key; - - if (refresh) { - for (i = 0; i < config->entry_count; i++) { - if (i < idx_first || i > idx_last) - continue; - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + i - idx_first); - if (i == idx_highlight) - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, - EFI_BLACK|EFI_BACKGROUND_LIGHTGRAY); - else - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, - EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[i]); - if ((INTN)i == config->idx_default_efivar) { - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + i - idx_first); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>"); - } - } - refresh = FALSE; - } else if (highlight) { - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + idx_highlight_prev - idx_first); - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[idx_highlight_prev]); - if ((INTN)idx_highlight_prev == config->idx_default_efivar) { - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + idx_highlight_prev - idx_first); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>"); - } - - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + idx_highlight - idx_first); - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_BLACK|EFI_BACKGROUND_LIGHTGRAY); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, lines[idx_highlight]); - if ((INTN)idx_highlight == config->idx_default_efivar) { - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, x_start-3, y_start + idx_highlight - idx_first); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, L"=>"); - } - highlight = FALSE; - } - - if (timeout_remain > 0) { - FreePool(status); - status = PoolPrint(L"Boot in %d sec.", (timeout_remain + 5) / 10); - } - - /* print status at last line of screen */ - if (status) { - UINTN len; - UINTN x; - - /* center line */ - len = StrLen(status); - if (len < x_max) - x = (x_max - len) / 2; - else - x = 0; - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline + (x_max - x)); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, status); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len); - } - - err = console_key_read(&key, wait); - if (EFI_ERROR(err)) { - /* timeout reached */ - if (timeout_remain == 0) { - exit = TRUE; - break; - } - - /* sleep and update status */ - if (timeout_remain > 0) { - uefi_call_wrapper(BS->Stall, 1, 100 * 1000); - timeout_remain--; - continue; - } - - /* timeout disabled, wait for next key */ - wait = TRUE; - continue; - } - - timeout_remain = -1; - - /* clear status after keystroke */ - if (status) { - FreePool(status); - status = NULL; - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1); - } - - idx_highlight_prev = idx_highlight; - - switch (key) { - case KEYPRESS(0, SCAN_UP, 0): - case KEYPRESS(0, 0, 'k'): - if (idx_highlight > 0) - idx_highlight--; - break; - - case KEYPRESS(0, SCAN_DOWN, 0): - case KEYPRESS(0, 0, 'j'): - if (idx_highlight < config->entry_count-1) - idx_highlight++; - break; - - case KEYPRESS(0, SCAN_HOME, 0): - case KEYPRESS(EFI_ALT_PRESSED, 0, '<'): - if (idx_highlight > 0) { - refresh = TRUE; - idx_highlight = 0; - } - break; - - case KEYPRESS(0, SCAN_END, 0): - case KEYPRESS(EFI_ALT_PRESSED, 0, '>'): - if (idx_highlight < config->entry_count-1) { - refresh = TRUE; - idx_highlight = config->entry_count-1; - } - break; - - case KEYPRESS(0, SCAN_PAGE_UP, 0): - if (idx_highlight > visible_max) - idx_highlight -= visible_max; - else - idx_highlight = 0; - break; - - case KEYPRESS(0, SCAN_PAGE_DOWN, 0): - idx_highlight += visible_max; - if (idx_highlight > config->entry_count-1) - idx_highlight = config->entry_count-1; - break; - - case KEYPRESS(0, 0, CHAR_LINEFEED): - case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN): - exit = TRUE; - break; - - case KEYPRESS(0, SCAN_F1, 0): - case KEYPRESS(0, 0, 'h'): - case KEYPRESS(0, 0, '?'): - status = StrDuplicate(L"(d)efault, (t/T)timeout, (e)dit, (v)ersion (Q)uit (P)rint (h)elp"); - break; - - case KEYPRESS(0, 0, 'Q'): - exit = TRUE; - run = FALSE; - break; - - case KEYPRESS(0, 0, 'd'): - if (config->idx_default_efivar != (INTN)idx_highlight) { - /* store the selected entry in a persistent EFI variable */ - efivar_set(L"LoaderEntryDefault", config->entries[idx_highlight]->file, TRUE); - config->idx_default_efivar = idx_highlight; - status = StrDuplicate(L"Default boot entry selected."); - } else { - /* clear the default entry EFI variable */ - efivar_set(L"LoaderEntryDefault", NULL, TRUE); - config->idx_default_efivar = -1; - status = StrDuplicate(L"Default boot entry cleared."); - } - refresh = TRUE; - break; - - case KEYPRESS(0, 0, '-'): - case KEYPRESS(0, 0, 'T'): - if (config->timeout_sec_efivar > 0) { - config->timeout_sec_efivar--; - efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE); - if (config->timeout_sec_efivar > 0) - status = PoolPrint(L"Menu timeout set to %d sec.", config->timeout_sec_efivar); - else - status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu."); - } else if (config->timeout_sec_efivar <= 0){ - config->timeout_sec_efivar = -1; - efivar_set(L"LoaderConfigTimeout", NULL, TRUE); - if (config->timeout_sec_config > 0) - status = PoolPrint(L"Menu timeout of %d sec is defined by configuration file.", - config->timeout_sec_config); - else - status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu."); - } - break; - - case KEYPRESS(0, 0, '+'): - case KEYPRESS(0, 0, 't'): - if (config->timeout_sec_efivar == -1 && config->timeout_sec_config == 0) - config->timeout_sec_efivar++; - config->timeout_sec_efivar++; - efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE); - if (config->timeout_sec_efivar > 0) - status = PoolPrint(L"Menu timeout set to %d sec.", - config->timeout_sec_efivar); - else - status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu."); - break; - - case KEYPRESS(0, 0, 'e'): - /* only the options of configured entries can be edited */ - if (config->no_editor || config->entries[idx_highlight]->type == LOADER_UNDEFINED) - break; - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1); - if (line_edit(config->entries[idx_highlight]->options, &config->options_edit, x_max-1, y_max-1)) - exit = TRUE; - uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_max-1); - uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1); - break; - - case KEYPRESS(0, 0, 'v'): - status = PoolPrint(L"gummiboot " VERSION " (" MACHINE_TYPE_NAME "), UEFI Specification %d.%02d, Vendor %s %d.%02d", - ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff, - ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - break; - - case KEYPRESS(0, 0, 'P'): - print_status(config, root_dir, loaded_image_path); - refresh = TRUE; - break; - - case KEYPRESS(EFI_CONTROL_PRESSED, 0, 'l'): - case KEYPRESS(EFI_CONTROL_PRESSED, 0, CHAR_CTRL('l')): - refresh = TRUE; - break; - - default: - /* jump with a hotkey directly to a matching entry */ - idx = entry_lookup_key(config, idx_highlight+1, KEYCHAR(key)); - if (idx < 0) - break; - idx_highlight = idx; - refresh = TRUE; - } - - if (idx_highlight > idx_last) { - idx_last = idx_highlight; - idx_first = 1 + idx_highlight - visible_max; - refresh = TRUE; - } - if (idx_highlight < idx_first) { - idx_first = idx_highlight; - idx_last = idx_highlight + visible_max-1; - refresh = TRUE; - } - - idx_last = idx_first + visible_max-1; - - if (!refresh && idx_highlight != idx_highlight_prev) - highlight = TRUE; - } - - *chosen_entry = config->entries[idx_highlight]; - - for (i = 0; i < config->entry_count; i++) - FreePool(lines[i]); - FreePool(lines); - FreePool(clearline); - - uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_WHITE|EFI_BACKGROUND_BLACK); - uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - return run; -} - -static VOID config_add_entry(Config *config, ConfigEntry *entry) { - if ((config->entry_count & 15) == 0) { - UINTN i; - - i = config->entry_count + 16; - if (config->entry_count == 0) - config->entries = AllocatePool(sizeof(VOID *) * i); - else - config->entries = ReallocatePool(config->entries, - sizeof(VOID *) * config->entry_count, sizeof(VOID *) * i); - } - config->entries[config->entry_count++] = entry; -} - -static VOID config_entry_free(ConfigEntry *entry) { - FreePool(entry->title_show); - FreePool(entry->title); - FreePool(entry->machine_id); - FreePool(entry->loader); - FreePool(entry->options); -} - -static BOOLEAN is_digit(CHAR16 c) -{ - return (c >= '0') && (c <= '9'); -} - -static UINTN c_order(CHAR16 c) -{ - if (c == '\0') - return 0; - if (is_digit(c)) - return 0; - else if ((c >= 'a') && (c <= 'z')) - return c; - else - return c + 0x10000; -} - -static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) -{ - CHAR16 *os1 = s1; - CHAR16 *os2 = s2; - - while (*s1 || *s2) { - INTN first; - - while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) { - INTN order; - - order = c_order(*s1) - c_order(*s2); - if (order) - return order; - s1++; - s2++; - } - - while (*s1 == '0') - s1++; - while (*s2 == '0') - s2++; - - first = 0; - while (is_digit(*s1) && is_digit(*s2)) { - if (first == 0) - first = *s1 - *s2; - s1++; - s2++; - } - - if (is_digit(*s1)) - return 1; - if (is_digit(*s2)) - return -1; - - if (first) - return first; - } - - return StrCmp(os1, os2); -} - -static CHAR8 *line_get_key_value(CHAR8 *content, CHAR8 *sep, UINTN *pos, CHAR8 **key_ret, CHAR8 **value_ret) { - CHAR8 *line; - UINTN linelen; - CHAR8 *value; - -skip: - line = content + *pos; - if (*line == '\0') - return NULL; - - linelen = 0; - while (line[linelen] && !strchra((CHAR8 *)"\n\r", line[linelen])) - linelen++; - - /* move pos to next line */ - *pos += linelen; - if (content[*pos]) - (*pos)++; - - /* empty line */ - if (linelen == 0) - goto skip; - - /* terminate line */ - line[linelen] = '\0'; - - /* remove leading whitespace */ - while (strchra((CHAR8 *)" \t", *line)) { - line++; - linelen--; - } - - /* remove trailing whitespace */ - while (linelen > 0 && strchra(sep, line[linelen-1])) - linelen--; - line[linelen] = '\0'; - - if (*line == '#') - goto skip; - - /* split key/value */ - value = line; - while (*value && !strchra(sep, *value)) - value++; - if (*value == '\0') - goto skip; - *value = '\0'; - value++; - while (*value && strchra(sep, *value)) - value++; - - /* unquote */ - if (value[0] == '\"' && line[linelen-1] == '\"') { - value++; - line[linelen-1] = '\0'; - } - - *key_ret = line; - *value_ret = value; - return line; -} - -static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) { - CHAR8 *line; - UINTN pos = 0; - CHAR8 *key, *value; - - line = content; - while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) { - if (strcmpa((CHAR8 *)"timeout", key) == 0) { - CHAR16 *s; - - s = stra_to_str(value); - config->timeout_sec_config = Atoi(s); - config->timeout_sec = config->timeout_sec_config; - FreePool(s); - continue; - } - - if (strcmpa((CHAR8 *)"default", key) == 0) { - FreePool(config->entry_default_pattern); - config->entry_default_pattern = stra_to_str(value); - StrLwr(config->entry_default_pattern); - continue; - } - - if (strcmpa((CHAR8 *)"splash", key) == 0) { - FreePool(config->splash); - config->splash = stra_to_path(value); - continue; - } - - if (strcmpa((CHAR8 *)"background", key) == 0) { - CHAR16 c[3]; - - /* accept #RRGGBB hex notation */ - if (value[0] != '#') - continue; - if (value[7] != '\0') - continue; - - FreePool(config->background); - config->background = AllocateZeroPool(sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); - if (!config->background) - continue; - - c[0] = value[1]; - c[1] = value[2]; - c[2] = '\0'; - config->background->Red = xtoi(c); - - c[0] = value[3]; - c[1] = value[4]; - config->background->Green = xtoi(c); - - c[0] = value[5]; - c[1] = value[6]; - config->background->Blue = xtoi(c); - continue; - } - - if (strcmpa((CHAR8 *)"editor", key) == 0) { - BOOLEAN on; - - if (EFI_ERROR(parse_boolean(value, &on))) - continue; - config->no_editor = !on; - } - } -} - -static VOID config_entry_add_from_file(Config *config, EFI_HANDLE *device, CHAR16 *file, CHAR8 *content, CHAR16 *loaded_image_path) { - ConfigEntry *entry; - CHAR8 *line; - UINTN pos = 0; - CHAR8 *key, *value; - UINTN len; - CHAR16 *initrd = NULL; - - entry = AllocateZeroPool(sizeof(ConfigEntry)); - - line = content; - while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) { - if (strcmpa((CHAR8 *)"title", key) == 0) { - FreePool(entry->title); - entry->title = stra_to_str(value); - continue; - } - - if (strcmpa((CHAR8 *)"version", key) == 0) { - FreePool(entry->version); - entry->version = stra_to_str(value); - continue; - } - - if (strcmpa((CHAR8 *)"machine-id", key) == 0) { - FreePool(entry->machine_id); - entry->machine_id = stra_to_str(value); - continue; - } - - if (strcmpa((CHAR8 *)"linux", key) == 0) { - FreePool(entry->loader); - entry->type = LOADER_LINUX; - entry->loader = stra_to_path(value); - entry->key = 'l'; - continue; - } - - if (strcmpa((CHAR8 *)"efi", key) == 0) { - entry->type = LOADER_EFI; - FreePool(entry->loader); - entry->loader = stra_to_path(value); - - /* do not add an entry for ourselves */ - if (StriCmp(entry->loader, loaded_image_path) == 0) { - entry->type = LOADER_UNDEFINED; - break; - } - continue; - } - - if (strcmpa((CHAR8 *)"architecture", key) == 0) { - /* do not add an entry for an EFI image of architecture not matching with that of the gummiboot image */ - if (strcmpa((CHAR8 *)MACHINE_TYPE_NAME, value) != 0) { - entry->type = LOADER_UNDEFINED; - break; - } - continue; - } - - if (strcmpa((CHAR8 *)"initrd", key) == 0) { - CHAR16 *new; - - new = stra_to_path(value); - if (initrd) { - CHAR16 *s; - - s = PoolPrint(L"%s initrd=%s", initrd, new); - FreePool(initrd); - initrd = s; - } else - initrd = PoolPrint(L"initrd=%s", new); - FreePool(new); - continue; - } - - if (strcmpa((CHAR8 *)"options", key) == 0) { - CHAR16 *new; - - new = stra_to_str(value); - if (entry->options) { - CHAR16 *s; - - s = PoolPrint(L"%s %s", entry->options, new); - FreePool(entry->options); - entry->options = s; - } else { - entry->options = new; - new = NULL; - } - FreePool(new); - continue; - } - - if (strcmpa((CHAR8 *)"splash", key) == 0) { - FreePool(entry->splash); - entry->splash = stra_to_path(value); - continue; - } - } - - if (entry->type == LOADER_UNDEFINED) { - config_entry_free(entry); - FreePool(initrd); - FreePool(entry); - return; - } - - /* add initrd= to options */ - if (entry->type == LOADER_LINUX && initrd) { - if (entry->options) { - CHAR16 *s; - - s = PoolPrint(L"%s %s", initrd, entry->options); - FreePool(entry->options); - entry->options = s; - } else { - entry->options = initrd; - initrd = NULL; - } - } - FreePool(initrd); - - if (entry->machine_id) { - CHAR16 *var; - - /* append additional options from EFI variables for this machine-id */ - var = PoolPrint(L"LoaderEntryOptions-%s", entry->machine_id); - if (var) { - CHAR16 *s; - - if (efivar_get(var, &s) == EFI_SUCCESS) { - if (entry->options) { - CHAR16 *s2; - - s2 = PoolPrint(L"%s %s", entry->options, s); - FreePool(entry->options); - entry->options = s2; - } else - entry->options = s; - } - FreePool(var); - } - - var = PoolPrint(L"LoaderEntryOptionsOneShot-%s", entry->machine_id); - if (var) { - CHAR16 *s; - - if (efivar_get(var, &s) == EFI_SUCCESS) { - if (entry->options) { - CHAR16 *s2; - - s2 = PoolPrint(L"%s %s", entry->options, s); - FreePool(entry->options); - entry->options = s2; - } else - entry->options = s; - efivar_set(var, NULL, TRUE); - } - FreePool(var); - } - } - - entry->device = device; - entry->file = StrDuplicate(file); - len = StrLen(entry->file); - /* remove ".conf" */ - if (len > 5) - entry->file[len - 5] = '\0'; - StrLwr(entry->file); - - config_add_entry(config, entry); -} - -static VOID config_load(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path) { - EFI_FILE_HANDLE entries_dir; - EFI_STATUS err; - CHAR8 *content = NULL; - UINTN sec; - UINTN len; - UINTN i; - - len = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content); - if (len > 0) - config_defaults_load_from_file(config, content); - FreePool(content); - - err = efivar_get_int(L"LoaderConfigTimeout", &sec); - if (!EFI_ERROR(err)) { - config->timeout_sec_efivar = sec; - config->timeout_sec = sec; - } else - config->timeout_sec_efivar = -1; - - err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL); - if (!EFI_ERROR(err)) { - for (;;) { - CHAR16 buf[256]; - UINTN bufsize; - EFI_FILE_INFO *f; - CHAR8 *content = NULL; - UINTN len; - - bufsize = sizeof(buf); - err = uefi_call_wrapper(entries_dir->Read, 3, entries_dir, &bufsize, buf); - if (bufsize == 0 || EFI_ERROR(err)) - break; - - f = (EFI_FILE_INFO *) buf; - if (f->FileName[0] == '.') - continue; - if (f->Attribute & EFI_FILE_DIRECTORY) - continue; - len = StrLen(f->FileName); - if (len < 6) - continue; - if (StriCmp(f->FileName + len - 5, L".conf") != 0) - continue; - - len = file_read(entries_dir, f->FileName, 0, 0, &content); - if (len > 0) - config_entry_add_from_file(config, device, f->FileName, content, loaded_image_path); - FreePool(content); - } - uefi_call_wrapper(entries_dir->Close, 1, entries_dir); - } - - /* sort entries after version number */ - for (i = 1; i < config->entry_count; i++) { - BOOLEAN more; - UINTN k; - - more = FALSE; - for (k = 0; k < config->entry_count - i; k++) { - ConfigEntry *entry; - - if (str_verscmp(config->entries[k]->file, config->entries[k+1]->file) <= 0) - continue; - entry = config->entries[k]; - config->entries[k] = config->entries[k+1]; - config->entries[k+1] = entry; - more = TRUE; - } - if (!more) - break; - } -} - -static VOID config_default_entry_select(Config *config) { - CHAR16 *var; - EFI_STATUS err; - UINTN i; - - /* - * The EFI variable to specify a boot entry for the next, and only the - * next reboot. The variable is always cleared directly after it is read. - */ - err = efivar_get(L"LoaderEntryOneShot", &var); - if (!EFI_ERROR(err)) { - BOOLEAN found = FALSE; - - for (i = 0; i < config->entry_count; i++) { - if (StrCmp(config->entries[i]->file, var) == 0) { - config->idx_default = i; - found = TRUE; - break; - } - } - - config->entry_oneshot = StrDuplicate(var); - efivar_set(L"LoaderEntryOneShot", NULL, TRUE); - FreePool(var); - if (found) - return; - } - - /* - * The EFI variable to select the default boot entry overrides the - * configured pattern. The variable can be set and cleared by pressing - * the 'd' key in the loader selection menu, the entry is marked with - * an '*'. - */ - err = efivar_get(L"LoaderEntryDefault", &var); - if (!EFI_ERROR(err)) { - BOOLEAN found = FALSE; - - for (i = 0; i < config->entry_count; i++) { - if (StrCmp(config->entries[i]->file, var) == 0) { - config->idx_default = i; - config->idx_default_efivar = i; - found = TRUE; - break; - } - } - FreePool(var); - if (found) - return; - } - config->idx_default_efivar = -1; - - if (config->entry_count == 0) - return; - - /* - * Match the pattern from the end of the list to the start, find last - * entry (largest number) matching the given pattern. - */ - if (config->entry_default_pattern) { - i = config->entry_count; - while (i--) { - if (config->entries[i]->no_autoselect) - continue; - if (MetaiMatch(config->entries[i]->file, config->entry_default_pattern)) { - config->idx_default = i; - return; - } - } - } - - /* select the last suitable entry */ - i = config->entry_count; - while (i--) { - if (config->entries[i]->no_autoselect) - continue; - config->idx_default = i; - return; - } - - /* no entry found */ - config->idx_default = -1; -} - -/* generate a unique title, avoiding non-distinguishable menu entries */ -static VOID config_title_generate(Config *config) { - UINTN i, k; - BOOLEAN unique; - - /* set title */ - for (i = 0; i < config->entry_count; i++) { - CHAR16 *title; - - FreePool(config->entries[i]->title_show); - title = config->entries[i]->title; - if (!title) - title = config->entries[i]->file; - config->entries[i]->title_show = StrDuplicate(title); - } - - unique = TRUE; - for (i = 0; i < config->entry_count; i++) { - for (k = 0; k < config->entry_count; k++) { - if (i == k) - continue; - if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0) - continue; - - unique = FALSE; - config->entries[i]->non_unique = TRUE; - config->entries[k]->non_unique = TRUE; - } - } - if (unique) - return; - - /* add version to non-unique titles */ - for (i = 0; i < config->entry_count; i++) { - CHAR16 *s; - - if (!config->entries[i]->non_unique) - continue; - if (!config->entries[i]->version) - continue; - - s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, config->entries[i]->version); - FreePool(config->entries[i]->title_show); - config->entries[i]->title_show = s; - config->entries[i]->non_unique = FALSE; - } - - unique = TRUE; - for (i = 0; i < config->entry_count; i++) { - for (k = 0; k < config->entry_count; k++) { - if (i == k) - continue; - if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0) - continue; - - unique = FALSE; - config->entries[i]->non_unique = TRUE; - config->entries[k]->non_unique = TRUE; - } - } - if (unique) - return; - - /* add machine-id to non-unique titles */ - for (i = 0; i < config->entry_count; i++) { - CHAR16 *s; - CHAR16 *m; - - if (!config->entries[i]->non_unique) - continue; - if (!config->entries[i]->machine_id) - continue; - - m = StrDuplicate(config->entries[i]->machine_id); - m[8] = '\0'; - s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, m); - FreePool(config->entries[i]->title_show); - config->entries[i]->title_show = s; - config->entries[i]->non_unique = FALSE; - FreePool(m); - } - - unique = TRUE; - for (i = 0; i < config->entry_count; i++) { - for (k = 0; k < config->entry_count; k++) { - if (i == k) - continue; - if (StrCmp(config->entries[i]->title_show, config->entries[k]->title_show) != 0) - continue; - - unique = FALSE; - config->entries[i]->non_unique = TRUE; - config->entries[k]->non_unique = TRUE; - } - } - if (unique) - return; - - /* add file name to non-unique titles */ - for (i = 0; i < config->entry_count; i++) { - CHAR16 *s; - - if (!config->entries[i]->non_unique) - continue; - s = PoolPrint(L"%s (%s)", config->entries[i]->title_show, config->entries[i]->file); - FreePool(config->entries[i]->title_show); - config->entries[i]->title_show = s; - config->entries[i]->non_unique = FALSE; - } -} - -static BOOLEAN config_entry_add_call(Config *config, CHAR16 *title, EFI_STATUS (*call)(VOID)) { - ConfigEntry *entry; - - entry = AllocateZeroPool(sizeof(ConfigEntry)); - entry->title = StrDuplicate(title); - entry->call = call; - entry->no_autoselect = TRUE; - config_add_entry(config, entry); - return TRUE; -} - -static ConfigEntry *config_entry_add_loader(Config *config, EFI_HANDLE *device, - enum loader_type type,CHAR16 *file, CHAR16 key, CHAR16 *title, CHAR16 *loader) { - ConfigEntry *entry; - - entry = AllocateZeroPool(sizeof(ConfigEntry)); - entry->type = type; - entry->title = StrDuplicate(title); - entry->device = device; - entry->loader = StrDuplicate(loader); - entry->file = StrDuplicate(file); - StrLwr(entry->file); - entry->key = key; - config_add_entry(config, entry); - - return entry; -} - -static BOOLEAN config_entry_add_loader_auto(Config *config, EFI_HANDLE *device, EFI_FILE *root_dir, CHAR16 *loaded_image_path, - CHAR16 *file, CHAR16 key, CHAR16 *title, CHAR16 *loader) { - EFI_FILE_HANDLE handle; - ConfigEntry *entry; - EFI_STATUS err; - - /* do not add an entry for ourselves */ - if (loaded_image_path && StriCmp(loader, loaded_image_path) == 0) - return FALSE; - - /* check existence */ - err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, loader, EFI_FILE_MODE_READ, 0ULL); - if (EFI_ERROR(err)) - return FALSE; - uefi_call_wrapper(handle->Close, 1, handle); - - entry = config_entry_add_loader(config, device, LOADER_UNDEFINED, file, key, title, loader); - if (!entry) - return FALSE; - - /* do not boot right away into auto-detected entries */ - entry->no_autoselect = TRUE; - - /* do not show a splash; they do not need one, or they draw their own */ - entry->splash = StrDuplicate(L""); - - /* export identifiers of automatically added entries */ - if (config->entries_auto) { - CHAR16 *s; - - s = PoolPrint(L"%s %s", config->entries_auto, file); - FreePool(config->entries_auto); - config->entries_auto = s; - } else - config->entries_auto = StrDuplicate(file); - - return TRUE; -} - -static VOID config_entry_add_osx(Config *config) { - EFI_STATUS err; - UINTN handle_count = 0; - EFI_HANDLE *handles = NULL; - - err = LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &handle_count, &handles); - if (!EFI_ERROR(err)) { - UINTN i; - - for (i = 0; i < handle_count; i++) { - EFI_FILE *root; - BOOLEAN found; - - root = LibOpenRoot(handles[i]); - if (!root) - continue; - found = config_entry_add_loader_auto(config, handles[i], root, NULL, L"auto-osx", 'a', L"OS X", - L"\\System\\Library\\CoreServices\\boot.efi"); - uefi_call_wrapper(root->Close, 1, root); - if (found) - break; - } - - FreePool(handles); - } -} - -static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_image, EFI_FILE *root_dir) { - EFI_FILE_HANDLE linux_dir; - EFI_STATUS err; - - err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL); - if (!EFI_ERROR(err)) { - for (;;) { - CHAR16 buf[256]; - UINTN bufsize; - EFI_FILE_INFO *f; - CHAR8 *sections[] = { - (UINT8 *)".osrel", - NULL - }; - UINTN offs[ELEMENTSOF(sections)-1] = {}; - UINTN szs[ELEMENTSOF(sections)-1] = {}; - UINTN addrs[ELEMENTSOF(sections)-1] = {}; - CHAR8 *content = NULL; - UINTN len; - CHAR8 *line; - UINTN pos = 0; - CHAR8 *key, *value; - CHAR16 *os_name = NULL; - CHAR16 *os_id = NULL; - CHAR16 *os_version = NULL; - - bufsize = sizeof(buf); - err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf); - if (bufsize == 0 || EFI_ERROR(err)) - break; - - f = (EFI_FILE_INFO *) buf; - if (f->FileName[0] == '.') - continue; - if (f->Attribute & EFI_FILE_DIRECTORY) - continue; - len = StrLen(f->FileName); - if (len < 5) - continue; - if (StriCmp(f->FileName + len - 4, L".efi") != 0) - continue; - - /* look for an .osrel section in the .efi binary */ - err = pefile_locate_sections(linux_dir, f->FileName, sections, addrs, offs, szs); - if (EFI_ERROR(err)) - continue; - - len = file_read(linux_dir, f->FileName, offs[0], szs[0], &content); - if (len <= 0) - continue; - - /* read properties from the embedded os-release file */ - line = content; - while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) { - if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) { - os_name = stra_to_str(value); - continue; - } - - if (strcmpa((CHAR8 *)"ID", key) == 0) { - os_id = stra_to_str(value); - continue; - } - - if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) { - os_version = stra_to_str(value); - continue; - } - } - - if (os_name && os_id && os_version) { - CHAR16 *conf; - CHAR16 *path; - - conf = PoolPrint(L"%s-%s", os_id, os_version); - path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName); - config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path); - FreePool(conf); - FreePool(path); - FreePool(os_name); - FreePool(os_id); - FreePool(os_version); - } - - FreePool(content); - } - uefi_call_wrapper(linux_dir->Close, 1, linux_dir); - } -} - -static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, const ConfigEntry *entry) { - EFI_HANDLE image; - EFI_DEVICE_PATH *path; - CHAR16 *options; - EFI_STATUS err; - - path = FileDevicePath(entry->device, entry->loader); - if (!path) { - Print(L"Error getting device path."); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return EFI_INVALID_PARAMETER; - } - - err = uefi_call_wrapper(BS->LoadImage, 6, FALSE, parent_image, path, NULL, 0, &image); - if (EFI_ERROR(err)) { - Print(L"Error loading %s: %r", entry->loader, err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - goto out; - } - - if (config->options_edit) - options = config->options_edit; - else if (entry->options) - options = entry->options; - else - options = NULL; - if (options) { - EFI_LOADED_IMAGE *loaded_image; - - err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image, - parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (EFI_ERROR(err)) { - Print(L"Error getting LoadedImageProtocol handle: %r", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - goto out_unload; - } - loaded_image->LoadOptions = options; - loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16); - } - - efivar_set_time_usec(L"LoaderTimeExecUSec", 0); - err = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL); -out_unload: - uefi_call_wrapper(BS->UnloadImage, 1, image); -out: - FreePool(path); - return err; -} - -static EFI_STATUS reboot_into_firmware(VOID) { - CHAR8 *b; - UINTN size; - UINT64 osind; - EFI_STATUS err; - - osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; - - err = efivar_get_raw(&global_guid, L"OsIndications", &b, &size); - if (!EFI_ERROR(err)) - osind |= (UINT64)*b; - FreePool(b); - - err = efivar_set_raw(&global_guid, L"OsIndications", (CHAR8 *)&osind, sizeof(UINT64), TRUE); - if (EFI_ERROR(err)) - return err; - - err = uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS, 0, NULL); - Print(L"Error calling ResetSystem: %r", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return err; -} - -static VOID config_free(Config *config) { - UINTN i; - - for (i = 0; i < config->entry_count; i++) - config_entry_free(config->entries[i]); - FreePool(config->entries); - FreePool(config->entry_default_pattern); - FreePool(config->options_edit); - FreePool(config->entry_oneshot); - FreePool(config->entries_auto); - FreePool(config->splash); - FreePool(config->background); -} - -EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { - CHAR16 *s; - CHAR8 *b; - UINTN size; - EFI_LOADED_IMAGE *loaded_image; - EFI_FILE *root_dir; - CHAR16 *loaded_image_path; - EFI_DEVICE_PATH *device_path; - EFI_STATUS err; - Config config; - UINT64 init_usec; - BOOLEAN menu = FALSE; - - InitializeLib(image, sys_table); - init_usec = time_usec(); - efivar_set_time_usec(L"LoaderTimeInitUSec", init_usec); - efivar_set(L"LoaderInfo", L"gummiboot " VERSION, FALSE); - s = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - efivar_set(L"LoaderFirmwareInfo", s, FALSE); - FreePool(s); - s = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); - efivar_set(L"LoaderFirmwareType", s, FALSE); - FreePool(s); - - err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image, - image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (EFI_ERROR(err)) { - Print(L"Error getting a LoadedImageProtocol handle: %r ", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return err; - } - - /* export the device path this image is started from */ - device_path = DevicePathFromHandle(loaded_image->DeviceHandle); - if (device_path) { - CHAR16 *str; - EFI_DEVICE_PATH *path, *paths; - - str = DevicePathToStr(device_path); - efivar_set(L"LoaderDeviceIdentifier", str, FALSE); - FreePool(str); - - paths = UnpackDevicePath(device_path); - for (path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) { - HARDDRIVE_DEVICE_PATH *drive; - CHAR16 uuid[37]; - - if (DevicePathType(path) != MEDIA_DEVICE_PATH) - continue; - if (DevicePathSubType(path) != MEDIA_HARDDRIVE_DP) - continue; - drive = (HARDDRIVE_DEVICE_PATH *)path; - if (drive->SignatureType != SIGNATURE_TYPE_GUID) - continue; - - GuidToString(uuid, (EFI_GUID *)&drive->Signature); - efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); - break; - } - FreePool(paths); - } - - root_dir = LibOpenRoot(loaded_image->DeviceHandle); - if (!root_dir) { - Print(L"Unable to open root directory: %r ", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return EFI_LOAD_ERROR; - } - - - /* the filesystem path to this image, to prevent adding ourselves to the menu */ - loaded_image_path = DevicePathToStr(loaded_image->FilePath); - efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE); - - /* scan "\loader\entries\*.conf" files */ - ZeroMem(&config, sizeof(Config)); - config_load(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path); - - if (!config.background) { - config.background = AllocateZeroPool(sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); - if (StriCmp(L"Apple", ST->FirmwareVendor) == 0) { - config.background->Red = 0xc0; - config.background->Green = 0xc0; - config.background->Blue = 0xc0; - } - } - - /* if we find some well-known loaders, add them to the end of the list */ - config_entry_add_linux(&config, loaded_image, root_dir); - config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, - L"auto-windows", 'w', L"Windows Boot Manager", L"\\EFI\\Microsoft\\Boot\\bootmgfw.efi"); - config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, - L"auto-efi-shell", 's', L"EFI Shell", L"\\shell" MACHINE_TYPE_NAME ".efi"); - config_entry_add_loader_auto(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path, - L"auto-efi-default", '\0', L"EFI Default Loader", L"\\EFI\\Boot\\boot" MACHINE_TYPE_NAME ".efi"); - config_entry_add_osx(&config); - efivar_set(L"LoaderEntriesAuto", config.entries_auto, FALSE); - - if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) { - UINT64 osind = (UINT64)*b; - - if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) - config_entry_add_call(&config, L"Reboot Into Firmware Interface", reboot_into_firmware); - FreePool(b); - } - - if (config.entry_count == 0) { - Print(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed."); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - goto out; - } - - config_title_generate(&config); - - /* select entry by configured pattern or EFI LoaderDefaultEntry= variable*/ - config_default_entry_select(&config); - - /* if no configured entry to select from was found, enable the menu */ - if (config.idx_default == -1) { - config.idx_default = 0; - if (config.timeout_sec == 0) - config.timeout_sec = 10; - } - - /* select entry or show menu when key is pressed or timeout is set */ - if (config.timeout_sec == 0) { - UINT64 key; - - err = console_key_read(&key, FALSE); - if (!EFI_ERROR(err)) { - INT16 idx; - - /* find matching key in config entries */ - idx = entry_lookup_key(&config, config.idx_default, KEYCHAR(key)); - if (idx >= 0) - config.idx_default = idx; - else - menu = TRUE; - } - } else - menu = TRUE; - - for (;;) { - ConfigEntry *entry; - - entry = config.entries[config.idx_default]; - if (menu) { - efivar_set_time_usec(L"LoaderTimeMenuUSec", 0); - uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x10000, 0, NULL); - if (!menu_run(&config, &entry, root_dir, loaded_image_path)) - break; - - /* run special entry like "reboot" */ - if (entry->call) { - entry->call(); - continue; - } - } else { - err = EFI_NOT_FOUND; - - /* splash from entry file */ - if (entry->splash) { - /* some entries disable the splash because they draw their own */ - if (entry->splash[0] == '\0') - err = EFI_SUCCESS; - else - err = graphics_splash(root_dir, entry->splash, config.background); - } - - /* splash from config file */ - if (EFI_ERROR(err) && config.splash) - err = graphics_splash(root_dir, config.splash, config.background); - - /* default splash */ - if (EFI_ERROR(err)) - graphics_splash(root_dir, L"\\EFI\\gummiboot\\splash.bmp", config.background); - } - - /* export the selected boot entry to the system */ - efivar_set(L"LoaderEntrySelected", entry->file, FALSE); - - uefi_call_wrapper(BS->SetWatchdogTimer, 4, 5 * 60, 0x10000, 0, NULL); - err = image_start(image, &config, entry); - - if (err == EFI_ACCESS_DENIED || err == EFI_SECURITY_VIOLATION) { - /* Platform is secure boot and requested image isn't - * trusted. Need to go back to prior boot system and - * install more keys or hashes. Signal failure by - * returning the error */ - Print(L"\nImage %s gives a security error\n", entry->title); - Print(L"Please enrol the hash or signature of %s\n", entry->loader); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - goto out; - } - - menu = TRUE; - config.timeout_sec = 0; - } - err = EFI_SUCCESS; -out: - FreePool(loaded_image_path); - config_free(&config); - uefi_call_wrapper(root_dir->Close, 1, root_dir); - uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL); - return err; -} diff --git a/src/efi/linux.c b/src/efi/linux.c deleted file mode 100644 index 809c693..0000000 --- a/src/efi/linux.c +++ /dev/null @@ -1,130 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2015 Kay Sievers <kay@vrfy.org> - */ - -#include <efi.h> -#include <efilib.h> - -#include "util.h" -#include "linux.h" - -#define SETUP_MAGIC 0x53726448 /* "HdrS" */ -struct SetupHeader { - UINT8 boot_sector[0x01f1]; - UINT8 setup_secs; - UINT16 root_flags; - UINT32 sys_size; - UINT16 ram_size; - UINT16 video_mode; - UINT16 root_dev; - UINT16 signature; - UINT16 jump; - UINT32 header; - UINT16 version; - UINT16 su_switch; - UINT16 setup_seg; - UINT16 start_sys; - UINT16 kernel_ver; - UINT8 loader_id; - UINT8 load_flags; - UINT16 movesize; - UINT32 code32_start; - UINT32 ramdisk_start; - UINT32 ramdisk_len; - UINT32 bootsect_kludge; - UINT16 heap_end; - UINT8 ext_loader_ver; - UINT8 ext_loader_type; - UINT32 cmd_line_ptr; - UINT32 ramdisk_max; - UINT32 kernel_alignment; - UINT8 relocatable_kernel; - UINT8 min_alignment; - UINT16 xloadflags; - UINT32 cmdline_size; - UINT32 hardware_subarch; - UINT64 hardware_subarch_data; - UINT32 payload_offset; - UINT32 payload_length; - UINT64 setup_data; - UINT64 pref_address; - UINT32 init_size; - UINT32 handover_offset; -} __attribute__((packed)); - -#ifdef __x86_64__ -typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup); -static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { - handover_f handover; - - asm volatile ("cli"); - handover = (handover_f)((UINTN)setup->code32_start + 512 + setup->handover_offset); - handover(image, ST, setup); -} -#else -typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup) __attribute__((regparm(0))); -static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { - handover_f handover; - - handover = (handover_f)((UINTN)setup->code32_start + setup->handover_offset); - handover(image, ST, setup); -} -#endif - -EFI_STATUS linux_exec(EFI_HANDLE *image, - CHAR8 *cmdline, UINTN cmdline_len, - UINTN linux_addr, - UINTN initrd_addr, UINTN initrd_size) { - struct SetupHeader *image_setup; - struct SetupHeader *boot_setup; - EFI_PHYSICAL_ADDRESS addr; - EFI_STATUS err; - - image_setup = (struct SetupHeader *)(linux_addr); - if (image_setup->signature != 0xAA55 || image_setup->header != SETUP_MAGIC) - return EFI_LOAD_ERROR; - - if (image_setup->version < 0x20b || !image_setup->relocatable_kernel) - return EFI_LOAD_ERROR; - - addr = 0x3fffffff; - err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData, - EFI_SIZE_TO_PAGES(0x4000), &addr); - if (EFI_ERROR(err)) - return err; - boot_setup = (struct SetupHeader *)(UINTN)addr; - ZeroMem(boot_setup, 0x4000); - CopyMem(boot_setup, image_setup, sizeof(struct SetupHeader)); - boot_setup->loader_id = 0xff; - - boot_setup->code32_start = (UINT32)linux_addr + (image_setup->setup_secs+1) * 512; - - if (cmdline) { - addr = 0xA0000; - err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData, - EFI_SIZE_TO_PAGES(cmdline_len + 1), &addr); - if (EFI_ERROR(err)) - return err; - CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len); - ((CHAR8 *)addr)[cmdline_len] = 0; - boot_setup->cmd_line_ptr = (UINT32)addr; - } - - boot_setup->ramdisk_start = (UINT32)initrd_addr; - boot_setup->ramdisk_len = (UINT32)initrd_size; - - linux_efi_handover(image, boot_setup); - return EFI_LOAD_ERROR; -} diff --git a/src/efi/linux.h b/src/efi/linux.h deleted file mode 100644 index e5d4f5a..0000000 --- a/src/efi/linux.h +++ /dev/null @@ -1,24 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2015 Kay Sievers <kay@vrfy.org> - */ - -#ifndef __GUMMIBOOT_kernel_H -#define __GUMMIBOOT_kernel_H - -EFI_STATUS linux_exec(EFI_HANDLE *image, - CHAR8 *cmdline, UINTN cmdline_size, - UINTN linux_addr, - UINTN initrd_addr, UINTN initrd_size); -#endif diff --git a/src/efi/pefile.c b/src/efi/pefile.c deleted file mode 100644 index e6fedbc..0000000 --- a/src/efi/pefile.c +++ /dev/null @@ -1,172 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2015 Kay Sievers <kay@vrfy.org> - */ - -#include <efi.h> -#include <efilib.h> - -#include "util.h" -#include "pefile.h" - -struct DosFileHeader { - UINT8 Magic[2]; - UINT16 LastSize; - UINT16 nBlocks; - UINT16 nReloc; - UINT16 HdrSize; - UINT16 MinAlloc; - UINT16 MaxAlloc; - UINT16 ss; - UINT16 sp; - UINT16 Checksum; - UINT16 ip; - UINT16 cs; - UINT16 RelocPos; - UINT16 nOverlay; - UINT16 reserved[4]; - UINT16 OEMId; - UINT16 OEMInfo; - UINT16 reserved2[10]; - UINT32 ExeHeader; -} __attribute__((packed)); - -#define PE_HEADER_MACHINE_I386 0x014c -#define PE_HEADER_MACHINE_X64 0x8664 -struct PeFileHeader { - UINT16 Machine; - UINT16 NumberOfSections; - UINT32 TimeDateStamp; - UINT32 PointerToSymbolTable; - UINT32 NumberOfSymbols; - UINT16 SizeOfOptionalHeader; - UINT16 Characteristics; -} __attribute__((packed)); - -struct PeSectionHeader { - UINT8 Name[8]; - UINT32 VirtualSize; - UINT32 VirtualAddress; - UINT32 SizeOfRawData; - UINT32 PointerToRawData; - UINT32 PointerToRelocations; - UINT32 PointerToLinenumbers; - UINT16 NumberOfRelocations; - UINT16 NumberOfLinenumbers; - UINT32 Characteristics; -} __attribute__((packed)); - - -EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) { - EFI_FILE_HANDLE handle; - struct DosFileHeader dos; - uint8_t magic[4]; - struct PeFileHeader pe; - UINTN len; - UINTN i; - EFI_STATUS err; - - err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL); - if (EFI_ERROR(err)) - return err; - - /* MS-DOS stub */ - len = sizeof(dos); - err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos); - if (EFI_ERROR(err)) - goto out; - if (len != sizeof(dos)) { - err = EFI_LOAD_ERROR; - goto out; - } - - if (CompareMem(dos.Magic, "MZ", 2) != 0) { - err = EFI_LOAD_ERROR; - goto out; - } - - err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader); - if (EFI_ERROR(err)) - goto out; - - /* PE header */ - len = sizeof(magic); - err = uefi_call_wrapper(handle->Read, 3, handle, &len, &magic); - if (EFI_ERROR(err)) - goto out; - if (len != sizeof(magic)) { - err = EFI_LOAD_ERROR; - goto out; - } - - if (CompareMem(magic, "PE\0\0", 2) != 0) { - err = EFI_LOAD_ERROR; - goto out; - } - - len = sizeof(pe); - err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe); - if (EFI_ERROR(err)) - goto out; - if (len != sizeof(pe)) { - err = EFI_LOAD_ERROR; - goto out; - } - - /* PE32+ Subsystem type */ - if (pe.Machine != PE_HEADER_MACHINE_X64 && - pe.Machine != PE_HEADER_MACHINE_I386) { - err = EFI_LOAD_ERROR; - goto out; - } - - if (pe.NumberOfSections > 96) { - err = EFI_LOAD_ERROR; - goto out; - } - - /* the sections start directly after the headers */ - err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader + sizeof(magic) + sizeof(pe) + pe.SizeOfOptionalHeader); - if (EFI_ERROR(err)) - goto out; - - for (i = 0; i < pe.NumberOfSections; i++) { - struct PeSectionHeader sect; - UINTN j; - - len = sizeof(sect); - err = uefi_call_wrapper(handle->Read, 3, handle, &len, §); - if (EFI_ERROR(err)) - goto out; - if (len != sizeof(sect)) { - err = EFI_LOAD_ERROR; - goto out; - } - for (j = 0; sections[j]; j++) { - if (CompareMem(sect.Name, sections[j], strlena(sections[j])) != 0) - continue; - - if (addrs) - addrs[j] = (UINTN)sect.VirtualAddress; - if (offsets) - offsets[j] = (UINTN)sect.PointerToRawData; - if (sizes) - sizes[j] = (UINTN)sect.VirtualSize; - } - } - -out: - uefi_call_wrapper(handle->Close, 1, handle); - return err; -} diff --git a/src/efi/pefile.h b/src/efi/pefile.h deleted file mode 100644 index 3adf1b0..0000000 --- a/src/efi/pefile.h +++ /dev/null @@ -1,22 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2015 Kay Sievers <kay@vrfy.org> - */ - -#ifndef __GUMMIBOOT_PEFILE_H -#define __GUMMIBOOT_PEFILE_H - -EFI_STATUS pefile_locate_sections(EFI_FILE *dir, CHAR16 *path, - CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes); -#endif diff --git a/src/efi/stub.c b/src/efi/stub.c deleted file mode 100644 index e18faac..0000000 --- a/src/efi/stub.c +++ /dev/null @@ -1,106 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2015 Kay Sievers <kay@vrfy.org> - */ - -#include <efi.h> -#include <efilib.h> - -#include "util.h" -#include "pefile.h" -#include "linux.h" - -/* magic string to find in the binary image */ -static const char __attribute__((used)) magic[] = "#### LoaderInfo: stub " VERSION " ####"; - -static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; - -EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { - EFI_LOADED_IMAGE *loaded_image; - EFI_FILE *root_dir; - CHAR16 *loaded_image_path; - CHAR8 *b; - UINTN size; - BOOLEAN secure = FALSE; - CHAR8 *sections[] = { - (UINT8 *)".cmdline", - (UINT8 *)".linux", - (UINT8 *)".initrd", - NULL - }; - UINTN addrs[ELEMENTSOF(sections)-1] = {}; - UINTN offs[ELEMENTSOF(sections)-1] = {}; - UINTN szs[ELEMENTSOF(sections)-1] = {}; - CHAR8 *cmdline = NULL; - UINTN cmdline_len; - EFI_STATUS err; - - InitializeLib(image, sys_table); - - err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image, - image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (EFI_ERROR(err)) { - Print(L"Error getting a LoadedImageProtocol handle: %r ", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return err; - } - - root_dir = LibOpenRoot(loaded_image->DeviceHandle); - if (!root_dir) { - Print(L"Unable to open root directory: %r ", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return EFI_LOAD_ERROR; - } - - loaded_image_path = DevicePathToStr(loaded_image->FilePath); - - if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) { - if (*b > 0) - secure = TRUE; - FreePool(b); - } - - err = pefile_locate_sections(root_dir, loaded_image_path, sections, addrs, offs, szs); - if (EFI_ERROR(err)) { - Print(L"Unable to locate embedded .linux section: %r ", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return err; - } - - if (szs[0] > 0) - cmdline = (CHAR8 *)(loaded_image->ImageBase + addrs[0]); - - cmdline_len = szs[0]; - - /* if we are not in secure boot mode, accept a custom command line and replace the built-in one */ - if (!secure && loaded_image->LoadOptionsSize > 0) { - CHAR16 *options; - CHAR8 *line; - UINTN i; - - options = (CHAR16 *)loaded_image->LoadOptions; - cmdline_len = (loaded_image->LoadOptionsSize / sizeof(CHAR16)) * sizeof(CHAR8); - line = AllocatePool(cmdline_len); - for (i = 0; i < cmdline_len; i++) - line[i] = options[i]; - cmdline = line; - } - - err = linux_exec(image, cmdline, cmdline_len, - (UINTN)loaded_image->ImageBase + addrs[1], - (UINTN)loaded_image->ImageBase + addrs[2], szs[2]); - - Print(L"Execution of embedded linux image failed: %r\n", err); - uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000); - return err; -} diff --git a/src/efi/util.c b/src/efi/util.c deleted file mode 100644 index ba5ed7d..0000000 --- a/src/efi/util.c +++ /dev/null @@ -1,342 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> - */ - -#include <efi.h> -#include <efilib.h> - -#include "util.h" - -/* - * Allocated random UUID, intended to be shared across tools that implement - * the (ESP)\loader\entries\<vendor>-<revision>.conf convention and the - * associated EFI variables. - */ -static const EFI_GUID loader_guid = { 0x4a67b082, 0x0a4c, 0x41cf, {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f} }; - -#ifdef __x86_64__ -UINT64 ticks_read(VOID) { - UINT64 a, d; - __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); - return (d << 32) | a; -} -#else -UINT64 ticks_read(VOID) { - UINT64 val; - __asm__ volatile ("rdtsc" : "=A" (val)); - return val; -} -#endif - -/* count TSC ticks during a millisecond delay */ -UINT64 ticks_freq(VOID) { - UINT64 ticks_start, ticks_end; - - ticks_start = ticks_read(); - uefi_call_wrapper(BS->Stall, 1, 1000); - ticks_end = ticks_read(); - - return (ticks_end - ticks_start) * 1000; -} - -UINT64 time_usec(VOID) { - UINT64 ticks; - static UINT64 freq; - - ticks = ticks_read(); - if (ticks == 0) - return 0; - - if (freq == 0) { - freq = ticks_freq(); - if (freq == 0) - return 0; - } - - return 1000 * 1000 * ticks / freq; -} - -EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b) { - if (strcmpa(v, (CHAR8 *)"1") == 0 || - strcmpa(v, (CHAR8 *)"yes") == 0 || - strcmpa(v, (CHAR8 *)"y") == 0 || - strcmpa(v, (CHAR8 *)"true") == 0) { - *b = TRUE; - return EFI_SUCCESS; - } - - if (strcmpa(v, (CHAR8 *)"0") == 0 || - strcmpa(v, (CHAR8 *)"no") == 0 || - strcmpa(v, (CHAR8 *)"n") == 0 || - strcmpa(v, (CHAR8 *)"false") == 0) { - *b = FALSE; - return EFI_SUCCESS; - } - - return EFI_INVALID_PARAMETER; -} - -EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) { - UINT32 flags; - - flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; - if (persistent) - flags |= EFI_VARIABLE_NON_VOLATILE; - - return uefi_call_wrapper(RT->SetVariable, 5, name, (EFI_GUID *)vendor, flags, size, buf); -} - -EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent) { - return efivar_set_raw(&loader_guid, name, (CHAR8 *)value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent); -} - -EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) { - CHAR16 str[32]; - - SPrint(str, 32, L"%d", i); - return efivar_set(name, str, persistent); -} - -EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value) { - CHAR8 *buf; - CHAR16 *val; - UINTN size; - EFI_STATUS err; - - err = efivar_get_raw(&loader_guid, name, &buf, &size); - if (EFI_ERROR(err)) - return err; - - val = StrDuplicate((CHAR16 *)buf); - if (!val) { - FreePool(buf); - return EFI_OUT_OF_RESOURCES; - } - - *value = val; - return EFI_SUCCESS; -} - -EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i) { - CHAR16 *val; - EFI_STATUS err; - - err = efivar_get(name, &val); - if (!EFI_ERROR(err)) { - *i = Atoi(val); - FreePool(val); - } - return err; -} - -EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) { - CHAR8 *buf; - UINTN l; - EFI_STATUS err; - - l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE; - buf = AllocatePool(l); - if (!buf) - return EFI_OUT_OF_RESOURCES; - - err = uefi_call_wrapper(RT->GetVariable, 5, name, (EFI_GUID *)vendor, NULL, &l, buf); - if (!EFI_ERROR(err)) { - *buffer = buf; - if (size) - *size = l; - } else - FreePool(buf); - return err; - -} - -VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec) { - CHAR16 str[32]; - - if (usec == 0) - usec = time_usec(); - if (usec == 0) - return; - - SPrint(str, 32, L"%ld", usec); - efivar_set(name, str, FALSE); -} - -static INTN utf8_to_16(CHAR8 *stra, CHAR16 *c) { - CHAR16 unichar; - UINTN len; - UINTN i; - - if (stra[0] < 0x80) - len = 1; - else if ((stra[0] & 0xe0) == 0xc0) - len = 2; - else if ((stra[0] & 0xf0) == 0xe0) - len = 3; - else if ((stra[0] & 0xf8) == 0xf0) - len = 4; - else if ((stra[0] & 0xfc) == 0xf8) - len = 5; - else if ((stra[0] & 0xfe) == 0xfc) - len = 6; - else - return -1; - - switch (len) { - case 1: - unichar = stra[0]; - break; - case 2: - unichar = stra[0] & 0x1f; - break; - case 3: - unichar = stra[0] & 0x0f; - break; - case 4: - unichar = stra[0] & 0x07; - break; - case 5: - unichar = stra[0] & 0x03; - break; - case 6: - unichar = stra[0] & 0x01; - break; - } - - for (i = 1; i < len; i++) { - if ((stra[i] & 0xc0) != 0x80) - return -1; - unichar <<= 6; - unichar |= stra[i] & 0x3f; - } - - *c = unichar; - return len; -} - -CHAR16 *stra_to_str(CHAR8 *stra) { - UINTN strlen; - UINTN len; - UINTN i; - CHAR16 *str; - - len = strlena(stra); - str = AllocatePool((len + 1) * sizeof(CHAR16)); - - strlen = 0; - i = 0; - while (i < len) { - INTN utf8len; - - utf8len = utf8_to_16(stra + i, str + strlen); - if (utf8len <= 0) { - /* invalid utf8 sequence, skip the garbage */ - i++; - continue; - } - - strlen++; - i += utf8len; - } - str[strlen] = '\0'; - return str; -} - -CHAR16 *stra_to_path(CHAR8 *stra) { - CHAR16 *str; - UINTN strlen; - UINTN len; - UINTN i; - - len = strlena(stra); - str = AllocatePool((len + 2) * sizeof(CHAR16)); - - str[0] = '\\'; - strlen = 1; - i = 0; - while (i < len) { - INTN utf8len; - - utf8len = utf8_to_16(stra + i, str + strlen); - if (utf8len <= 0) { - /* invalid utf8 sequence, skip the garbage */ - i++; - continue; - } - - if (str[strlen] == '/') - str[strlen] = '\\'; - if (str[strlen] == '\\' && str[strlen-1] == '\\') { - /* skip double slashes */ - i += utf8len; - continue; - } - - strlen++; - i += utf8len; - } - str[strlen] = '\0'; - return str; -} - -CHAR8 *strchra(CHAR8 *s, CHAR8 c) { - do { - if (*s == c) - return s; - } while (*s++); - return NULL; -} - -INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content) { - EFI_FILE_HANDLE handle; - CHAR8 *buf; - UINTN buflen; - EFI_STATUS err; - UINTN len; - - err = uefi_call_wrapper(dir->Open, 5, dir, &handle, name, EFI_FILE_MODE_READ, 0ULL); - if (EFI_ERROR(err)) - return err; - - if (size == 0) { - EFI_FILE_INFO *info; - - info = LibFileInfo(handle); - buflen = info->FileSize+1; - FreePool(info); - } else - buflen = size; - - if (off > 0) { - err = uefi_call_wrapper(handle->SetPosition, 2, handle, off); - if (EFI_ERROR(err)) - return err; - } - - buf = AllocatePool(buflen); - err = uefi_call_wrapper(handle->Read, 3, handle, &buflen, buf); - if (!EFI_ERROR(err)) { - buf[buflen] = '\0'; - *content = buf; - len = buflen; - } else { - len = err; - FreePool(buf); - } - - uefi_call_wrapper(handle->Close, 1, handle); - return len; -} diff --git a/src/efi/util.h b/src/efi/util.h deleted file mode 100644 index b86102e..0000000 --- a/src/efi/util.h +++ /dev/null @@ -1,50 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * Copyright (C) 2012-2013 Kay Sievers <kay@vrfy.org> - * Copyright (C) 2012 Harald Hoyer <harald@redhat.com> - */ - -#ifndef __GUMMIBOOT_UTIL_H -#define __GUMMIBOOT_UTIL_H - -#include <efi.h> -#include <efilib.h> - -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) - -static inline const CHAR16 *yes_no(BOOLEAN b) { - return b ? L"yes" : L"no"; -} - -EFI_STATUS parse_boolean(CHAR8 *v, BOOLEAN *b); - -UINT64 ticks_read(void); -UINT64 ticks_freq(void); -UINT64 time_usec(void); - -EFI_STATUS efivar_set(CHAR16 *name, CHAR16 *value, BOOLEAN persistent); -EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent); -EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent); -VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec); - -EFI_STATUS efivar_get(CHAR16 *name, CHAR16 **value); -EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size); -EFI_STATUS efivar_get_int(CHAR16 *name, UINTN *i); - -CHAR8 *strchra(CHAR8 *s, CHAR8 c); -CHAR16 *stra_to_path(CHAR8 *stra); -CHAR16 *stra_to_str(CHAR8 *stra); - -INTN file_read(EFI_FILE_HANDLE dir, CHAR16 *name, UINTN off, UINTN size, CHAR8 **content); -#endif diff --git a/src/setup/efivars.c b/src/setup/efivars.c deleted file mode 100644 index 7123257..0000000 --- a/src/setup/efivars.c +++ /dev/null @@ -1,647 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - Copyright 2013 Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <unistd.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <errno.h> -#include <assert.h> -#include <stdio.h> -#include <fcntl.h> -#include <string.h> -#include <stddef.h> -#include <dirent.h> -#include <ctype.h> - -#include "efivars.h" - -bool is_efi_boot(void) { - return access("/sys/firmware/efi", F_OK) >= 0; -} - -static int read_flag(const char *varname) { - int r; - void *v; - size_t s; - uint8_t b; - - r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, &v, &s); - if (r < 0) - return r; - - if (s != 1) { - r = -EINVAL; - goto finish; - } - - b = *(uint8_t *)v; - r = b > 0; -finish: - free(v); - return r; -} - -int is_efi_secure_boot(void) { - return read_flag("SecureBoot"); -} - -int is_efi_secure_boot_setup_mode(void) { - return read_flag("SetupMode"); -} - -int efi_get_variable( - const uint8_t vendor[16], - const char *name, - void **value, - size_t *size) { - - int fd = -1; - char *p = NULL; - uint32_t a; - ssize_t n; - struct stat st; - void *b; - int r; - - assert(name); - assert(value); - assert(size); - - if (asprintf(&p, - "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - name, - vendor[0], vendor[1], vendor[2], vendor[3], vendor[4], vendor[5], vendor[6], vendor[7], - vendor[8], vendor[9], vendor[10], vendor[11], vendor[12], vendor[13], vendor[14], vendor[15]) < 0) - return -ENOMEM; - - fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (fd < 0) { - r = -errno; - goto finish; - } - - if (fstat(fd, &st) < 0) { - r = -errno; - goto finish; - } - if (st.st_size < 4) { - r = -EIO; - goto finish; - } - if (st.st_size > 4*1024*1024 + 4) { - r = -E2BIG; - goto finish; - } - - n = read(fd, &a, sizeof(a)); - if (n < 0) { - r = errno; - goto finish; - } - if (n != sizeof(a)) { - r = -EIO; - goto finish; - } - - b = malloc(st.st_size - 4 + 2); - if (!b) { - r = -ENOMEM; - goto finish; - } - - n = read(fd, b, (size_t) st.st_size - 4); - if (n < 0) { - free(b); - r = errno; - goto finish; - } - if (n != (ssize_t) st.st_size - 4) { - free(b); - r = -EIO; - goto finish; - } - - /* Always NUL terminate (2 bytes, to protect UTF-16) */ - ((char*) b)[st.st_size - 4] = 0; - ((char*) b)[st.st_size - 4 + 1] = 0; - - *value = b; - *size = (size_t) st.st_size - 4; - r = 0; - -finish: - if (fd >= 0) - close(fd); - free(p); - return r; -} - -int efi_set_variable( - const uint8_t vendor[16], - const char *name, - const void *value, - size_t size) { - - struct var { - uint32_t attr; - char buf[]; - } __attribute__((packed)) *buf = NULL; - char *p = NULL; - int fd = -1; - int r; - - assert(vendor); - assert(name); - - if (asprintf(&p, - "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - name, - vendor[0], vendor[1], vendor[2], vendor[3], vendor[4], vendor[5], vendor[6], vendor[7], - vendor[8], vendor[9], vendor[10], vendor[11], vendor[12], vendor[13], vendor[14], vendor[15]) < 0) - return -ENOMEM; - - if (size == 0) { - r = unlink(p); - goto finish; - } - - fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644); - if (fd < 0) { - r = -errno; - goto finish; - } - - buf = malloc(sizeof(uint32_t) + size); - if (!buf) { - r = -errno; - goto finish; - } - - buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; - memcpy(buf->buf, value, size); - - r = write(fd, buf, sizeof(uint32_t) + size); - if (r < 0) { - r = -errno; - goto finish; - } - - if ((size_t)r != sizeof(uint32_t) + size) { - r = -EIO; - goto finish; - } - -finish: - if (fd >= 0) - close(fd); - free(buf); - free(p); - return r; -} - -int efi_get_variable_string(const uint8_t vendor[16], const char *name, char **p) { - void *s = NULL; - size_t ss; - char *x; - int r; - - r = efi_get_variable(vendor, name, &s, &ss); - if (r < 0) - return r; - - x = utf16_to_utf8(s, ss); - free(s); - if (!x) - return -ENOMEM; - - *p = x; - return 0; -} - -static size_t utf16_size(const uint16_t *s) { - size_t l = 0; - - while (s[l] > 0) - l++; - - return (l+1) * sizeof(uint16_t); -} - -struct guid { - uint32_t u1; - uint16_t u2; - uint16_t u3; - uint8_t u4[8]; -} __attribute__((packed)); - -static void efi_guid_to_id128(const void *guid, uint8_t *bytes) { - const struct guid *uuid = guid; - - bytes[0] = (uuid->u1 >> 24) & 0xff; - bytes[1] = (uuid->u1 >> 16) & 0xff; - bytes[2] = (uuid->u1 >> 8) & 0xff; - bytes[3] = (uuid->u1) & 0xff; - bytes[4] = (uuid->u2 >> 8) & 0xff; - bytes[5] = (uuid->u2) & 0xff; - bytes[6] = (uuid->u3 >> 8) & 0xff; - bytes[7] = (uuid->u3) & 0xff; - memcpy(bytes+8, uuid->u4, sizeof(uuid->u4)); -} - -static void id128_to_efi_guid(const uint8_t *bytes, void *guid) { - struct guid *uuid = guid; - - uuid->u1 = bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]; - uuid->u2 = bytes[4] << 8 | bytes[5]; - uuid->u3 = bytes[6] << 8 | bytes[7]; - memcpy(uuid->u4, bytes+8, sizeof(uuid->u4)); -} - -char *tilt_backslashes(char *s) { - char *p; - - for (p = s; *p; p++) - if (*p == '\\') - *p = '/'; - - return s; -} - -uint16_t *tilt_slashes(uint16_t *s) { - uint16_t *p; - - for (p = s; *p; p++) - if (*p == '/') - *p = '\\'; - - return s; -} - -#define LOAD_OPTION_ACTIVE 0x00000001 -#define MEDIA_DEVICE_PATH 0x04 -#define MEDIA_HARDDRIVE_DP 0x01 -#define MEDIA_FILEPATH_DP 0x04 -#define SIGNATURE_TYPE_GUID 0x02 -#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02 -#define END_DEVICE_PATH_TYPE 0x7f -#define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff - -struct boot_option { - uint32_t attr; - uint16_t path_len; - uint16_t title[]; -} __attribute__((packed)); - -struct drive_path { - uint32_t part_nr; - uint64_t part_start; - uint64_t part_size; - char signature[16]; - uint8_t mbr_type; - uint8_t signature_type; -} __attribute__((packed)); - -struct device_path { - uint8_t type; - uint8_t sub_type; - uint16_t length; - union { - uint16_t path[0]; - struct drive_path drive; - }; -} __attribute__((packed)); - -int efi_get_boot_option(uint16_t id, char **title, uint8_t part_uuid[16], char **path, bool *active) { - char boot_id[9]; - uint8_t *buf = NULL; - size_t l; - struct boot_option *header; - size_t title_size; - char *s = NULL; - char *p = NULL; - uint8_t p_uuid[16] = ""; - int err; - - snprintf(boot_id, sizeof(boot_id), "Boot%04X", id); - err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, (void **) &buf, &l); - if (err < 0) - return err; - if (l < sizeof(struct boot_option)) { - err = -ENOENT; - goto err; - } - - header = (struct boot_option *) buf; - title_size = utf16_size(header->title); - if (title_size > l - offsetof(struct boot_option, title)) { - err = -EINVAL; - goto err; - } - - s = utf16_to_utf8(header->title, title_size); - if (!s) { - err = -ENOMEM; - goto err; - } - - if (header->path_len > 0) { - uint8_t *dbuf; - size_t dnext; - - dbuf = buf + offsetof(struct boot_option, title) + title_size; - dnext = 0; - while (dnext < header->path_len) { - struct device_path *dpath; - - dpath = (struct device_path *)(dbuf + dnext); - if (dpath->length < 4) - break; - - /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */ - if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE) - break; - - dnext += dpath->length; - - if (dpath->type != MEDIA_DEVICE_PATH) - continue; - - if (dpath->sub_type == MEDIA_HARDDRIVE_DP) { - /* GPT Partition Table */ - if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER) - continue; - - if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID) - continue; - - efi_guid_to_id128(dpath->drive.signature, p_uuid); - continue; - } - - if (dpath->sub_type == MEDIA_FILEPATH_DP) { - p = utf16_to_utf8(dpath->path, dpath->length-4); - tilt_backslashes(p); - continue; - } - } - } - - if (title) - *title = s; - else - free(s); - - if (part_uuid) - memcpy(part_uuid, p_uuid, 16); - - if (path) - *path = p; - else - free(p); - - if (active) - *active = !!header->attr & LOAD_OPTION_ACTIVE; - - free(buf); - return 0; -err: - free(s); - free(p); - free(buf); - return err; -} - -static void to_utf16(uint16_t *dest, const char *src) { - int i; - - for (i = 0; src[i] != '\0'; i++) - dest[i] = src[i]; - dest[i] = '\0'; -} - -int efi_add_boot_option(uint16_t id, const char *title, - uint32_t part, uint64_t pstart, uint64_t psize, - const uint8_t part_uuid[16], - const char *path) { - char boot_id[9]; - char *buf; - size_t size; - size_t title_len; - size_t path_len; - struct boot_option *option; - struct device_path *devicep; - int err; - - title_len = (strlen(title)+1) * 2; - path_len = (strlen(path)+1) * 2; - - buf = calloc(sizeof(struct boot_option) + title_len + - sizeof(struct drive_path) + - sizeof(struct device_path) + path_len, 1); - if (!buf) { - err = -ENOMEM; - goto finish; - } - - /* header */ - option = (struct boot_option *)buf; - option->attr = LOAD_OPTION_ACTIVE; - option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) + - offsetof(struct device_path, path) + path_len + - offsetof(struct device_path, path); - to_utf16(option->title, title); - size = offsetof(struct boot_option, title) + title_len; - - /* partition info */ - devicep = (struct device_path *)(buf + size); - devicep->type = MEDIA_DEVICE_PATH; - devicep->sub_type = MEDIA_HARDDRIVE_DP; - devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path); - devicep->drive.part_nr = part; - devicep->drive.part_start = pstart; - devicep->drive.part_size = psize; - devicep->drive.signature_type = SIGNATURE_TYPE_GUID; - devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER; - id128_to_efi_guid(part_uuid, devicep->drive.signature); - size += devicep->length; - - /* path to loader */ - devicep = (struct device_path *)(buf + size); - devicep->type = MEDIA_DEVICE_PATH; - devicep->sub_type = MEDIA_FILEPATH_DP; - devicep->length = offsetof(struct device_path, path) + path_len; - to_utf16(devicep->path, path); - tilt_slashes(devicep->path); - size += devicep->length; - - /* end of path */ - devicep = (struct device_path *)(buf + size); - devicep->type = END_DEVICE_PATH_TYPE; - devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE; - devicep->length = offsetof(struct device_path, path); - size += devicep->length; - - snprintf(boot_id, sizeof(boot_id), "Boot%04X", id); - err = efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size); - -finish: - free(buf); - return err; -} - -int efi_remove_boot_option(uint16_t id) { - char boot_id[9]; - - snprintf(boot_id, sizeof(boot_id), "Boot%04X", id); - return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0); -} - -int efi_get_boot_order(uint16_t **order) { - void *buf; - size_t l; - int r; - - r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", &buf, &l); - if (r < 0) - return r; - - if (l <= 0) { - free(buf); - return -ENOENT; - } - - if ((l % sizeof(uint16_t) > 0)) { - free(buf); - return -EINVAL; - } - - *order = buf; - return (int) (l / sizeof(uint16_t)); -} - -int efi_set_boot_order(uint16_t *order, size_t n) { - return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t)); -} - -static int boot_id_hex(const char s[4]) { - int i; - int id = 0; - - for (i = 0; i < 4; i++) - if (s[i] >= '0' && s[i] <= '9') - id |= (s[i] - '0') << (3 - i) * 4; - else if (s[i] >= 'A' && s[i] <= 'F') - id |= (s[i] - 'A' + 10) << (3 - i) * 4; - else - return -1; - - return id; -} - -static int cmp_uint16(const void *_a, const void *_b) { - const uint16_t *a = _a, *b = _b; - - return (int)*a - (int)*b; -} - -int efi_get_boot_options(uint16_t **options) { - DIR *dir; - struct dirent *de; - uint16_t *list = NULL; - int count = 0; - - assert(options); - - dir = opendir("/sys/firmware/efi/efivars/"); - if (!dir) - return -errno; - - while ((de = readdir(dir))) { - int id; - uint16_t *t; - - if (strncmp(de->d_name, "Boot", 4) != 0) - continue; - - if (strlen(de->d_name) != 45) - continue; - - if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0) - continue; - - id = boot_id_hex(de->d_name + 4); - if (id < 0) - continue; - - t = realloc(list, (count + 1) * sizeof(uint16_t)); - if (!t) { - free(list); - closedir(dir); - return -ENOMEM; - } - list = t; - - list[count++] = id; - } - - closedir(dir); - qsort(list, count, sizeof(uint16_t), cmp_uint16); - *options = list; - - return count; -} - -char *utf16_to_utf8(const void *s, size_t length) { - char *r; - const uint8_t *f; - uint8_t *t; - - r = malloc((length*3+1)/2 + 1); - if (!r) - return NULL; - - t = (uint8_t*) r; - - for (f = s; f < (const uint8_t*) s + length; f += 2) { - uint16_t c; - - c = (f[1] << 8) | f[0]; - - if (c == 0) { - *t = 0; - return r; - } else if (c < 0x80) { - *(t++) = (uint8_t) c; - } else if (c < 0x800) { - *(t++) = (uint8_t) (0xc0 | (c >> 6)); - *(t++) = (uint8_t) (0x80 | (c & 0x3f)); - } else { - *(t++) = (uint8_t) (0xe0 | (c >> 12)); - *(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); - *(t++) = (uint8_t) (0x80 | (c & 0x3f)); - } - } - - *t = 0; - - return r; -} diff --git a/src/setup/efivars.h b/src/setup/efivars.h deleted file mode 100644 index dfe7355..0000000 --- a/src/setup/efivars.h +++ /dev/null @@ -1,55 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdbool.h> -#include <sys/types.h> -#include <inttypes.h> - -#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 -#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 -#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 - -#define EFI_VENDOR_GLOBAL ((uint8_t[16]) { 0x8b,0xe4,0xdf,0x61,0x93,0xca,0x11,0xd2,0xaa,0x0d,0x00,0xe0,0x98,0x03,0x2b,0x8c }) -#define EFI_VENDOR_LOADER ((uint8_t[16]) { 0x4a,0x67,0xb0,0x82,0x0a,0x4c,0x41,0xcf,0xb6,0xc7,0x44,0x0b,0x29,0xbb,0x8c,0x4f }) - -bool is_efi_boot(void); -int is_efi_secure_boot(void); -int is_efi_secure_boot_setup_mode(void); -int efi_get_variable(const uint8_t vendor[16], const char *name, void **value, size_t *size); -int efi_set_variable( const uint8_t vendor[16], const char *name, const void *value, size_t size); -int efi_get_variable_string(const uint8_t vendor[16], const char *name, char **p); -int efi_get_boot_option(uint16_t id, char **title, uint8_t part_uuid[16], char **path, bool *active); - -int efi_get_boot_options(uint16_t **options); -int efi_add_boot_option(uint16_t id, const char *title, - uint32_t part, uint64_t pstart, uint64_t psize, - const uint8_t part_uuid[16], - const char *path); -int efi_remove_boot_option(uint16_t id); - -int efi_get_boot_order(uint16_t **order); -int efi_set_boot_order(uint16_t *order, size_t n); - -char *utf16_to_utf8(const void *s, size_t length); -char *tilt_backslashes(char *s); -uint16_t *tilt_slashes(uint16_t *s); diff --git a/src/setup/setup.c b/src/setup/setup.c deleted file mode 100644 index 6a4275a..0000000 --- a/src/setup/setup.c +++ /dev/null @@ -1,1425 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - Copyright 2013 Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdio.h> -#include <getopt.h> -#include <errno.h> -#include <stdlib.h> -#include <assert.h> -#include <sys/statfs.h> -#include <sys/stat.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <sys/mman.h> -#include <dirent.h> -#include <ctype.h> -#include <limits.h> -#include <ftw.h> -#include <stdbool.h> -#include <blkid.h> - -#include "efivars.h" - -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) -#define streq(a,b) (strcmp((a),(b)) == 0) -#define UUID_EMPTY ((uint8_t[16]) {}) - -static inline bool streq_ptr(const char *a, const char *b) { - if (a && b) - return streq(a, b); - if (!a && !b) - return true; - return false; -} - -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - -static inline const char *strna(const char *s) { - return isempty(s) ? "n/a" : s; -} - -static int uuid_parse(const char *s, uint8_t uuid[16]) { - int u[16]; - int i; - - if (sscanf(s, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - &u[0], &u[1], &u[2], &u[3], &u[4], &u[5], &u[6], &u[7], - &u[8], &u[9], &u[10], &u[11], &u[12], &u[13], &u[14], &u[15]) != 16) - return -EINVAL; - - for (i = 0; i < 16; i++) - uuid[i] = u[i]; - - return 0; -} - -static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, uint8_t uuid[16]) { - struct statfs sfs; - struct stat st, st2; - char *t; - blkid_probe b = NULL; - int r; - const char *v; - - if (statfs(p, &sfs) < 0) { - fprintf(stderr, "Failed to check file system type of %s: %m\n", p); - return -errno; - } - - if (sfs.f_type != 0x4d44) { - fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system.\n", p); - return -ENODEV; - } - - if (stat(p, &st) < 0) { - fprintf(stderr, "Failed to determine block device node of %s: %m\n", p); - return -errno; - } - - if (major(st.st_dev) == 0) { - fprintf(stderr, "Block device node of %p is invalid.\n", p); - return -ENODEV; - } - - r = asprintf(&t, "%s/..", p); - if (r < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - r = stat(t, &st2); - free(t); - if (r < 0) { - fprintf(stderr, "Failed to determine block device node of parent of %s: %m\n", p); - return -errno; - } - - if (st.st_dev == st2.st_dev) { - fprintf(stderr, "Directory %s is not the root of the EFI System Partition (ESP) file system.\n", p); - return -ENODEV; - } - - r = asprintf(&t, "/dev/block/%u:%u", major(st.st_dev), minor(st.st_dev)); - if (r < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - errno = 0; - b = blkid_new_probe_from_filename(t); - free(t); - if (!b) { - if (errno != 0) { - fprintf(stderr, "Failed to open file system %s: %m\n", p); - return -errno; - } - - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - blkid_probe_enable_superblocks(b, 1); - blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); - blkid_probe_enable_partitions(b, 1); - blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); - - errno = 0; - r = blkid_do_safeprobe(b); - if (r == -2) { - fprintf(stderr, "File system %s is ambigious.\n", p); - r = -ENODEV; - goto fail; - } else if (r == 1) { - fprintf(stderr, "File system %s does not contain a label.\n", p); - r = -ENODEV; - goto fail; - } else if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe file system %s: %s\n", p, strerror(-r)); - goto fail; - } - - errno = 0; - r = blkid_probe_lookup_value(b, "TYPE", &v, NULL); - if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe file system type %s: %s\n", p, strerror(-r)); - goto fail; - } - - if (strcmp(v, "vfat") != 0) { - fprintf(stderr, "File system %s is not a FAT EFI System Partition (ESP) file system after all.\n", p); - r = -ENODEV; - goto fail; - } - - errno = 0; - r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL); - if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe partition scheme %s: %s\n", p, strerror(-r)); - goto fail; - } - - if (strcmp(v, "gpt") != 0) { - fprintf(stderr, "File system %s is not on a GPT partition table.\n", p); - r = -ENODEV; - goto fail; - } - - errno = 0; - r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); - if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe partition type UUID %s: %s\n", p, strerror(-r)); - goto fail; - } - - if (strcmp(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b") != 0) { - r = -ENODEV; - fprintf(stderr, "File system %s is not an EFI System Partition (ESP).\n", p); - goto fail; - } - - errno = 0; - r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL); - if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe partition entry UUID %s: %s\n", p, strerror(-r)); - goto fail; - } - uuid_parse(v, uuid); - - errno = 0; - r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL); - if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe partition number %s: %s\n", p, strerror(-r)); - goto fail; - } - *part = strtoul(v, NULL, 10); - - errno = 0; - r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL); - if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe partition offset %s: %s\n", p, strerror(-r)); - goto fail; - } - *pstart = strtoul(v, NULL, 10); - - errno = 0; - r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL); - if (r != 0) { - r = errno ? -errno : -EIO; - fprintf(stderr, "Failed to probe partition size %s: %s\n", p, strerror(-r)); - goto fail; - } - *psize = strtoul(v, NULL, 10); - - blkid_free_probe(b); - return 0; -fail: - if (b) - blkid_free_probe(b); - return r; -} - -/* search for "#### LoaderInfo: gummiboot 31 ####" string inside the binary */ -static int get_file_version(FILE *f, char **v) { - struct stat st; - char *buf; - const char *s, *e; - char *x = NULL; - int r = 0; - - assert(f); - assert(v); - - if (fstat(fileno(f), &st) < 0) - return -errno; - - if (st.st_size < 27) - return 0; - - buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fileno(f), 0); - if (buf == MAP_FAILED) - return -errno; - - s = memmem(buf, st.st_size - 8, "#### LoaderInfo: ", 17); - if (!s) - goto finish; - s += 17; - - e = memmem(s, st.st_size - (s - buf), " ####", 5); - if (!e || e - s < 3) { - fprintf(stderr, "Malformed version string.\n"); - r = -EINVAL; - goto finish; - } - - x = strndup(s, e - s); - if (!x) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - r = 1; - -finish: - munmap(buf, st.st_size); - *v = x; - return r; -} - -static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) { - struct dirent *de; - char *p = NULL, *q = NULL; - DIR *d = NULL; - int r = 0, c = 0; - - if (asprintf(&p, "%s/%s", esp_path, path) < 0) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - - d = opendir(p); - if (!d) { - if (errno == ENOENT) { - r = 0; - goto finish; - } - - fprintf(stderr, "Failed to read %s: %m\n", p); - r = -errno; - goto finish; - } - - while ((de = readdir(d))) { - char *v; - size_t n; - FILE *f; - - if (de->d_name[0] == '.') - continue; - - n = strlen(de->d_name); - if (n < 4 || strcasecmp(de->d_name + n - 4, ".efi") != 0) - continue; - - if (prefix && strncasecmp(de->d_name, prefix, strlen(prefix)) != 0) - continue; - - free(q); - q = NULL; - if (asprintf(&q, "%s/%s/%s", esp_path, path, de->d_name) < 0) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - - f = fopen(q, "re"); - if (!f) { - fprintf(stderr, "Failed to open %s for reading: %m\n", q); - r = -errno; - goto finish; - } - - r = get_file_version(f, &v); - fclose(f); - - if (r < 0) - goto finish; - - if (r > 0) - printf(" File: └─/%s/%s (%s)\n", path, de->d_name, v); - else - printf(" File: └─/%s/%s\n", path, de->d_name); - - c++; - free(v); - } - - r = c; - -finish: - if (d) - closedir(d); - - free(p); - free(q); - return r; -} - -static int status_binaries(const char *esp_path, uint8_t partition[16]) { - int r; - - printf("Boot Loader Binaries:\n"); - - printf(" ESP: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", - partition[0], partition[1], partition[2], partition[3], partition[4], partition[5], partition[6], partition[7], - partition[8], partition[9], partition[10], partition[11], partition[12], partition[13], partition[14], partition[15]); - - r = enumerate_binaries(esp_path, "EFI/gummiboot", NULL); - if (r == 0) - fprintf(stderr, "Gummiboot not installed in ESP.\n"); - else if (r < 0) - return r; - - r = enumerate_binaries(esp_path, "EFI/Boot", "boot"); - if (r == 0) - fprintf(stderr, "No default/fallback boot loader installed in ESP.\n"); - else if (r < 0) - return r; - - printf("\n"); - return 0; -} - -static int print_efi_option(uint16_t id, bool in_order) { - char *title = NULL; - char *path = NULL; - uint8_t partition[16]; - bool active; - int r = 0; - - r = efi_get_boot_option(id, &title, partition, &path, &active); - if (r < 0) - goto finish; - - /* print only configured entries with partition information */ - if (!path || memcmp(partition, UUID_EMPTY, 16) == 0) - return 0; - - printf(" Title: %s\n", strna(title)); - printf(" ID: 0x%04X\n", id); - printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : ""); - printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", - partition[0], partition[1], partition[2], partition[3], partition[4], partition[5], partition[6], partition[7], - partition[8], partition[9], partition[10], partition[11], partition[12], partition[13], partition[14], partition[15]); - printf(" File: └─%s\n", path); - printf("\n"); - -finish: - free(title); - free(path); - return r; -} - -static int status_variables(void) { - int n_options, n_order; - uint16_t *options = NULL, *order = NULL; - int r, i; - - if (!is_efi_boot()) { - fprintf(stderr, "Not booted with EFI, not showing EFI variables.\n"); - return 0; - } - - n_options = efi_get_boot_options(&options); - if (n_options < 0) { - if (n_options == -ENOENT) - fprintf(stderr, "Failed to access EFI variables, " - "efivarfs needs to be available at /sys/firmware/efi/efivars/.\n"); - else - fprintf(stderr, "Failed to read EFI boot entries: %s\n", strerror(-n_options)); - r = n_options; - goto finish; - } - - printf("Boot Loader Entries in EFI Variables:\n"); - n_order = efi_get_boot_order(&order); - if (n_order == -ENOENT) { - n_order = 0; - } else if (n_order < 0) { - fprintf(stderr, "Failed to read EFI boot order.\n"); - r = n_order; - goto finish; - } - - /* print entries in BootOrder first */ - for (i = 0; i < n_order; i++) - print_efi_option(order[i], true); - - /* print remaining entries */ - for (i = 0; i < n_options; i++) { - int j; - bool found = false; - - for (j = 0; j < n_order; j++) - if (options[i] == order[j]) { - found = true; - break; - } - - if (found) - continue; - - print_efi_option(options[i], false); - } - - r = 0; -finish: - free(options); - free(order); - - return r; -} - -static int compare_product(const char *a, const char *b) { - size_t x, y; - - assert(a); - assert(b); - - x = strcspn(a, " "); - y = strcspn(b, " "); - if (x != y) - return x < y ? -1 : x > y ? 1 : 0; - - return strncmp(a, b, x); -} - -static int compare_version(const char *a, const char *b) { - assert(a); - assert(b); - - a += strcspn(a, " "); - a += strspn(a, " "); - b += strcspn(b, " "); - b += strspn(b, " "); - - return strverscmp(a, b); -} - -static int version_check(FILE *f, const char *from, const char *to) { - FILE *g = NULL; - char *a = NULL, *b = NULL; - int r; - - assert(f); - assert(from); - assert(to); - - r = get_file_version(f, &a); - if (r < 0) - goto finish; - if (r == 0) { - r = -EINVAL; - fprintf(stderr, "Source file %s does not carry version information!\n", from); - goto finish; - } - - g = fopen(to, "re"); - if (!g) { - if (errno == ENOENT) { - r = 0; - goto finish; - } - - r = -errno; - fprintf(stderr, "Failed to open %s for reading: %m\n", to); - goto finish; - } - - r = get_file_version(g, &b); - if (r < 0) - goto finish; - if (r == 0 || compare_product(a, b) != 0) { - r = -EEXIST; - fprintf(stderr, "Skipping %s, since it's owned by another boot loader.\n", to); - goto finish; - } - - if (compare_version(a, b) < 0) { - r = -EEXIST; - fprintf(stderr, "Skipping %s, since it's a newer boot loader version already.\n", to); - goto finish; - } - - r = 0; - -finish: - free(a); - free(b); - if (g) - fclose(g); - return r; -} - -static int copy_file(const char *from, const char *to, bool force) { - FILE *f = NULL, *g = NULL; - char *p = NULL; - int r; - struct timespec t[2]; - struct stat st; - - assert(from); - assert(to); - - f = fopen(from, "re"); - if (!f) { - fprintf(stderr, "Failed to open %s for reading: %m\n", from); - return -errno; - } - - if (!force) { - /* If this is an update, then let's compare versions first */ - r = version_check(f, from, to); - if (r < 0) - goto finish; - } - - if (asprintf(&p, "%s~", to) < 0) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - - g = fopen(p, "wxe"); - if (!g) { - /* Directory doesn't exist yet? Then let's skip this... */ - if (!force && errno == ENOENT) { - r = 0; - goto finish; - } - - fprintf(stderr, "Failed to open %s for writing: %m\n", to); - r = -errno; - goto finish; - } - - rewind(f); - do { - size_t k; - uint8_t buf[32*1024]; - - k = fread(buf, 1, sizeof(buf), f); - if (ferror(f)) { - fprintf(stderr, "Failed to read %s: %m\n", from); - r = -errno; - goto finish; - } - if (k == 0) - break; - - fwrite(buf, 1, k, g); - if (ferror(g)) { - fprintf(stderr, "Failed to write %s: %m\n", to); - r = -errno; - goto finish; - } - } while (!feof(f)); - - fflush(g); - if (ferror(g)) { - fprintf(stderr, "Failed to write %s: %m\n", to); - r = -errno; - goto finish; - } - - r = fstat(fileno(f), &st); - if (r < 0) { - fprintf(stderr, "Failed to get file timestamps of %s: %m", from); - r = -errno; - goto finish; - } - - t[0] = st.st_atim; - t[1] = st.st_mtim; - - r = futimens(fileno(g), t); - if (r < 0) { - fprintf(stderr, "Failed to change file timestamps for %s: %m", p); - r = -errno; - goto finish; - } - - if (rename(p, to) < 0) { - fprintf(stderr, "Failed to rename %s to %s: %m\n", p, to); - r = -errno; - goto finish; - } - - fprintf(stderr, "Copied %s to %s.\n", from, to); - - free(p); - p = NULL; - r = 0; - -finish: - if (f) - fclose(f); - if (g) - fclose(g); - if (p) { - unlink(p); - free(p); - } - return r; -} - -static char* strupper(char *s) { - char *p; - - for (p = s; *p; p++) - *p = toupper(*p); - - return s; -} - -static int mkdir_one(const char *prefix, const char *suffix) { - char *p; - - if (asprintf(&p, "%s/%s", prefix, suffix) < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - if (mkdir(p, 0700) < 0) { - if (errno != EEXIST) { - fprintf(stderr, "Failed to create %s: %m\n", p); - free(p); - return -errno; - } - } else - fprintf(stderr, "Created %s.\n", p); - - free(p); - return 0; -} - -static int create_dirs(const char *esp_path) { - int r; - - r = mkdir_one(esp_path, "EFI"); - if (r < 0) - return r; - - r = mkdir_one(esp_path, "EFI/gummiboot"); - if (r < 0) - return r; - - r = mkdir_one(esp_path, "EFI/Boot"); - if (r < 0) - return r; - - r = mkdir_one(esp_path, "loader"); - if (r < 0) - return r; - - r = mkdir_one(esp_path, "loader/entries"); - if (r < 0) - return r; - - return 0; -} - -static int copy_one_file(const char *esp_path, const char *name, bool force) { - char *p = NULL, *q = NULL, *v = NULL; - int r; - - if (asprintf(&p, GUMMIBOOTLIBDIR "/%s", name) < 0) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - - if (asprintf(&q, "%s/EFI/gummiboot/%s", esp_path, name) < 0) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - - r = copy_file(p, q, force); - - if (strncmp(name, "gummiboot", 9) == 0) { - int k; - - /* Create the EFI default boot loader name (specified for removable devices) */ - if (asprintf(&v, "%s/EFI/Boot/%s", esp_path, name + 5) < 0) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - strupper(strrchr(v, '/') + 1); - - k = copy_file(p, v, force); - if (k < 0 && r == 0) { - r = k; - goto finish; - } - } - -finish: - free(p); - free(q); - free(v); - return r; -} - -static int install_binaries(const char *esp_path, bool force) { - struct dirent *de; - DIR *d; - int r = 0; - - if (force) { - /* Don't create any of these directories when we are - * just updating. When we update we'll drop-in our - * files (unless there are newer ones already), but we - * won't create the directories for them in the first - * place. */ - r = create_dirs(esp_path); - if (r < 0) - return r; - } - - d = opendir(GUMMIBOOTLIBDIR); - if (!d) { - fprintf(stderr, "Failed to open "GUMMIBOOTLIBDIR": %m\n"); - return -errno; - } - - while ((de = readdir(d))) { - size_t n; - int k; - - if (de->d_name[0] == '.') - continue; - - n = strlen(de->d_name); - if (n < 4 || strcmp(de->d_name + n - 4, ".efi") != 0) - continue; - - k = copy_one_file(esp_path, de->d_name, force); - if (k < 0 && r == 0) - r = k; - } - - closedir(d); - return r; -} - -static bool same_entry(uint16_t id, const uint8_t uuid[16], const char *path) { - char *opath = NULL; - uint8_t ouuid[16]; - int err; - bool same = false; - - err = efi_get_boot_option(id, NULL, ouuid, &opath, NULL); - if (err < 0) - return false; - if (memcmp(uuid, ouuid, 16) != 0) - goto finish; - - if (!streq_ptr(path, opath)) - goto finish; - - same = true; - -finish: - free(opath); - return same; -} - -static int find_slot(const uint8_t uuid[16], const char *path, uint16_t *id) { - uint16_t *options = NULL; - int n_options; - int i; - uint16_t new_id = 0; - bool existing = false; - - n_options = efi_get_boot_options(&options); - if (n_options < 0) - return n_options; - - /* find already existing gummiboot entry */ - for (i = 0; i < n_options; i++) - if (same_entry(options[i], uuid, path)) { - new_id = options[i]; - existing = true; - goto finish; - } - - /* find free slot in the sorted BootXXXX variable list */ - for (i = 0; i < n_options; i++) - if (i != options[i]) { - new_id = i; - goto finish; - } - - /* use the next one */ - if (i == 0xffff) - return -ENOSPC; - new_id = i; - -finish: - *id = new_id; - free(options); - return existing; -} - -static int insert_into_order(uint16_t slot, bool first) { - uint16_t *order = NULL; - uint16_t *new_order; - int n_order; - int i; - int err = 0; - - n_order = efi_get_boot_order(&order); - if (n_order <= 0) { - /* no entry, add us */ - err = efi_set_boot_order(&slot, 1); - goto finish; - } - - /* are we the first and only one? */ - if (n_order == 1 && order[0] == slot) - goto finish; - - /* are we already in the boot order? */ - for (i = 0; i < n_order; i++) { - if (order[i] != slot) - continue; - - /* we do not require to be the first one, all is fine */ - if (!first) - goto finish; - - /* move us to the first slot */ - memmove(&order[1], order, i * sizeof(uint16_t)); - order[0] = slot; - efi_set_boot_order(order, n_order); - goto finish; - } - - /* extend array */ - new_order = realloc(order, (n_order+1) * sizeof(uint16_t)); - if (!new_order) { - err = -ENOMEM; - goto finish; - } - order = new_order; - - /* add us to the top or end of the list */ - if (first) { - memmove(&order[1], order, n_order * sizeof(uint16_t)); - order[0] = slot; - } else - order[n_order] = slot; - - efi_set_boot_order(order, n_order+1); - -finish: - free(order); - return err; -} - -static int remove_from_order(uint16_t slot) { - uint16_t *order = NULL; - int n_order; - int i; - int err = 0; - - n_order = efi_get_boot_order(&order); - if (n_order < 0) - return n_order; - if (n_order == 0) - return 0; - - for (i = 0; i < n_order; i++) { - if (order[i] != slot) - continue; - - if (i+1 < n_order) - memmove(&order[i], &order[i+1], (n_order - i) * sizeof(uint16_t)); - efi_set_boot_order(order, n_order-1); - break; - } - - free(order); - return err; -} - -static int install_variables(const char *esp_path, - uint32_t part, uint64_t pstart, uint64_t psize, - const uint8_t uuid[16], const char *path, - bool first) { - char *p = NULL; - uint16_t *options = NULL; - uint16_t slot; - int r; - - if (!is_efi_boot()) { - fprintf(stderr, "Not booted with EFI, skipping EFI variable setup.\n"); - return 0; - } - - if (asprintf(&p, "%s%s", esp_path, path) < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - if (access(p, F_OK) < 0) { - if (errno == ENOENT) - r = 0; - else - r = -errno; - goto finish; - } - - r = find_slot(uuid, path, &slot); - if (r < 0) { - if (r == -ENOENT) - fprintf(stderr, "Failed to access EFI variables. Is the \"efivarfs\" filesystem mounted?\n"); - else - fprintf(stderr, "Failed to determine current boot order: %s\n", strerror(-r)); - goto finish; - } - - if (first || r == false) { - r = efi_add_boot_option(slot, "Linux Boot Manager", - part, pstart, psize, - uuid, path); - if (r < 0) { - fprintf(stderr, "Failed to create EFI Boot variable entry: %s\n", strerror(-r)); - goto finish; - } - fprintf(stderr, "Created EFI boot entry \"Linux Boot Manager\".\n"); - } - - insert_into_order(slot, first); - -finish: - free(p); - free(options); - return r; -} - -static int delete_nftw(const char *path, const struct stat *sb, int typeflag, struct FTW *ftw) { - int r; - - if (typeflag == FTW_D || typeflag == FTW_DNR || typeflag == FTW_DP) - r = rmdir(path); - else - r = unlink(path); - - if (r < 0) - fprintf(stderr, "Failed to remove %s: %m\n", path); - else - fprintf(stderr, "Removed %s.\n", path); - - return 0; -} - -static int rm_rf(const char *p) { - nftw(p, delete_nftw, 20, FTW_DEPTH|FTW_MOUNT|FTW_PHYS); - return 0; -} - -static int remove_boot_efi(const char *esp_path) { - struct dirent *de; - char *p = NULL, *q = NULL; - DIR *d = NULL; - int r = 0, c = 0; - - if (asprintf(&p, "%s/EFI/Boot", esp_path) < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - d = opendir(p); - if (!d) { - if (errno == ENOENT) { - r = 0; - goto finish; - } - - fprintf(stderr, "Failed to read %s: %m\n", p); - r = -errno; - goto finish; - } - - while ((de = readdir(d))) { - char *v; - size_t n; - FILE *f; - - if (de->d_name[0] == '.') - continue; - - n = strlen(de->d_name); - if (n < 4 || strcasecmp(de->d_name + n - 4, ".EFI") != 0) - continue; - - if (strncasecmp(de->d_name, "Boot", 4) != 0) - continue; - - free(q); - q = NULL; - if (asprintf(&q, "%s/%s", p, de->d_name) < 0) { - fprintf(stderr, "Out of memory.\n"); - r = -ENOMEM; - goto finish; - } - - f = fopen(q, "re"); - if (!f) { - fprintf(stderr, "Failed to open %s for reading: %m\n", q); - r = -errno; - goto finish; - } - - r = get_file_version(f, &v); - fclose(f); - - if (r < 0) - goto finish; - - if (r > 0 && strncmp(v, "gummiboot ", 10) == 0) { - - r = unlink(q); - if (r < 0) { - fprintf(stderr, "Failed to remove %s: %m\n", q); - r = -errno; - free(v); - goto finish; - } else - fprintf(stderr, "Removed %s.\n", q); - } - - c++; - free(v); - } - - r = c; - -finish: - if (d) - closedir(d); - free(p); - free(q); - - return r; -} - -static int rmdir_one(const char *prefix, const char *suffix) { - char *p; - - if (asprintf(&p, "%s/%s", prefix, suffix) < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - if (rmdir(p) < 0) { - if (errno != ENOENT && errno != ENOTEMPTY) { - fprintf(stderr, "Failed to remove %s: %m\n", p); - free(p); - return -errno; - } - } else - fprintf(stderr, "Removed %s.\n", p); - - free(p); - return 0; -} - - -static int remove_binaries(const char *esp_path) { - char *p; - int r, q; - - if (asprintf(&p, "%s/EFI/gummiboot", esp_path) < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - r = rm_rf(p); - free(p); - - q = remove_boot_efi(esp_path); - if (q < 0 && r == 0) - r = q; - - q = rmdir_one(esp_path, "loader/entries"); - if (q < 0 && r == 0) - r = q; - - q = rmdir_one(esp_path, "loader"); - if (q < 0 && r == 0) - r = q; - - q = rmdir_one(esp_path, "EFI/Boot"); - if (q < 0 && r == 0) - r = q; - - q = rmdir_one(esp_path, "EFI/gummiboot"); - if (q < 0 && r == 0) - r = q; - - q = rmdir_one(esp_path, "EFI"); - if (q < 0 && r == 0) - r = q; - - return r; -} - -static int remove_variables(const uint8_t uuid[16], const char *path, bool in_order) { - uint16_t slot; - int r; - - if (!is_efi_boot()) - return 0; - - r = find_slot(uuid, path, &slot); - if (r != 1) - return 0; - - r = efi_remove_boot_option(slot); - if (r < 0) - return r; - - if (in_order) - remove_from_order(slot); - - return 0; -} - -static int install_loader_config(const char *esp_path) { - char *p = NULL; - char line[64]; - char *machine = NULL; - FILE *f; - - f = fopen("/etc/machine-id", "re"); - if (!f) - return -errno; - - if (fgets(line, sizeof(line), f) != NULL) { - char *s; - - s = strchr(line, '\n'); - if (s) - s[0] = '\0'; - if (strlen(line) == 32) - machine = line; - } - - fclose(f); - - if (!machine) - return -ESRCH; - - if (asprintf(&p, "%s/%s", esp_path, "loader/loader.conf") < 0) { - fprintf(stderr, "Out of memory.\n"); - return -ENOMEM; - } - - f = fopen(p, "wxe"); - if (f) { - fprintf(f, "#timeout 3\n"); - fprintf(f, "default %s-*\n", machine); - fclose(f); - } - - free(p); - return 0; -} - -static int help(void) { - printf("%s [COMMAND] [OPTIONS...]\n" - "\n" - "Install, update or remove the Gummiboot EFI boot loader.\n\n" - " -h --help Show this help\n" - " --version Print version\n" - " --path=PATH Path to the EFI System Partition (ESP)\n" - " --no-variables Don't touch EFI variables\n" - "\n" - "Comands:\n" - " status Show status of installed Gummiboot and EFI variables\n" - " install Install Gummiboot to the ESP and EFI variables\n" - " update Update Gummiboot in the ESP and EFI variables\n" - " remove Remove Gummiboot from the ESP and EFI variables\n", - program_invocation_short_name); - - return 0; -} - -static const char *arg_path = NULL; -static bool arg_touch_variables = true; - -static int parse_argv(int argc, char *argv[]) { - enum { - ARG_PATH = 0x100, - ARG_VERSION, - ARG_NO_VARIABLES, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "path", required_argument, NULL, ARG_PATH }, - { "no-variables", no_argument, NULL, ARG_NO_VARIABLES }, - { NULL, 0, NULL, 0 } - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - printf(VERSION "\n"); - return 0; - - case ARG_PATH: - arg_path = optarg; - break; - - case ARG_NO_VARIABLES: - arg_touch_variables = false; - break; - - case '?': - return -EINVAL; - - default: - fprintf(stderr, "Unknown option code '%c'.\n", c); - return -EINVAL; - } - } - - return 1; -} - -int main(int argc, char*argv[]) { - enum action { - ACTION_STATUS, - ACTION_INSTALL, - ACTION_UPDATE, - ACTION_REMOVE - } arg_action = ACTION_STATUS; - - static const struct { - const char* verb; - enum action action; - } verbs[] = { - { "status", ACTION_STATUS }, - { "install", ACTION_INSTALL }, - { "update", ACTION_UPDATE }, - { "remove", ACTION_REMOVE }, - }; - - uint8_t uuid[16] = ""; - uint32_t part = 0; - uint64_t pstart = 0; - uint64_t psize = 0; - unsigned int i; - int q; - int r; - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - if (argv[optind]) { - for (i = 0; i < ELEMENTSOF(verbs); i++) { - if (!streq(argv[optind], verbs[i].verb)) - continue; - arg_action = verbs[i].action; - break; - } - if (i >= ELEMENTSOF(verbs)) { - fprintf(stderr, "Unknown operation %s\n", argv[optind]); - r = -EINVAL; - goto finish; - } - } - - if (!arg_path) - arg_path = "/boot"; - - if (geteuid() != 0) { - fprintf(stderr, "Need to be root.\n"); - r = -EPERM; - goto finish; - } - - r = verify_esp(arg_path, &part, &pstart, &psize, uuid); - if (r == -ENODEV && !arg_path) - fprintf(stderr, "You might want to use --path= to indicate the path to your ESP, in case it is not mounted to /boot.\n"); - if (r < 0) - goto finish; - - switch (arg_action) { - case ACTION_STATUS: - r = status_binaries(arg_path, uuid); - if (r < 0) - goto finish; - - if (arg_touch_variables) - r = status_variables(); - break; - - case ACTION_INSTALL: - case ACTION_UPDATE: - umask(0002); - - r = install_binaries(arg_path, arg_action == ACTION_INSTALL); - if (r < 0) - goto finish; - - if (arg_action == ACTION_INSTALL) - install_loader_config(arg_path); - - if (arg_touch_variables) - r = install_variables(arg_path, - part, pstart, psize, uuid, - "/EFI/gummiboot/gummiboot" MACHINE_TYPE_NAME ".efi", - arg_action == ACTION_INSTALL); - break; - - case ACTION_REMOVE: - r = remove_binaries(arg_path); - - if (arg_touch_variables) { - q = remove_variables(uuid, "/EFI/gummiboot/gummiboot" MACHINE_TYPE_NAME ".efi", true); - if (q < 0 && r == 0) - r = q; - } - break; - } - -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/test/gummiboot.svg b/test/gummiboot.svg deleted file mode 100644 index aec7695..0000000 --- a/test/gummiboot.svg +++ /dev/null @@ -1,1327 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="295.12869" - height="245.34628" - id="svg2" - version="1.1" - inkscape:version="0.48.2 r9819" - sodipodi:docname="gummiboot.svg" - inkscape:export-filename="/home/gnokii/Downloads/gummiboot/gummiboot.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <defs - id="defs4"> - <linearGradient - inkscape:collect="always" - id="linearGradient4535"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop4537" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop4539" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4476"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop4478" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop4480" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4298"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop4300" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop4302" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4288"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop4290" /> - <stop - style="stop-color:black;stop-opacity:0;" - offset="1" - id="stop4292" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4247"> - <stop - style="stop-color:maroon;stop-opacity:1;" - offset="0" - id="stop4249" /> - <stop - style="stop-color:maroon;stop-opacity:0;" - offset="1" - id="stop4251" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4234"> - <stop - style="stop-color:white;stop-opacity:1;" - offset="0" - id="stop4236" /> - <stop - style="stop-color:white;stop-opacity:0;" - offset="1" - id="stop4238" /> - </linearGradient> - <linearGradient - id="linearGradient4226"> - <stop - style="stop-color:#999;stop-opacity:1" - offset="0" - id="stop4228" /> - <stop - id="stop4508" - offset="0.09241502" - style="stop-color:white;stop-opacity:1;" /> - <stop - style="stop-color:#999;stop-opacity:1" - offset="1" - id="stop4230" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3997"> - <stop - id="stop4001" - offset="0" - style="stop-color:#4d4d4d;stop-opacity:1" /> - <stop - id="stop3999" - offset="1" - style="stop-color:black;stop-opacity:1;" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3899"> - <stop - id="stop3903" - offset="0" - style="stop-color:#3e3e3e;stop-opacity:0;" /> - <stop - id="stop3901" - offset="1" - style="stop-color:#3e3e3e;stop-opacity:1;" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3889"> - <stop - id="stop3893" - offset="0" - style="stop-color:#3e3e3e;stop-opacity:0;" /> - <stop - id="stop3891" - offset="1" - style="stop-color:#3e3e3e;stop-opacity:1;" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3879"> - <stop - id="stop3883" - offset="0" - style="stop-color:#3e3e3e;stop-opacity:0;" /> - <stop - id="stop3881" - offset="1" - style="stop-color:#3e3e3e;stop-opacity:1;" /> - </linearGradient> - <linearGradient - id="linearGradient4140"> - <stop - style="stop-color:#333;stop-opacity:1;" - offset="0" - id="stop4142" /> - <stop - id="stop4148" - offset="0.4896037" - style="stop-color:#4d4d4d;stop-opacity:1" /> - <stop - style="stop-color:#333;stop-opacity:1;" - offset="1" - id="stop4144" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4127"> - <stop - style="stop-color:black;stop-opacity:1;" - offset="0" - id="stop4129" /> - <stop - style="stop-color:#333;stop-opacity:1" - offset="1" - id="stop4131" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4061"> - <stop - style="stop-color:#f60;stop-opacity:1;" - offset="0" - id="stop4063" /> - <stop - style="stop-color:#f60;stop-opacity:0;" - offset="1" - id="stop4065" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3213"> - <stop - style="stop-color:#500;stop-opacity:1;" - offset="0" - id="stop3215" /> - <stop - style="stop-color:#2b0000;stop-opacity:1" - offset="1" - id="stop3217" /> - </linearGradient> - <linearGradient - id="linearGradient3190"> - <stop - style="stop-color:#f60;stop-opacity:0;" - offset="0" - id="stop3192" /> - <stop - id="stop3198" - offset="0.5" - style="stop-color:#f60;stop-opacity:1;" /> - <stop - style="stop-color:#f60;stop-opacity:0;" - offset="1" - id="stop3194" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3083"> - <stop - style="stop-color:#a00;stop-opacity:1;" - offset="0" - id="stop3085" /> - <stop - style="stop-color:red;stop-opacity:1" - offset="1" - id="stop3087" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3083" - id="linearGradient3135" - x1="-155.19038" - y1="430.61288" - x2="-25.082302" - y2="464.95807" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(443.72882,-203.52067)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient3205" - gradientUnits="userSpaceOnUse" - x1="-398.54465" - y1="581.10352" - x2="-359.37869" - y2="555.38928" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient3207" - gradientUnits="userSpaceOnUse" - x1="-433.73215" - y1="585.09375" - x2="-401.41965" - y2="560.80798" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient3209" - gradientUnits="userSpaceOnUse" - x1="-453.45709" - y1="607.90222" - x2="-423.75446" - y2="587.90222" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3213" - id="linearGradient3219" - x1="216.15257" - y1="284.21103" - x2="149.5762" - y2="-0.074683182" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(115.15739,5.0507627)" /> - <filter - inkscape:collect="always" - id="filter4057" - color-interpolation-filters="sRGB"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="5.086231" - id="feGaussianBlur4059" /> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="linearGradient4067" - x1="261.48038" - y1="262.50522" - x2="-65.937302" - y2="-63.209064" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(115.15739,5.0507627)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4127" - id="linearGradient4133" - x1="108.05394" - y1="137.08904" - x2="501.89236" - y2="515.66046" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(115.15739,5.0507627)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4140" - id="linearGradient4146" - x1="298.94162" - y1="195.93752" - x2="314.65753" - y2="215.13042" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(115.15739,5.0507627)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4140" - id="linearGradient4152" - gradientUnits="userSpaceOnUse" - x1="298.94162" - y1="195.93752" - x2="314.65753" - y2="215.13042" - gradientTransform="translate(-53.53809,100.0051)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3083" - id="linearGradient4154" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(443.72882,-203.52067)" - x1="-129.6945" - y1="326.69928" - x2="-139.07919" - y2="663.8421" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4317" - gradientUnits="userSpaceOnUse" - x1="-398.54465" - y1="581.10352" - x2="-359.37869" - y2="555.38928" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4319" - gradientUnits="userSpaceOnUse" - x1="-433.73215" - y1="585.09375" - x2="-401.41965" - y2="560.80798" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4321" - gradientUnits="userSpaceOnUse" - x1="-453.45709" - y1="607.90222" - x2="-423.75446" - y2="587.90222" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4324" - gradientUnits="userSpaceOnUse" - x1="-453.45709" - y1="607.90222" - x2="-423.75446" - y2="587.90222" - gradientTransform="translate(745.15739,-317.80638)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4327" - gradientUnits="userSpaceOnUse" - x1="-433.73215" - y1="585.09375" - x2="-401.41965" - y2="560.80798" - gradientTransform="translate(745.15739,-317.80638)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4330" - gradientUnits="userSpaceOnUse" - x1="-398.54465" - y1="581.10352" - x2="-359.37869" - y2="555.38928" - gradientTransform="translate(745.15739,-317.80638)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3083" - id="linearGradient4332" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(443.72882,-203.52067)" - x1="-129.6945" - y1="326.69928" - x2="-139.07919" - y2="663.8421" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4061" - id="linearGradient4403" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(115.15739,5.0507627)" - x1="261.48038" - y1="262.50522" - x2="-65.937302" - y2="-63.209064" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4411" - gradientUnits="userSpaceOnUse" - x1="-398.54465" - y1="581.10352" - x2="-359.37869" - y2="555.38928" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4413" - gradientUnits="userSpaceOnUse" - x1="-433.73215" - y1="585.09375" - x2="-401.41965" - y2="560.80798" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4415" - gradientUnits="userSpaceOnUse" - x1="-453.45709" - y1="607.90222" - x2="-423.75446" - y2="587.90222" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4140" - id="linearGradient3059" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,-40.747352,45.32306)" - x1="298.94162" - y1="195.93752" - x2="314.65753" - y2="215.13042" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4140" - id="linearGradient3063" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,41.904236,-1.199388)" - x1="298.94162" - y1="195.93752" - x2="314.65753" - y2="215.13042" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3213" - id="linearGradient3073" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,41.904236,-1.199388)" - x1="216.15257" - y1="284.21103" - x2="149.5762" - y2="-0.074683182" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3083" - id="linearGradient3076" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,202.88632,-103.38802)" - x1="-155.19038" - y1="430.61288" - x2="-25.082302" - y2="464.95807" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4127" - id="linearGradient3079" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,41.904236,-1.199388)" - x1="108.05394" - y1="137.08904" - x2="501.89236" - y2="515.66046" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3083" - id="linearGradient3084" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,202.88632,-103.38802)" - x1="-129.6945" - y1="326.69928" - x2="-139.07919" - y2="663.8421" /> - <filter - inkscape:collect="always" - id="filter3861" - x="-0.0061426144" - width="1.0122852" - y="-0.25842857" - height="1.5168571" - color-interpolation-filters="sRGB"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.26919643" - id="feGaussianBlur3863" /> - </filter> - <filter - inkscape:collect="always" - id="filter3951" - x="-0.088288896" - width="1.1765778" - y="-0.18725839" - height="1.3745168" - color-interpolation-filters="sRGB"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="3.2523265" - id="feGaussianBlur3953" /> - </filter> - <filter - inkscape:collect="always" - id="filter3957" - x="-0.10244129" - width="1.2048826" - y="-0.14482306" - height="1.2896461" - color-interpolation-filters="sRGB"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="2.7508259" - id="feGaussianBlur3959" /> - </filter> - <filter - inkscape:collect="always" - id="filter3991" - x="-0.12006523" - width="1.2401305" - y="-0.064596489" - height="1.1291929" - color-interpolation-filters="sRGB"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="2.3246134" - id="feGaussianBlur3993" /> - </filter> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient3997" - id="radialGradient4003" - cx="110.74842" - cy="145.46278" - fx="110.74842" - fy="145.46278" - r="8.5547333" - gradientTransform="matrix(0.66713883,-0.31394736,0.35781001,0.76034708,-15.184192,69.62976)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3997" - id="linearGradient4007" - x1="-71.785713" - y1="89.147903" - x2="-70" - y2="89.147903" - gradientUnits="userSpaceOnUse" /> - <filter - inkscape:collect="always" - id="filter4020" - color-interpolation-filters="sRGB"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.38324131" - id="feGaussianBlur4022" /> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3889" - id="linearGradient4032" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-0.35714286,0.35714286)" - x1="297.38904" - y1="287.81311" - x2="327.66589" - y2="287.81311" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3879" - id="linearGradient4034" - gradientUnits="userSpaceOnUse" - x1="297.01022" - y1="296.93698" - x2="328.17096" - y2="296.93698" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3899" - id="linearGradient4036" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-2.1428571,-1.4285714)" - x1="297.26276" - y1="305.87143" - x2="328.04468" - y2="305.87143" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3889" - id="linearGradient4052" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-0.35714286,0.35714286)" - x1="297.38904" - y1="287.81311" - x2="327.66589" - y2="287.81311" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3879" - id="linearGradient4054" - gradientUnits="userSpaceOnUse" - x1="297.01022" - y1="296.93698" - x2="328.17096" - y2="296.93698" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3899" - id="linearGradient4056" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-2.1428571,-1.4285714)" - x1="297.26276" - y1="305.87143" - x2="328.04468" - y2="305.87143" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4120" - gradientUnits="userSpaceOnUse" - x1="-398.54465" - y1="581.10352" - x2="-359.37869" - y2="555.38928" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4122" - gradientUnits="userSpaceOnUse" - x1="-433.73215" - y1="585.09375" - x2="-401.41965" - y2="560.80798" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4124" - gradientUnits="userSpaceOnUse" - x1="-453.45709" - y1="607.90222" - x2="-423.75446" - y2="587.90222" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4128" - gradientUnits="userSpaceOnUse" - x1="-453.45709" - y1="607.90222" - x2="-423.75446" - y2="587.90222" - gradientTransform="matrix(0.48994548,0,0,0.48994548,350.56989,-159.38179)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4131" - gradientUnits="userSpaceOnUse" - x1="-433.73215" - y1="585.09375" - x2="-401.41965" - y2="560.80798" - gradientTransform="matrix(0.48994548,0,0,0.48994548,350.56989,-159.38179)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3190" - id="linearGradient4134" - gradientUnits="userSpaceOnUse" - x1="-398.54465" - y1="581.10352" - x2="-359.37869" - y2="555.38928" - gradientTransform="matrix(0.48994548,0,0,0.48994548,350.56989,-159.38179)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3889" - id="linearGradient4136" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-0.35714286,0.35714286)" - x1="297.38904" - y1="287.81311" - x2="327.66589" - y2="287.81311" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3879" - id="linearGradient4138" - gradientUnits="userSpaceOnUse" - x1="297.01022" - y1="296.93698" - x2="328.17096" - y2="296.93698" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3899" - id="linearGradient4141" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-2.1428571,-1.4285714)" - x1="297.26276" - y1="305.87143" - x2="328.04468" - y2="305.87143" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3899" - id="linearGradient4144" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-30.427128,-201.43877)" - x1="297.26276" - y1="305.87143" - x2="328.04468" - y2="305.87143" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3879" - id="linearGradient4147" - gradientUnits="userSpaceOnUse" - x1="297.01022" - y1="296.93698" - x2="328.17096" - y2="296.93698" - gradientTransform="translate(-28.284271,-200.0102)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3889" - id="linearGradient4150" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-28.641414,-199.65306)" - x1="297.38904" - y1="287.81311" - x2="327.66589" - y2="287.81311" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3889" - id="linearGradient4155" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-0.35714286,0.35714286)" - x1="297.38904" - y1="287.81311" - x2="327.66589" - y2="287.81311" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3879" - id="linearGradient4157" - gradientUnits="userSpaceOnUse" - x1="297.01022" - y1="296.93698" - x2="328.17096" - y2="296.93698" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3899" - id="linearGradient4159" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-2.1428571,-1.4285714)" - x1="297.26276" - y1="305.87143" - x2="328.04468" - y2="305.87143" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3899" - id="linearGradient4162" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-0.52943173,0.84835255,0.84835255,0.52943173,-17.10484,-212.31631)" - x1="297.26276" - y1="305.87143" - x2="328.04468" - y2="305.87143" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3879" - id="linearGradient4165" - gradientUnits="userSpaceOnUse" - x1="297.01022" - y1="296.93698" - x2="328.17096" - y2="296.93698" - gradientTransform="matrix(-0.52943173,0.84835255,0.84835255,0.52943173,-17.027404,-209.74208)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3889" - id="linearGradient4168" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-0.52943173,0.84835255,0.84835255,0.52943173,-16.535338,-209.85598)" - x1="297.38904" - y1="287.81311" - x2="327.66589" - y2="287.81311" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3083" - id="linearGradient4173" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,174.76488,-111.73254)" - x1="-129.6945" - y1="326.69928" - x2="-139.07919" - y2="663.8421" /> - <filter - inkscape:collect="always" - id="filter4184"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="3.4423031" - id="feGaussianBlur4186" /> - </filter> - <filter - inkscape:collect="always" - id="filter4216"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="1.9124443" - id="feGaussianBlur4218" /> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4226" - id="linearGradient4232" - x1="201.85893" - y1="201.62338" - x2="88.238426" - y2="29.098005" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4234" - id="radialGradient4240" - cx="135.30005" - cy="59.140411" - fx="135.30005" - fy="59.140411" - r="40.136741" - gradientTransform="matrix(1,0,0,0.81698548,0,17.046426)" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4247" - id="linearGradient4253" - x1="35.157597" - y1="70.196426" - x2="56.52232" - y2="71.26786" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4247" - id="linearGradient4260" - x1="150.62947" - y1="234.53995" - x2="138.9509" - y2="183.46852" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4247" - id="linearGradient4264" - gradientUnits="userSpaceOnUse" - x1="95.629471" - y1="249.89709" - x2="231.09375" - y2="177.03995" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4247" - id="linearGradient4271" - x1="128.5759" - y1="222.77562" - x2="129.52232" - y2="201.34705" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4247" - id="linearGradient4278" - x1="213.71428" - y1="172.97545" - x2="201.10735" - y2="166.54688" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4288" - id="radialGradient4294" - cx="132.05447" - cy="100.1967" - fx="132.05447" - fy="100.1967" - r="25.40625" - gradientTransform="matrix(0.83734013,-0.54668227,1.2370409,1.8947461,-102.46746,-27.168077)" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4298" - id="radialGradient4304" - cx="123.48306" - cy="113.45441" - fx="123.48306" - fy="113.45441" - r="25.40625" - gradientTransform="matrix(0.82472039,-0.5655407,1.2510982,1.8244597,-120.29854,-30.956633)" - gradientUnits="userSpaceOnUse" /> - <filter - inkscape:collect="always" - id="filter4310"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.31593749" - id="feGaussianBlur4312" /> - </filter> - <filter - inkscape:collect="always" - id="filter4330"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.3159375" - id="feGaussianBlur4332" /> - </filter> - <filter - inkscape:collect="always" - id="filter4400" - x="-0.34000003" - width="1.6800001" - y="-0.1115625" - height="1.223125"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="1.5026018" - id="feGaussianBlur4402" /> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4140" - id="linearGradient4406" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,-40.747352,45.32306)" - x1="298.94162" - y1="195.93752" - x2="314.65753" - y2="215.13042" /> - <filter - inkscape:collect="always" - id="filter4472" - x="-0.15124256" - width="1.3024851" - y="-0.11710123" - height="1.2342025"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.72078202" - id="feGaussianBlur4474" /> - </filter> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4476" - id="radialGradient4482" - cx="110.59362" - cy="145.605" - fx="110.59362" - fy="145.605" - r="7.4487594" - gradientTransform="matrix(1,0,0,1.2238444,0,-32.592856)" - gradientUnits="userSpaceOnUse" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient4476" - id="radialGradient4486" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1,0,0,1.2238444,82.57997,-79.312411)" - cx="110.59362" - cy="145.605" - fx="110.59362" - fy="145.605" - r="7.4487594" /> - <filter - inkscape:collect="always" - id="filter4502" - x="-0.25105351" - width="1.502107" - y="-0.026536847" - height="1.0530737"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.79301865" - id="feGaussianBlur4504" /> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3213" - id="linearGradient4519" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.48994548,0,0,0.48994548,41.904236,-1.199388)" - x1="216.15257" - y1="284.21103" - x2="149.5762" - y2="-0.074683182" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4535" - id="linearGradient4541" - x1="171.71072" - y1="169.34375" - x2="200.78407" - y2="142.91518" - gradientUnits="userSpaceOnUse" /> - </defs> - <sodipodi:namedview - id="base" - pagecolor="#ffffff" - bordercolor="#666666" - borderopacity="1.0" - inkscape:pageopacity="0.0" - inkscape:pageshadow="2" - inkscape:zoom="0.9899495" - inkscape:cx="151.67058" - inkscape:cy="130.22692" - inkscape:document-units="px" - inkscape:current-layer="layer1" - showgrid="false" - inkscape:window-width="1280" - inkscape:window-height="965" - inkscape:window-x="0" - inkscape:window-y="27" - inkscape:window-maximized="1" - fit-margin-top="20" - fit-margin-right="20" - fit-margin-bottom="20" - fit-margin-left="20" - inkscape:showpageshadow="false" - borderlayer="true" - showguides="true" - inkscape:guide-bbox="true" /> - <metadata - id="metadata7"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> - </cc:Work> - </rdf:RDF> - </metadata> - <g - inkscape:label="Ebene 1" - inkscape:groupmode="layer" - id="layer1" - transform="translate(-28.121442,-8.3445206)"> - <path - style="opacity:0.5;fill:black;stroke:none;filter:url(#filter4184)" - d="m 119.13037,34.558806 c -6.46995,0.102869 -12.93557,1.164239 -19.125,3.25 -7.073636,2.257821 -13.06569,7.125218 -17.749999,12.78125 -13.954711,17.440697 -17.137321,41.958601 -12.0625,63.281254 6.826837,18.85682 15.530888,37.16266 26.21875,54.21875 -0.992147,1.64344 -1.626584,2.68403 -2,3.15625 l -1.5625,-0.15625 -0.65625,1.28125 c -0.0097,0.01 -0.02246,-0.0103 -0.03125,0 -0.48075,0.50119 -0.495877,0.70011 -0.15625,1.5 l 0.375,0.90625 -2.90625,4.625 c -2.464107,3.90972 -3.013095,4.6489 -3.40625,4.65625 -0.256449,0.005 -0.604724,0.21991 -0.78125,0.5 -0.176987,0.27982 -0.628647,0.67362 -1,0.84375 -0.451297,0.20673 -0.976977,0.77897 -1.59375,1.75 -0.838625,1.32056 -0.986193,1.45743 -1.59375,1.40625 -0.404286,-0.0341 -0.875575,0.13221 -1.21875,0.46875 -0.705691,0.69205 -1.678336,1.1556 -4.375,2.0625 -2.40709,0.80951 -5.417848,2.20923 -8,3.6875 -4.890367,2.25417 -13.565719,12.51622 -17.28125,18.53125 -0.530479,0.85948 -0.946652,1.63187 -1.25,2.28125 -0.896073,1.90319 -2.299489,6.22356 -2.28125,7.03125 1.412554,5.50433 16.597841,15.78411 25.03125,15.78125 0.736522,-0.332 4.044644,-3.46426 5.375,-5.09375 0.454909,-0.55384 0.953779,-1.27543 1.5,-2.125 3.823544,-5.94696 9.357354,-18.17817 9.28125,-23.5625 0.219652,-2.96725 0.151892,-6.2917 -0.15625,-8.8125 -0.345215,-2.82406 -0.351119,-3.90855 -0.03125,-4.84375 0.155594,-0.45476 0.14264,-0.96247 -0.0625,-1.3125 -0.308338,-0.52604 -0.266924,-0.7049 0.5625,-2.03125 0.609885,-0.97538 0.914412,-1.72243 0.90625,-2.21875 -0.0067,-0.40841 0.135983,-0.96991 0.3125,-1.25 0.176976,-0.27981 0.231314,-0.70407 0.125,-0.9375 -0.162999,-0.35786 0.254635,-1.15279 2.71875,-5.0625 l 2.9375,-4.625 0.96875,-0.0312 c 0.868137,-0.0387 1.036509,-0.13131 1.28125,-0.78125 0.0046,-0.013 -0.0054,-0.0187 0,-0.0312 l 0.875,-1.15625 -0.84375,-1.34375 c 0.178207,-0.36368 0.557982,-0.96013 1.0625,-1.75 4.099979,6.32493 8.499389,12.45778 13.156249,18.375 0.48509,0.61645 0.97761,1.2322 1.46875,1.84375 1.8736,2.33253 3.78752,4.64786 5.75,6.90625 0.74439,0.85673 1.52399,1.71693 2.28125,2.5625 1.75433,1.95812 3.55158,3.88531 5.375,5.78125 0.0817,0.0849 0.16818,0.1652 0.25,0.25 2.54216,2.63479 5.13572,5.21231 7.8125,7.71875 8.50027,9.95425 22.88939,10.296 34.75,7.875 10.57416,-3.28393 20.74676,-8.10548 30.71875,-12.96875 9.02977,-5.71216 19.12361,-10.46239 26.09375,-18.78125 7.1065,-6.63597 9.36094,-16.9079 7.03125,-26.15625 -0.87215,-3.12221 -1.80086,-6.24194 -2.78125,-9.34375 -0.28444,-0.89998 -0.58127,-1.78975 -0.875,-2.6875 -2.35945,-7.21433 -5.0026,-14.36085 -7.96875,-21.375 -0.31468,-0.74302 -0.64712,-1.47864 -0.96875,-2.21875 -3.80762,-8.77496 -8.09911,-17.34196 -12.90625,-25.59375 8.25065,-0.11748 15.08852,-0.25018 17.40625,-0.3125 2.61172,-0.0703 3.92372,-0.072 4.625,0 l 0.71875,1.40625 1.40625,-0.125 c 0.0134,0.002 0.0178,-0.003 0.0312,0 0.68095,0.13647 0.85132,0.0598 1.34375,-0.65625 l 0.5625,-0.8125 5.46875,-0.0312 c 4.6214,-0.0205 5.53271,0.0473 5.75,0.375 0.14175,0.21378 0.51268,0.377 0.84375,0.375 0.33107,-0.001 0.90709,0.18431 1.25,0.40625 0.41673,0.26969 1.19339,0.40725 2.34375,0.40625 1.56434,-0.001 1.74823,0.0537 2.03125,0.59375 0.18834,0.35935 0.59432,0.67248 1.0625,0.78125 0.96273,0.22376 1.88072,0.77449 4.09375,2.5625 1.97538,1.596 4.74144,3.39664 7.375,4.78125 4.52752,2.9152 17.86807,4.7202 24.9375,4.625 1.00992,-0.0136 1.88305,-0.0635 2.59375,-0.15625 2.08671,-0.26591 6.48466,-1.42594 7.15625,-1.875 4.46734,-7.15299 3.79676,-25.449994 -0.125,-29.562504 -0.67555,-0.44309 -5.06727,-1.56508 -7.15625,-1.8125 -0.71151,-0.08646 -1.61501,-0.12 -2.625,-0.125 -7.06999,-0.03247 -20.37356,1.85717 -24.875,4.8125 -2.62117,1.40793 -5.38261,3.26152 -7.34375,4.875 -2.19707,1.80758 -3.10178,2.36147 -4.0625,2.59375 -0.46719,0.11296 -0.87737,0.42023 -1.0625,0.78125 -0.27824,0.54252 -0.46695,0.6127 -2.03125,0.625 -1.15031,0.0091 -1.92944,0.16409 -2.34375,0.4375 -0.34093,0.22497 -0.88766,0.40425 -1.21875,0.40625 -0.33107,0.0015 -0.73516,0.15998 -0.875,0.375 -0.21439,0.32964 -1.09735,0.417 -5.71875,0.4375 l -5.5,0 -0.5625,-0.8125 c -0.49878,-0.71161 -0.63279,-0.7675 -1.3125,-0.625 -0.0134,0.002 -0.0177,-0.003 -0.0312,0 l -1.4375,-0.125 -0.6875,1.40625 c -0.70061,0.0782 -2.01276,0.07825 -4.625,0.03125 -2.52621,-0.04549 -10.51861,-0.07748 -19.84375,-0.125 -10.99838,-18.001163 -24.49526,-34.379543 -40.75,-48 -12.29389,-11.240981 -28.87193,-17.262888 -45.40625,-17 z" - id="path4058" - inkscape:connector-curvature="0" /> - <path - style="fill:url(#linearGradient3084);stroke:none" - d="m 101.4278,33.103606 c 22.00686,-7.41604 47.43988,-1.904589 64.54442,13.735037 34.53894,28.941476 56.68428,70.344647 68.6772,113.278217 2.32969,9.24835 0.0805,19.51595 -7.026,26.15192 -6.97014,8.31886 -17.07619,13.08807 -26.10596,18.80023 -9.97199,4.86327 -20.14535,9.69152 -30.71951,12.97545 -11.86061,2.421 -26.24237,2.07569 -34.74264,-7.87856 C 106.58411,182.57008 85.298526,146.92722 71.619341,109.14311 66.54452,87.820461 69.73869,63.30161 83.693401,45.860913 88.37771,40.204881 94.354163,35.361427 101.4278,33.103606 z" - id="path3060" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.50914636;fill:url(#linearGradient4403);stroke:none;filter:url(#filter4057)" - d="m 275.09489,77.582013 c -25.48954,-0.0341 -53.23884,9.303263 -67.65625,31.593747 -29.34598,40.0012 -31.35591,96.06645 -10.15625,140.1875 28.40061,68.57333 69.87976,132.82934 125.71875,181.875 18.83018,13.75543 44.70925,9.94441 65.2843,2.19161 31.84184,-12.08972 63.14991,-27.48346 89.54425,-49.21364 12.02569,-9.65157 21.4953,-23.66814 20.54645,-39.57172 C 497.25128,329.51069 490.84796,315.277 486.42547,300.85528 459.98101,225.34605 416.99674,153.47738 353.15739,103.55076 331.45029,85.766501 303.01267,77.038582 275.09489,77.582013 z m 18.5,35.281247 c 33.49963,-0.16647 62.76474,21.30865 82.35166,46.955 33.60869,44.23485 60.18853,94.91388 70.61709,149.82625 1.85099,21.10638 -10.76826,41.10271 -28.34873,51.8572 -14.67831,10.02452 -31.37172,18.53922 -49.05752,21.11155 -20.86965,1.52845 -39.4515,-10.98641 -52.66421,-26.00796 -21.68266,-22.65013 -40.72161,-47.99611 -57.53199,-74.53539 -19.73396,-32.86952 -33.92671,-71.75049 -28.21005,-110.6754 5.66976,-29.99665 30.88766,-57.96287 62.84375,-58.53125 z" - id="path3225" - inkscape:connector-curvature="0" - transform="matrix(0.48994548,0,0,0.48994548,-14.516607,-3.6739864)" /> - <path - style="fill:url(#linearGradient3079);stroke:none;stroke-width:0.48994546999999999" - d="m 122.62713,32.816827 c -0.45601,-0.0029 -0.92372,0.0078 -1.37797,0.01529 -7.61411,0.125372 -14.95375,1.734064 -21.312631,5.220981 -14.297942,7.840331 -19.751829,27.814615 -21.282007,44.049159 -2.628651,27.888823 9.472253,55.994813 21.771948,81.162523 3.11536,6.37465 6.12356,12.07802 9.09462,17.13279 0.004,0.006 0.011,0.01 0.0153,0.0153 6.60116,8.82634 13.79399,17.19442 21.60354,24.98722 3.86943,2.36591 7.93954,3.84064 12.35581,4.3942 21.58464,2.70555 39.79412,1.82298 55.42508,-8.42094 16.71358,-10.95342 36.39004,-31.21492 32.94884,-50.58687 -5.13967,-16.26239 -11.79429,-32.17661 -20.05715,-47.15725 -0.0645,-0.11087 -0.11898,-0.226 -0.18373,-0.33684 C 197.79062,79.603321 179.38585,56.647788 162.78732,45.478804 151.65959,37.991067 136.76345,32.908961 122.6271,32.816778 z m -5.68031,1.454525 c 14.68779,0.138366 30.82466,9.423631 44.01854,17.086847 32.65271,18.965206 59.81676,65.422781 67.22971,96.840791 4.4609,18.90644 -13.38155,41.90571 -29.73395,52.62243 -14.93666,9.7889 -33.81894,7.65402 -54.44481,5.06865 -16.13613,-2.0226 -27.54641,-16.60043 -41.15542,-44.44725 C 91.10753,137.39303 82.58703,110.70225 84.533868,84.368276 85.779304,67.521824 88.362194,45.064993 103.38146,37.333512 c 3.8426,-1.978062 7.92469,-2.913035 12.14146,-3.046849 0.47062,-0.01494 0.9501,-0.01979 1.4239,-0.01529 z" - id="path3067" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ssssscccssccsssssssssssss" /> - <path - style="fill:url(#linearGradient3076);fill-opacity:1" - d="m 170.48143,170.96997 c 7.9039,-2.80386 9.4391,-3.71745 14.76747,-8.78809 5.28084,-5.0254 5.88037,-6.37731 5.03237,-11.34777 -0.54581,-3.19924 -2.12664,-8.17139 -2.93655,-9.23632 -0.20744,-0.27274 -2.09771,-3.80302 -4.20062,-7.84507 -10.31205,-19.82106 -24.17432,-40.715325 -32.77801,-49.405517 -4.77866,-4.826708 -10.87279,-7.384017 -20.27372,-8.507565 -4.91187,-0.587038 -7.50695,0.407973 -11.5781,4.439293 -5.19358,5.142772 -6.33742,9.372628 -5.017,18.552643 1.9554,13.594616 10.06269,31.133146 21.57803,46.679836 5.80487,7.83707 8.51242,11.05372 16.21908,19.26876 3.91594,4.17426 9.72372,8.27527 11.84917,8.36698 0.5887,0.0254 3.89075,-0.95433 7.33788,-2.17718 z" - id="path3115" - inkscape:connector-curvature="0" /> - <path - style="fill:url(#linearGradient4519)" - d="m 130.84074,58.923726 c -7.60891,-0.350673 -14.85403,3.428624 -19.50456,9.363275 -7.15812,7.872993 -8.76006,19.344218 -6.92564,29.513125 1.31869,14.540904 8.47163,27.606394 15.84606,39.895614 6.45437,9.19151 13.24056,18.21299 20.7056,26.61653 6.38854,6.86584 13.60394,15.25582 23.86911,15.08518 8.33851,-0.68382 15.73802,-5.30641 22.649,-9.67979 6.8134,-4.37968 12.0669,-12.08126 10.81292,-20.48258 -1.3419,-9.21799 -4.87937,-17.96964 -8.13844,-26.64906 -5.23797,-11.46211 -10.79354,-22.815147 -18.03913,-33.159679 -8.50676,-12.978882 -19.6145,-26.077692 -35.39552,-29.783007 -1.92747,-0.443852 -3.90128,-0.691455 -5.8794,-0.719608 z m -3.41428,17.117471 c 9.47621,0.329223 19.44533,3.578248 25.36433,11.405622 14.22558,16.928041 24.97515,36.420361 35.14857,55.949291 1.35182,4.42143 3.75936,9.50153 1.69397,14.03969 -4.51526,5.99515 -10.52686,11.23752 -17.86566,13.37943 -4.9001,2.08509 -10.68904,4.17452 -14.83439,-0.57642 -9.1776,-7.5501 -16.59474,-17.02466 -23.58578,-26.57917 -9.84934,-14.24824 -18.48273,-30.22495 -20.35268,-47.705266 -0.90187,-5.951667 1.33796,-12.074001 6.00755,-15.910788 2.25429,-2.228885 5.12844,-4.095401 8.42409,-4.002389 z" - id="path3129" - inkscape:connector-curvature="0" /> - <path - style="fill:url(#radialGradient4240);filter:url(#filter4216);opacity:0.20000000000000001;fill-opacity:1" - d="m 128.4375,65 c -7.55257,0.752539 -13.75463,6.817427 -16.5625,13.71875 5.8224,-8.006494 16.76877,-10.73731 25.9375,-7.40625 14.07275,3.2128 23.28411,15.378897 30.59375,26.90625 5.17978,7.51743 10.0853,15.15976 14.5625,23.125 C 173.38287,101.9067 163.01642,80.924945 144.28125,69 139.39108,66.242245 134.02863,64.603592 128.4375,65 z" - id="path4188" - inkscape:connector-curvature="0" /> - <path - sodipodi:nodetypes="cacac" - inkscape:connector-curvature="0" - id="path3995" - d="m 168.1904,63.422847 c 0,0 19.65859,24.838941 27.77919,38.385793 10.385,17.32433 26.55208,54.46844 26.55208,54.46844 0,0 -11.10228,-38.91122 -21.50132,-55.98367 C 192.45975,86.239191 168.1904,63.422847 168.1904,63.422847 z" - style="opacity:0.45;fill:white;stroke:none;filter:url(#filter3991)" - transform="matrix(-0.53741363,0.8433188,0.8433188,0.53741363,127.92952,-82.227985)" /> - <path - style="fill:url(#radialGradient4003);fill-opacity:1" - d="m 107.75379,134.95077 c -1.30345,0.0904 -2.48714,0.63971 -3.65929,1.65357 -1.83229,1.58486 -1.9196,1.78945 -1.89853,4.53199 0.0379,4.93646 3.957,11.76337 7.97692,13.8869 0.98849,0.52216 2.12208,0.9586 2.52628,0.96458 1.41684,0.021 4.83158,-1.8527 5.43534,-2.98561 1.19295,-2.06862 1.40968,-5.12061 0.93395,-7.54822 -0.74195,-3.57395 -3.96059,-7.91748 -6.9511,-9.40083 -1.64938,-0.81813 -3.06013,-1.1928 -4.36357,-1.10238 z" - id="path3139" - inkscape:connector-curvature="0" - sodipodi:nodetypes="sssscccss" /> - <path - style="opacity:0.45;fill:white;stroke:none;filter:url(#filter3991)" - d="m 162.83326,57.708561 c 0,0 24.19388,28.033804 33.13633,44.100079 8.34768,14.99769 18.68782,47.98225 18.68782,47.98225 0,0 -5.43338,-34.47799 -13.63706,-49.49748 -9.13959,-16.732981 -38.18709,-42.584849 -38.18709,-42.584849 z" - id="path3961" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cacac" /> - <path - sodipodi:nodetypes="sssscccss" - inkscape:connector-curvature="0" - id="path3148" - d="m 185.20338,91.946502 c 0.70476,-1.100206 1.75466,-1.875158 3.20661,-2.417072 2.26969,-0.847116 2.49109,-0.825543 4.88717,0.508897 4.31286,2.401947 8.42201,9.116165 8.35622,13.662023 -0.0162,1.11781 -0.1772,2.32179 -0.36591,2.67929 -0.6614,1.25316 -3.94383,3.35005 -5.2275,3.33616 -2.38735,0.0541 -5.16903,-1.22024 -7.07065,-2.80247 -2.77963,-2.36585 -5.04606,-7.273929 -4.91255,-10.609444 0.0736,-1.839671 0.42184,-3.257182 1.12661,-4.357384 z" - style="fill:url(#linearGradient4007);fill-opacity:1" /> - <g - id="g3200" - transform="matrix(0.48994548,0,0,0.48994548,350.56989,-159.38179)" - style="opacity:0.5"> - <path - inkscape:connector-curvature="0" - id="path3166" - d="m -455.20089,479.79464 c -1.17062,0.0161 -2.27669,0.1147 -3.34375,0.28125 l 120.71875,176.625 c 0.14376,-0.13638 0.25973,-0.23557 0.40625,-0.375 10.77843,-10.25706 11.9808,-13.01132 10.25,-23.15625 -1.11402,-6.52979 -4.31568,-16.67019 -5.96875,-18.84375 -0.42338,-0.55668 -4.30163,-7.78125 -8.59375,-16.03125 -0.36367,-0.69901 -0.7571,-1.39357 -1.125,-2.09375 l -70.1875,-102.71875 c -9.0802,-7.31226 -20.55483,-11.4133 -36.96875,-13.375 -1.87975,-0.22466 -3.5892,-0.33445 -5.1875,-0.3125 z" - style="fill:url(#linearGradient4411);fill-opacity:1" /> - <path - inkscape:connector-curvature="0" - id="path3164" - d="m -463.45089,481.51339 c -3.25944,1.45791 -6.41012,3.91583 -10.1875,7.65625 -5.30016,5.24831 -8.52193,10.03124 -10.09375,15.84375 l 115.78125,169.375 c 0.12815,-0.0452 0.24662,-0.0795 0.375,-0.125 13.96734,-4.95482 18.21591,-7.03738 26.15625,-14.21875 L -463.45089,481.51339 z" - style="fill:url(#linearGradient4413);fill-opacity:1" /> - <path - inkscape:connector-curvature="0" - id="path3150" - d="m -484.76339,511.38839 c -0.31802,4.40449 -0.012,9.45827 0.875,15.625 3.99106,27.7472 20.55919,63.54978 44.0625,95.28125 11.84799,15.9958 17.36412,22.5765 33.09375,39.34375 7.9926,8.51985 19.84936,16.87532 24.1875,17.0625 0.9231,0.0398 5.13529,-1.13592 10.21875,-2.8125 l -112.4375,-164.5 z" - style="fill:url(#linearGradient4415);fill-opacity:1" /> - </g> - <path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:black;fill:url(#linearGradient4232);fill-opacity:1;stroke:none;stroke-width:0.48994546999999999;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 122.1875,32.5625 c -0.31633,0.0028 -0.62844,0.02615 -0.9375,0.03125 -7.64601,0.125897 -15.03679,1.740145 -21.4375,5.25 -14.428716,7.912041 -19.87273,27.980004 -21.40625,44.25 -2.636685,27.97406 9.509045,56.10585 21.8125,81.28125 3.11737,6.37875 6.1185,12.09436 9.09375,17.15625 0.0493,0.0739 0.0709,0.0801 0.0312,0.0312 6.6078,8.83522 13.80662,17.19839 21.625,25 l 0.0312,0.0312 c 3.896,2.38216 8.01763,3.87957 12.46875,4.4375 21.60803,2.70848 39.89523,1.85069 55.59375,-8.4375 8.37785,-5.49051 17.4922,-13.33121 24.09375,-22.21875 6.60155,-8.88754 10.70599,-18.84538 8.96875,-28.625 l -0.0312,-0.0312 c -5.14414,-16.27654 -11.79107,-32.22257 -20.0625,-47.21875 -0.0576,-0.099 -0.11567,-0.22079 -0.1875,-0.34375 C 197.99264,79.445011 179.59543,56.490203 162.9375,45.28125 151.76835,37.765645 136.81894,32.655059 122.625,32.5625 l -0.4375,0 z m -0.9375,0.5 c 0.45532,-0.0075 0.92389,-0.0029 1.375,0 14.07876,0.09181 28.94494,5.165131 40.03125,12.625 16.53913,11.129015 34.92479,34.051851 48.75,57.71875 0.0577,0.0987 0.11608,0.22099 0.1875,0.34375 8.24952,14.95646 14.89727,30.85529 20.03125,47.09375 0.002,0.0103 -0.002,0.0209 0,0.0312 1.68984,9.58256 -2.32728,19.40368 -8.875,28.21875 -6.55477,8.82455 -15.63302,16.59959 -23.96875,22.0625 -15.5634,10.19965 -33.68875,11.10887 -55.25,8.40625 -4.36748,-0.54744 -8.38691,-2.0072 -12.21875,-4.34375 -0.0104,-0.0104 -0.0208,-0.0208 -0.0312,-0.0312 -7.78865,-7.77512 -14.9768,-16.10058 -21.5625,-24.90625 -0.004,-0.007 0.004,-0.024 0,-0.0312 -2.96275,-5.0423 -5.95358,-10.73229 -9.0625,-17.09375 C 88.360315,137.99623 76.285633,109.92859 78.90625,82.125 80.433086,65.925908 85.895332,46.049871 100.0625,38.28125 106.37955,34.817271 113.66779,33.187347 121.25,33.0625 z m -5.75,0.96875 c -4.24792,0.134802 -8.34131,1.097752 -12.21875,3.09375 -7.590368,3.9073 -12.029451,11.529539 -14.71875,20.25 -2.689299,8.720461 -3.658204,18.541088 -4.28125,26.96875 -1.95161,26.39852 6.610753,53.14668 18.375,77.21875 6.80896,13.93252 13.05934,24.52995 19.65625,31.9375 6.59691,7.40755 13.55444,11.60555 21.6875,12.625 20.62766,2.58559 39.56427,4.75598 54.59375,-5.09375 8.20923,-5.38001 16.78156,-13.82578 22.75,-23.3125 5.96844,-9.48672 9.34606,-20.01662 7.09375,-29.5625 -7.43127,-31.49566 -34.59182,-77.977165 -67.34375,-97 -13.19458,-7.663622 -29.36692,-16.985677 -44.15625,-17.125 -0.083,-7.88e-4 -0.16677,2.15e-4 -0.25,0 -0.39536,-0.001 -0.79576,-0.01244 -1.1875,0 z m 0.0312,0.5 c 0.46703,-0.01483 0.93569,-0.0045 1.40625,0 14.58625,0.137409 30.71307,9.36844 43.90625,17.03125 32.55349,18.907577 59.73037,65.34714 67.125,96.6875 2.20859,9.36056 -1.10559,19.76879 -7.03125,29.1875 -5.92566,9.41871 -14.48183,17.85079 -22.625,23.1875 -14.84384,9.72807 -33.65717,7.6164 -54.28125,5.03125 -8.00307,-1.00315 -14.79923,-5.12003 -21.34375,-12.46875 -6.54452,-7.34872 -12.7937,-17.92945 -19.59375,-31.84375 C 91.351277,137.31624 82.839184,110.64443 84.78125,84.375 85.40364,75.95621 86.362928,66.152438 89.03125,57.5 91.699572,48.847562 96.071102,41.386681 103.5,37.5625 c 3.80776,-1.960126 7.84563,-2.898424 12.03125,-3.03125 z" - id="path4220" - inkscape:connector-curvature="0" /> - <g - id="g4024" - transform="translate(-28.284271,-200.0102)"> - <path - style="fill:#1a1a1a" - d="m 318.53887,279.75654 c 1.00999,0.005 1.89177,0.0482 2.60328,0.13466 2.08898,0.24742 6.49786,1.35249 7.17341,1.79558 3.92176,4.11251 4.59865,22.42631 0.13131,29.5793 -0.67159,0.44906 -5.07047,1.5933 -7.15718,1.85921 -0.7107,0.0927 -1.59206,0.14415 -2.60198,0.15775 -7.06943,0.0952 -20.39523,-1.69296 -24.92275,-4.60816 -2.63356,-1.38461 -5.42336,-3.18744 -7.39874,-4.78344 -2.21303,-1.78801 -3.11021,-2.35716 -4.07294,-2.58092 -0.46818,-0.10877 -0.89474,-0.41554 -1.08308,-0.77489 -0.28302,-0.54008 -0.46902,-0.59343 -2.03336,-0.592 -1.15036,0.001 -1.92427,-0.13413 -2.341,-0.40382 -0.34291,-0.22194 -0.89816,-0.4021 -1.22923,-0.40064 -0.33107,0.002 -0.71467,-0.17225 -0.85642,-0.38603 -0.21729,-0.32774 -1.11898,-0.38489 -5.74038,-0.36438 l -5.48162,0.0243 -0.55547,0.81465 c -0.49243,0.71601 -0.65283,0.79214 -1.33378,0.65567 -0.0135,-0.003 -0.0187,-0.006 -0.0321,-0.008 l -1.42609,0.12817 -0.70028,-1.40198 c -0.70128,-0.072 -2.01523,-0.0578 -4.62695,0.0125 -7.97877,0.21454 -64.83584,0.92806 -76.08428,0.95504 -8.76866,0.0211 -10.16589,-0.0269 -10.43811,-0.36787 -0.27961,-0.35014 -0.36962,-1.21907 -0.28528,-2.01296 -0.0917,-0.79356 -0.009,-1.66255 0.2674,-2.01541 0.26919,-0.34333 1.66593,-0.40374 10.43442,-0.46054 11.24824,-0.0729 68.10941,0.13575 76.08977,0.27946 2.61224,0.047 3.92627,0.0496 4.62688,-0.0286 l 0.68781,-1.40814 1.42719,0.11514 c 0.0136,-0.003 0.0187,-0.006 0.0321,-0.008 0.67971,-0.1425 0.84077,-0.0678 1.33955,0.64381 l 0.56269,0.80969 5.48161,-0.0243 c 4.6214,-0.0205 5.52254,-0.0857 5.73693,-0.41534 0.13984,-0.21502 0.52188,-0.39216 0.85295,-0.39363 0.33109,-0.002 0.88469,-0.18656 1.22562,-0.41153 0.41431,-0.27341 1.18701,-0.41544 2.33732,-0.42459 1.5643,-0.0123 1.7498,-0.0675 2.02804,-0.61002 0.18513,-0.36102 0.60895,-0.67153 1.07614,-0.78449 0.96072,-0.23228 1.8528,-0.8094 4.04987,-2.61698 1.96114,-1.61348 4.73481,-3.44101 7.35598,-4.84894 4.50144,-2.95533 17.81085,-4.86179 24.88084,-4.82932 z" - id="path4285" - inkscape:connector-curvature="0" - sodipodi:nodetypes="sccccscssssssssccccccssscsssccccccsssssssscs" /> - <path - inkscape:connector-curvature="0" - id="path3087" - d="m 169.10714,296.11219 105,-0.17858 -0.35714,1.42858 -104.82143,1.07142 z" - style="opacity:0.5;fill:#666;stroke:none;filter:url(#filter3861)" /> - <path - inkscape:connector-curvature="0" - id="path4009" - d="m 317.53125,282.15178 c -11.36706,0.26523 -23.23057,2.55643 -31.6875,10.8125 -1.86956,1.14115 -4.05821,1.47538 -2.78125,4.53125 -0.84939,3.46529 4.1566,3.28051 5.65625,5.75 9.51653,7.68063 22.72213,8.97735 34.38448,7.94875 4.21291,0.28872 5.90132,-3.25103 6.14677,-6.98 0.9191,-6.73052 1.37996,-14.32892 -1.84375,-20.53125 -3.23537,-1.02214 -6.47262,-1.79974 -9.875,-1.53125 z" - style="opacity:0.5;fill:#333;filter:url(#filter4020)" /> - <path - sodipodi:nodetypes="cccc" - inkscape:connector-curvature="0" - id="path3865" - d="m 297.0319,288.01519 30.27684,-1.83276 -30.27684,3.97562 z" - style="fill:url(#linearGradient4032);fill-opacity:1;stroke:none" /> - <path - style="fill:url(#linearGradient4034);fill-opacity:1;stroke:none" - d="m 297.01023,295.86554 31.16072,1.07143 -31.16072,1.07143 z" - id="path3867" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccc" /> - <path - sodipodi:nodetypes="cccc" - inkscape:connector-curvature="0" - id="path3869" - d="m 295.11991,302.01312 30.78191,4.8595 -30.78191,-2.71664 z" - style="fill:url(#linearGradient4036);fill-opacity:1;stroke:none" /> - </g> - <path - style="fill:url(#linearGradient3063)" - d="m 190.26363,89.34866 c -0.43987,0.06867 -0.94061,0.240548 -1.66911,0.512448 -1.38847,0.518221 -2.40074,1.261233 -3.07469,2.313337 -0.25496,0.398012 -0.45333,0.827434 -0.61494,1.317728 l 10.96639,15.666277 c 0.01,-1.8e-4 0.0194,2.2e-4 0.0293,0 1.22755,0.0133 4.37487,-1.99345 5.00735,-3.19182 0.0946,-0.17924 0.17036,-0.58776 0.23427,-1.08346 L 190.26365,89.34866 z" - id="path4135" - inkscape:connector-curvature="0" /> - <path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;opacity:0.3;color:black;fill:url(#radialGradient4304);fill-opacity:1;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter4330);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 113.35358,88.956128 -0.8125,0.5625 50.89286,76.607142 0.8125,-0.5625 z" - id="path4280" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccc" /> - <path - inkscape:connector-curvature="0" - id="path4286" - d="m 125.85359,76.456128 -0.8125,0.5625 53.03571,80.892852 0.8125,-0.5625 z" - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;opacity:0.3;color:black;fill:url(#radialGradient4294);fill-opacity:1;stroke:none;stroke-width:1px;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter4310);enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - sodipodi:nodetypes="ccccc" /> - <g - transform="matrix(-0.52943173,0.84835255,0.84835255,0.52943173,-17.027404,-209.74208)" - id="g4038"> - <path - sodipodi:nodetypes="sccccscssssssssccccccssscsssccccccsssssssscs" - inkscape:connector-curvature="0" - id="path4040" - d="m 318.53887,279.75654 c 1.00999,0.005 1.89177,0.0482 2.60328,0.13466 2.08898,0.24742 6.49786,1.35249 7.17341,1.79558 3.92176,4.11251 4.59865,22.42631 0.13131,29.5793 -0.67159,0.44906 -5.07047,1.5933 -7.15718,1.85921 -0.7107,0.0927 -1.59206,0.14415 -2.60198,0.15775 -7.06943,0.0952 -20.39523,-1.69296 -24.92275,-4.60816 -2.63356,-1.38461 -5.42336,-3.18744 -7.39874,-4.78344 -2.21303,-1.78801 -3.11021,-2.35716 -4.07294,-2.58092 -0.46818,-0.10877 -0.89474,-0.41554 -1.08308,-0.77489 -0.28302,-0.54008 -0.46902,-0.59343 -2.03336,-0.592 -1.15036,0.001 -1.92427,-0.13413 -2.341,-0.40382 -0.34291,-0.22194 -0.89816,-0.4021 -1.22923,-0.40064 -0.33107,0.002 -0.71467,-0.17225 -0.85642,-0.38603 -0.21729,-0.32774 -1.11898,-0.38489 -5.74038,-0.36438 l -5.48162,0.0243 -0.55547,0.81465 c -0.49243,0.71601 -0.65283,0.79214 -1.33378,0.65567 -0.0135,-0.003 -0.0187,-0.006 -0.0321,-0.008 l -1.42609,0.12817 -0.70028,-1.40198 c -0.70128,-0.072 -2.01523,-0.0578 -4.62695,0.0125 -7.97877,0.21454 -64.83584,0.92806 -76.08428,0.95504 -8.76866,0.0211 -10.16589,-0.0269 -10.43811,-0.36787 -0.27961,-0.35014 -0.36962,-1.21907 -0.28528,-2.01296 -0.0917,-0.79356 -0.009,-1.66255 0.2674,-2.01541 0.26919,-0.34333 1.66593,-0.40374 10.43442,-0.46054 11.24824,-0.0729 68.10941,0.13575 76.08977,0.27946 2.61224,0.047 3.92627,0.0496 4.62688,-0.0286 l 0.68781,-1.40814 1.42719,0.11514 c 0.0136,-0.003 0.0187,-0.006 0.0321,-0.008 0.67971,-0.1425 0.84077,-0.0678 1.33955,0.64381 l 0.56269,0.80969 5.48161,-0.0243 c 4.6214,-0.0205 5.52254,-0.0857 5.73693,-0.41534 0.13984,-0.21502 0.52188,-0.39216 0.85295,-0.39363 0.33109,-0.002 0.88469,-0.18656 1.22562,-0.41153 0.41431,-0.27341 1.18701,-0.41544 2.33732,-0.42459 1.5643,-0.0123 1.7498,-0.0675 2.02804,-0.61002 0.18513,-0.36102 0.60895,-0.67153 1.07614,-0.78449 0.96072,-0.23228 1.8528,-0.8094 4.04987,-2.61698 1.96114,-1.61348 4.73481,-3.44101 7.35598,-4.84894 4.50144,-2.95533 17.81085,-4.86179 24.88084,-4.82932 z" - style="fill:#1a1a1a" /> - <path - style="opacity:0.5;fill:#666;stroke:none;filter:url(#filter3861)" - d="m 169.10714,296.11219 105,-0.17858 -0.35714,1.42858 -104.82143,1.07142 z" - id="path4042" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.5;fill:#333;filter:url(#filter4020)" - d="m 317.53125,282.15178 c -11.36706,0.26523 -23.23057,2.55643 -31.6875,10.8125 -1.86956,1.14115 -4.05821,1.47538 -2.78125,4.53125 -0.84939,3.46529 4.1566,3.28051 5.65625,5.75 9.51653,7.68063 22.72213,8.97735 34.38448,7.94875 4.21291,0.28872 5.90132,-3.25103 6.14677,-6.98 0.9191,-6.73052 1.37996,-14.32892 -1.84375,-20.53125 -3.23537,-1.02214 -6.47262,-1.79974 -9.875,-1.53125 z" - id="path4044" - inkscape:connector-curvature="0" /> - <path - style="fill:url(#linearGradient4052);fill-opacity:1;stroke:none" - d="m 297.0319,288.01519 30.27684,-1.83276 -30.27684,3.97562 z" - id="path4046" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccc" /> - <path - sodipodi:nodetypes="cccc" - inkscape:connector-curvature="0" - id="path4048" - d="m 297.01023,295.86554 31.16072,1.07143 -31.16072,1.07143 z" - style="fill:url(#linearGradient4054);fill-opacity:1;stroke:none" /> - <path - style="fill:url(#linearGradient4056);fill-opacity:1;stroke:none" - d="m 295.11991,302.01312 30.78191,4.8595 -30.78191,-2.71664 z" - id="path4050" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccc" /> - </g> - <path - inkscape:connector-curvature="0" - id="path4150" - d="m 107.61204,135.87111 c -0.43987,0.0687 -0.94061,0.24055 -1.66911,0.51245 -1.38847,0.51822 -2.40074,1.26123 -3.07469,2.31333 -0.25496,0.39802 -0.45333,0.82744 -0.61494,1.31773 l 10.9664,15.66628 c 0.01,-1.8e-4 0.0194,2.2e-4 0.0293,0 1.22755,0.0133 4.37487,-1.99345 5.00735,-3.19182 0.0946,-0.17924 0.17036,-0.58776 0.23427,-1.08347 l -10.87855,-15.5345 z" - style="fill:url(#linearGradient3059)" /> - <path - style="opacity:0.45;fill:white;stroke:none;filter:url(#filter3951)" - d="m 140.06407,195.32811 c 0,0 29.07782,-4.37183 42.39494,-10.1947 14.78259,-6.46364 40.26186,-26.86477 40.26186,-26.86477 0,0 -19.03151,32.17765 -35.15464,38.96292 -14.60604,6.14682 -47.50216,-1.90345 -47.50216,-1.90345 z" - id="path3909" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cacac" - transform="matrix(0.99690053,-0.07867232,0.07867232,0.99690053,-13.51203,13.166988)" /> - <path - sodipodi:nodetypes="cacac" - inkscape:connector-curvature="0" - id="path3955" - d="m 91.374375,85.871906 c 0,0 9.256535,-26.696739 20.754205,-32.346171 13.12094,-6.447035 43.69229,3.807076 43.69229,3.807076 0,0 -34.41022,-23.358229 -49.87846,-15.390694 -13.71495,7.06443 -14.568035,43.929789 -14.568035,43.929789 z" - style="opacity:0.4;fill:#faa;stroke:none;filter:url(#filter3957)" /> - <path - style="fill:url(#linearGradient4253);stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 55.09375 38.125 C 41.536468 55.525521 38.482469 79.730562 43.5 100.8125 C 44.024201 102.26043 44.578426 103.68369 45.125 105.125 C 44.024016 92.475252 43.404295 78.251935 44.9375 68.5625 C 46.28173 60.067328 50.756241 48.257598 55.09375 38.125 z " - transform="translate(28.121442,8.3445206)" - id="path4242" /> - <path - style="fill:url(#linearGradient4271);stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 114.28125 204.625 C 113.32558 204.67041 112.29016 204.8007 111.21875 204.96875 C 119.83569 211.80541 132.24015 211.82002 142.6875 209.6875 C 146.03427 208.64812 149.32096 207.45718 152.59375 206.15625 C 151.9534 205.85401 151.33022 205.57328 150.71875 205.34375 C 143.65393 202.69182 135.75218 208.28171 128.21875 207.84375 C 123.4619 207.56721 119.04076 204.39887 114.28125 204.625 z " - transform="translate(28.121442,8.3445206)" - id="path4266" /> - <path - style="fill:url(#linearGradient4278);stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" - d="M 207.03125 154.34375 L 193.5 183.75 C 195.65989 181.9894 197.68946 180.09837 199.5 177.9375 C 205.95635 171.90863 208.38452 162.88007 207.03125 154.34375 z " - transform="translate(28.121442,8.3445206)" - id="path4273" /> - <path - style="fill:url(#radialGradient4482);opacity:0.4;filter:url(#filter4472);fill-opacity:1" - d="m 106.75,138.21875 c -5.01915,1.36431 1.53172,5.62694 2.37808,8.14121 2.30839,1.7736 3.89374,9.63491 7.18442,5.39004 -3.19444,-4.47938 -6.33093,-9.19988 -9.5625,-13.53125 z" - id="path4404" - inkscape:connector-curvature="0" /> - <path - inkscape:connector-curvature="0" - id="path4484" - d="m 189.32997,91.499195 c -5.01915,1.36431 1.53172,5.62694 2.37808,8.14121 2.30839,1.773605 3.89374,9.634915 7.18442,5.390045 -3.19444,-4.47938 -6.33093,-9.199885 -9.5625,-13.531255 z" - style="opacity:0.4;fill:url(#radialGradient4486);fill-opacity:1;filter:url(#filter4472)" /> - <path - style="fill:white;stroke:none;filter:url(#filter4502);opacity:0.2" - d="m 57.578695,49.881767 c 0,0 -5.45362,18.676558 -5.555839,28.284271 -0.156361,14.696609 3.461299,29.155632 7.576144,43.436562 0,0 -4.701076,-23.455716 -5.050762,-35.355342 -0.357297,-12.158599 3.030457,-36.365491 3.030457,-36.365491 z" - id="path4488" - inkscape:connector-curvature="0" - transform="translate(28.121442,8.3445206)" - sodipodi:nodetypes="cacac" /> - <path - sodipodi:nodetypes="cacac" - transform="matrix(-0.47323097,0.88093839,0.88093839,0.47323097,107.53763,-41.655538)" - inkscape:connector-curvature="0" - id="path4506" - d="m 57.578695,49.881767 c 0,0 -5.45362,18.676558 -5.555839,28.284271 -0.156361,14.696609 3.461299,29.155632 7.576144,43.436562 0,0 -4.701076,-23.455716 -5.050762,-35.355342 -0.357297,-12.158599 3.030457,-36.365491 3.030457,-36.365491 z" - style="opacity:0.2;fill:white;stroke:none;filter:url(#filter4502)" /> - <path - style="opacity:0.2;color:black;fill:black;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - d="m 127.43394,76.032021 c -3.29565,-0.09301 -6.18321,1.771115 -8.4375,4 -4.60463,3.783417 -6.83452,9.814408 -6.03125,15.6875 2.14745,-4.274005 5.28349,-8.111538 9.34375,-11.125 5.34892,-3.969885 11.5628,-5.967746 17.84375,-6.15625 -4.06323,-1.493367 -8.43787,-2.257524 -12.71875,-2.40625 z" - id="path4526" /> - <path - style="opacity:0.20000000000000001;color:black;fill:url(#linearGradient4541);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.50000000000000000;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - d="m 187.18394,142.00077 c -0.63298,9.16177 -4.9691,17.87333 -12.71875,23.625 -4.81784,3.57573 -10.32971,5.53466 -15.96875,6.03125 3.96322,2.82465 8.96853,0.9914 13.28125,-0.84375 7.3388,-2.14191 13.32849,-7.37985 17.84375,-13.375 2.06539,-4.53816 -0.33568,-9.60982 -1.6875,-14.03125 -0.24533,-0.47093 -0.50396,-0.9354 -0.75,-1.40625 z" - id="path4533" /> - </g> -</svg> diff --git a/test/splash.bmp b/test/splash.bmp Binary files differdeleted file mode 100644 index 27247f7..0000000 --- a/test/splash.bmp +++ /dev/null diff --git a/test/test-create-disk.sh b/test/test-create-disk.sh deleted file mode 100755 index a5cd4cc..0000000 --- a/test/test-create-disk.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -e - -# create GPT table with EFI System Partition -rm -f test-disk.img -dd if=/dev/null of=test-disk.img bs=1M seek=512 count=1 -parted --script test-disk.img "mklabel gpt" "mkpart ESP fat32 1MiB 511MiB" "set 1 boot on" - -# create FAT32 file system -LOOP=$(losetup --show -f -P test-disk.img) -mkfs.vfat -F32 ${LOOP}p1 -mkdir -p mnt -mount ${LOOP}p1 mnt - -# install gummiboot -mkdir -p mnt/EFI/{Boot,gummiboot} -cp gummibootx64.efi mnt/EFI/Boot/bootx64.efi -cp test/splash.bmp mnt/EFI/gummiboot/ - -[ -e /boot/shellx64.efi ] && cp /boot/shellx64.efi mnt/ - -mkdir mnt/EFI/Linux -echo -n "foo=yes bar=no root=/dev/fakeroot debug rd.break=initqueue" > mnt/cmdline.txt -objcopy \ - --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000 \ - --add-section .cmdline=mnt/cmdline.txt --change-section-vma .cmdline=0x30000 \ - --add-section .linux=/boot/$(cat /etc/machine-id)/$(uname -r)/linux --change-section-vma .linux=0x40000 \ - --add-section .initrd=/boot/$(cat /etc/machine-id)/$(uname -r)/initrd --change-section-vma .initrd=0x3000000 \ - linuxx64.efi.stub mnt/EFI/Linux/linux-test.efi - -# install entries -mkdir -p mnt/loader/entries -echo -e "timeout 3\nsplash /EFI/gummiboot/splash.bmp\n" > mnt/loader/loader.conf -echo -e "title Test\nefi /test\n" > mnt/loader/entries/test.conf -echo -e "title Test2\nlinux /test2\noptions option=yes word number=1000 more\n" > mnt/loader/entries/test2.conf -echo -e "title Test3\nlinux /test3\n" > mnt/loader/entries/test3.conf -echo -e "title Test4\nlinux /test4\n" > mnt/loader/entries/test4.conf -echo -e "title Test5\nefi /test5\n" > mnt/loader/entries/test5.conf -echo -e "title Test6\nlinux /test6\n" > mnt/loader/entries/test6.conf - -sync -umount mnt -rmdir mnt -losetup -d $LOOP |